在中文环境中使用Apollo Client从Node环境上传文件的方法,虽然不是绝对必需,但可以这样操作
请留心
我正在使用node-fetch作为fetch的polyfill(同时也使用了next.js的api routes)。
注意:当 body 是一个流时,Content-Length 不会自动设置。
因此,当传递fs.createReadStream文件时,作为结果,content-length不会作为头信息传递到服务器端。这可能是一些服务器报错的原因。
如果无法成功处理POST数据,且服务器数据无法传递,建议检查puma的版本是否低于v4.3.7。
为块传输请求设置setContentLength返回
只需要一个选择。
-
- apollo clientを使っている
-
- apollo-upload-clientを使っている
- node環境から使っている(nextjsのapi routesとか)
在这种情况下,即使编写与客户端类似的代码也无法上传。
解决方法 (jiě jué àn)
在Node环境中
-
- Fileがない
-
- Blobがない
-
- FormDataがない
- fetchがない(nextjsならpolyfillしてるけど)
所以,在使用apollo-upload-client的createUploadLink时,需要指定这些node版。
因此,由于没有File和Blob对象,需要使用fs将文件作为流进行读取,并将其作为要上传的对象。但是,默认情况下,只有File或Blob才能作为目标对象,所以需要通过isExtractableFile重新设置为可提取的ReadStream对象。
import FormData from "form-data" // yarn add form-data
import fetch from "isomorphic-unfetch" // yarn add isomorphic-unfetch
import { ReadStream } from "fs"
import { createUploadLink, isExtractableFile } from "apollo-upload-client"
createUploadLink({
uri: "https://backend/graphql",
fetch,
FormData,
isExtractableFile: (value) =>
isExtractableFile(value) ||
(typeof ReadStream !== "undefined" && value instanceof ReadStream),
})
import { ApolloClient, InMemoryCache } from "@apollo/client"
import { createUploadLink, isExtractableFile } from "apollo-upload-client"
import FormData from "form-data"
import fs, { ReadStream } from "fs"
import type { NextApiRequest, NextApiResponse } from "next"
import * as Generated from "src/generated/graphql" // @graphql-codegenを使っているので...
const client = new ApolloClient({
cache: new InMemoryCache(),
link: createUploadLink({
uri: "https://backend/graphql", // 他のgraphqlサーバー
// fetch, nextjsを使っているので必要ない
FormData,
isExtractableFile: (value) =>
isExtractableFile(value) ||
(typeof ReadStream !== "undefined" && value instanceof ReadStream),
}),
})
export default async (req: NextApiRequest, res: NextApiResponse) => {
const file = fs.createReadStream(fs.realpathSync("./test.jpg"))
await client.mutate<
Generated.TestMutationMutation,
Generated.TestMutationMutationVariables
>({
mutation: Generated.TestMutationDocument,
variables: {
input: {
file,
},
},
fetchPolicy: "no-cache",
})
res.status(200).end()
}
{
"scripts": {
"dev": "next",
"generate": "graphql-codegen -w --config codegen.yml"
},
"dependencies": {
"@apollo/client": "^3.4.16",
"apollo-upload-client": "^16.0.0",
"form-data": "^4.0.0",
"graphql": "^15.6.1",
"next": "^11.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@graphql-codegen/cli": "^2.2.1",
"@graphql-codegen/typescript": "^2.2.4",
"@graphql-codegen/typescript-operations": "^2.1.8",
"@graphql-codegen/typescript-react-apollo": "^3.1.6",
"@types/react": "^17.0.30",
"typescript": "^4.4.4"
}
}