GraphQL 是一种查询语言,用于 API 的设计。它提供了一种更高效、更灵活的方式来描述 API 的数据。GraphQL 使得前端开发人员可以自由地指定他们需要的数据,并减少不必要的流量和查询开销。在前端,我们经常需要上传文件,如图片、音频等。GraphQL 支持上传单个文件,但在需要上传多个文件时就需要进行扩展。
前置要求
- 了解 GraphQL 和 Apollo。
实现原理
GraphQL 不支持多文件上传,因此我们需要使用一个实用程序库来帮助我们进行处理。这里选择使用 apollo-upload-client
库,它是 Apollo Client 的扩展程序,用于支持文件上传。
安装
首先,我们需要安装 apollo-upload-client
库。使用 npm 进行安装:
npm install apollo-upload-client
或者使用 yarn 进行安装:
yarn add apollo-upload-client
服务器端
在服务器端需要对 GraphQL server 进行配置以支持文件上传。下面以 Express 和 Apollo Server 为例进行配置。
安装依赖
安装以下依赖:
npm install graphql-upload
或者
yarn add graphql-upload
配置
在服务器端的 GraphQL 配置文件中添加以下代码:
// javascriptcn.com 代码示例 const { ApolloServer, gql } = require('apollo-server-express'); const { createWriteStream } = require('fs'); const { GraphQLUpload } = require('graphql-upload'); const typeDefs = gql` scalar Upload type File { filename: String! mimetype: String! encoding: String! } type Query { _: Boolean } type Mutation { singleUpload(file: Upload!): File! multipleUpload(files: [Upload!]!): [File!]! } `; const resolvers = { Upload: GraphQLUpload, Mutation: { singleUpload: async (_, { file }) => { const { createReadStream, filename, mimetype, encoding } = await file; const stream = createReadStream(); // Provide a safe filename here const path = `${__dirname}/uploads/${filename}`; await stream.pipe(createWriteStream(path)); return { filename, mimetype, encoding }; }, multipleUpload: async (_, { files }) => { // const { createReadStream, filename, mimetype, encoding } = await file; const results = await Promise.all( files.map(async (file) => { const { createReadStream, filename, mimetype, encoding } = await file; const stream = createReadStream(); // Provide a safe filename here const path = `${__dirname}/uploads/${filename}`; await stream.pipe(createWriteStream(path)); return { filename, mimetype, encoding }; }) ); return results; }, }, }; const server = new ApolloServer({ typeDefs, resolvers, uploads: false, }); const app = express(); server.applyMiddleware({ app, }); app.listen({ port: 4000 }, () => console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`) );
在上面的代码中,我们定义了两个 Mutation
:singleUpload
和 multipleUpload
。当执行 upload 操作时,通过 graphql-upload
提供的 GraphQLUpload
类型将文件添加到 GraphQL schema 中。由于文件上传可能会对应用程序的安全性产生威胁,因此我们需要在服务器端对其进行验证(例如,文件类型、大小等)。
客户端
安装
我们需要使用 apollo-upload-client
客户端库来向服务器上传文件。使用 npm 安装:
npm install apollo-upload-client
或者使用 yarn 进行安装:
yarn add apollo-upload-client
配置
在客户端的 ApolloClient
中启用上传插件,并将 UploadLink
用作连接类。
// javascriptcn.com 代码示例 import { ApolloClient, InMemoryCache } from '@apollo/client'; import { createUploadLink } from 'apollo-upload-client'; const link = createUploadLink({ uri: 'http://localhost:4000/graphql' }); const client = new ApolloClient({ link, cache: new InMemoryCache(), });
上传文件
在 GraphQL mutation 中添加 file(name: "filename")
参数来上传一个文件。如果需要上传多个文件,则使用 [file]
:
// javascriptcn.com 代码示例 import { useMutation } from '@apollo/client'; import { gql } from '@apollo/client/core'; export const UPLOAD_FILES = gql` mutation UploadFiles($files: [Upload!]!) { multipleUpload(files: $files) { filename mimetype encoding } } `; const UploadFiles = () => { const [uploadMutate] = useMutation(UPLOAD_FILES); const inputEl = useRef(null); const handleSubmit = async (e) => { e.preventDefault(); const { files } = inputEl.current; const filesArray = Array.from(files); const promises = filesArray.map((file) => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (event) => { resolve({ variables: { files: [file], }, }); }; reader.readAsDataURL(file); }); }); try { const results = await Promise.all(promises); results.forEach((variables) => { uploadMutate(variables); }); alert('文件上传成功'); } catch (err) { console.error(err); alert('文件上传失败'); } }; return ( <div className="upload"> <form onSubmit={handleSubmit}> <input type="file" multiple ref={inputEl} /> <button type="submit">上传文件</button> </form> </div> ); };
在上面的代码中,我们使用 useMutation
hook 来定义一个 UPLOAD_FILES
mutation。添加一个表单来上传文件。我们使用 FileReader
将文件读入内存,然后将其变换成 GraphQL mutation 的变量,最后将变量发送到服务器。
总结
在本篇文章中,我们介绍了如何使用 apollo-upload-client
实现 GraphQL 的多文件上传。我们提供了服务器端和客户端的完整代码示例。GraphQL 的上传操作背后的途中并不复杂,但它确实比较难以实现。使用 apollo-upload-client
,我们只需要一些简单的配置和相应的库,就可以轻松地实现多文件上传。如果你想一次上传多个文件,只需要将 file
参数改成 [file]
。使用本文中的代码示例可以方便地在你的项目中轻松实现文件上传功能。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6539f6d47d4982a6eb3a5150