在中文环境中使用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"
  }
}
广告
将在 10 秒后关闭
bannerAds