使用apollo和graphql上传时,大于16kb的文件会被损坏



我想我什么都试过了,但似乎什么都不起作用。我有一个React应用程序,我想把图片上传到一个文件夹。我正在使用Apollo服务器和Graphql。

奇怪的是,如果文件小于17kb,它就可以工作!。但是,任何比这更大的东西,文件都会被破坏。我可以在文件夹中看到图像文件,但它是0kb,当我试图打开它时,它会说图像包含错误;。我对物品的大小没有限制。

解析器:我试着用不同的方法来做这件事,但我遇到了同样的问题,所以我不认为这是问题所在。

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { UserInputError } = require('apollo-server');
const path = require('path');
const fs = require('fs');
async uploadFile(_, { file }) {
const { createReadStream, filename, mimetype, encoding } = await file;

const stream = createReadStream();
const pathName = path.join(__dirname, "../../public/images/", filename);
await stream.pipe(fs.createWriteStream(pathName));
return {
url: `http://localhost:5000/images/${filename}`,
}
}  

类型定义:

type File {
url: String!
filename: String!
mimetype: String!
encoding: String!
}
type Mutation {
uploadFile(file: Upload!): File!
}

阿波罗供应商:

import React from 'react';
import App from './App';
import ApolloClient from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
/* import { createHttpLink } from 'apollo-link-http'; */
import { ApolloProvider } from '@apollo/react-hooks';
import { setContext } from 'apollo-link-context';
import { createUploadLink } from 'apollo-upload-client';

const uploadLink = createUploadLink({
uri: 'http://localhost:5000/graphql'
});
const authLink = setContext(() => {
const token = localStorage.getItem('jwtToken');
return {
headers: {
Authorization: token ? `Bearer ${token}` : ''
}
};
});
const client = new ApolloClient({
link: authLink.concat(uploadLink),
cache: new InMemoryCache(),
onError: ({ networkError, graphQLErrors }) => {
console.log( 'graphQLErrors', graphQLErrors)
console.log( 'networkError', networkError)
}
});
export default (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);

服务器上的Index.js:

const { ApolloServer, PubSub } = require('apollo-server-express');
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');
const typeDefs = require('./graphql/typeDefs');
const resolvers = require('./graphql/resolvers');
const { MONGODB } = require('./config.js');
const pubsub = new PubSub();
const PORT = process.env.PORT || 5000;
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ req, pubsub })
});
const app = express();
server.applyMiddleware({ app });
app.use(express.static('public'));
app.use(cors());
mongoose
.connect(MONGODB, { useNewUrlParser: true })
.then(() => {
console.log('MongoDB Connected');
return app.listen({ port: PORT }, () => {
console.log(`Server running at http://localhost:5000/ Graphql Playground at http://localhost:5000/graphql `);
});
})
.catch(err => {
console.error(err)
})

我试着用不同的方式填写输入表格,但我遇到了同样的问题,所以我认为问题不在这里,但我不知道。

import React, { useCallback } from 'react';
import { useDropzone } from 'react-dropzone';
import { useMutation, gql } from '@apollo/client';
function UploadForm() {
const [uploadFile] = useMutation(UPLOAD_FILE_MUTATION, {
onCompleted: data => console.log(data),
});
const onDrop = useCallback(
([file]) => {
uploadFile({ variables: { file } });
},
[uploadFile]
);
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
return (
<div {...getRootProps()}>
<input {...getInputProps()}/>
{isDragActive ? (
<p>Drop the files here!</p>
) : (
<p>Drag and drop files here, or click to select files</p>
)}
</div>
)
}
const UPLOAD_FILE_MUTATION = gql`
mutation uploadFile($file: Upload!){
uploadFile(file: $file){
url
}
}
`
export default UploadForm;

我怀疑问题出在index.js或Apollo提供商中,但我真的不知道。谢谢

"async/await只适用于promise,而不适用于streams"-xadm

解决方案:

将解析器更改为:

const path = require('path');
const fs = require('fs');
const Image = require('../../models/Image');
const files = [];

module.exports = {
Mutation: {
async uploadProfilePic(_, { file }, context) {
const { createReadStream, filename, mimetype, encoding } = await file;
const { ext } = path.parse(filename);
const randomName = generateRandomString(12) + ext;
files.push(randomName);
console.log(file);
const storeUpload = async ({ stream, filename, mimetype, encoding }) => {

const path = `public/images/${randomName}`

return new Promise((resolve, reject) =>
stream
.pipe(fs.createWriteStream(path))
.on("finish", () => resolve({ 
category: "profilePic",
url: `http://localhost:5000/images/${randomName}`, 
path, 
filename: randomName, 
mimetype,
encoding,
createdAt: new Date().toISOString(),
commentsCount: 0,
likesCount: 0,
sharesCount: 0
}))
.on("error", reject)
);
};
const processUpload = async (upload) => {
const { createReadStream, filename, mimetype, encoding } = await upload;
const stream = createReadStream();
const file = await storeUpload({ stream, filename, mimetype, encoding });
return file;
};
const upload = await processUpload(file);

return {
url: `http://localhost:5000/images/${randomName}`,
};

}
}
};