GraphQL 是一种用于 API 的查询语言和运行时环境,它旨在提供更高效、强大和灵活的 API 设计方式。在前端开发中,我们通常需要实现文件上传和下载功能。本文将介绍如何在 GraphQL 中实现文件上传和下载,并提供示例代码。
文件上传
在 GraphQL 中实现文件上传,需要使用 GraphQLUpload 类型。这个类型是由 graphql-upload 库提供的,它允许我们将文件作为 GraphQL 查询的一部分上传到服务器。在服务器端,我们可以使用 createReadStream 方法读取上传的文件。
以下是一个文件上传的示例代码:
// www.javascriptcn.com code example
const { ApolloServer, gql } = require('apollo-server');
const { GraphQLUpload } = require('graphql-upload');
const typeDefs = gql`
scalar Upload
type Mutation {
uploadFile(file: Upload!): String!
}
`;
const resolvers = {
Mutation: {
uploadFile: async (_, { file }) => {
const { createReadStream, filename } = await file;
const stream = createReadStream();
// 将文件保存到服务器
return `File ${filename} uploaded successfully!`;
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
uploads: false, // 禁用文件上传大小限制
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});在上面的示例代码中,我们定义了一个 Upload 标量类型,用于接收上传的文件。在 Mutation 类型中定义了一个 uploadFile 方法,用于接收上传的文件,并将文件保存到服务器。
在客户端中,我们可以使用 graphql-upload 库将文件作为变量传递给 GraphQL 查询。以下是一个上传文件的示例代码:
// www.javascriptcn.com code example
import { gql } from '@apollo/client';
import { createUploadLink } from 'apollo-upload-client';
const UPLOAD_FILE = gql`
mutation UploadFile($file: Upload!) {
uploadFile(file: $file)
}
`;
const uploadLink = createUploadLink({
uri: '/graphql',
});
const client = new ApolloClient({
link: uploadLink,
cache: new InMemoryCache(),
});
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
const result = await client.mutate({
mutation: UPLOAD_FILE,
variables: {
file,
},
});
console.log(result.data.uploadFile);
});在上面的示例代码中,我们使用 createUploadLink 方法创建一个包含上传功能的 Apollo Link,并将其传递给 Apollo Client。然后,我们使用 UPLOAD_FILE 查询定义了一个上传文件的 GraphQL 查询,并使用 client.mutate 方法将文件作为变量传递给服务器。
文件下载
在 GraphQL 中实现文件下载,需要将文件的二进制数据作为查询结果返回给客户端。在服务器端,我们可以使用 createReadStream 方法读取文件,并将其转换为 Buffer 类型的数据。然后,我们可以将这个数据作为查询结果返回给客户端。
以下是一个文件下载的示例代码:
// www.javascriptcn.com code example
const { ApolloServer, gql } = require('apollo-server');
const fs = require('fs');
const typeDefs = gql`
type Query {
downloadFile: File!
}
type File {
filename: String!
mimetype: String!
data: String!
}
`;
const resolvers = {
Query: {
downloadFile: async () => {
const filename = 'example.txt';
const mimetype = 'text/plain';
const stream = fs.createReadStream(filename);
const chunks = [];
for await (const chunk of stream) {
chunks.push(chunk);
}
const data = Buffer.concat(chunks).toString('base64');
return { filename, mimetype, data };
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});在上面的示例代码中,我们定义了一个 Query 类型,用于下载文件。在 downloadFile 方法中,我们使用 fs.createReadStream 方法读取文件,并将其转换为 Buffer 类型的数据。然后,我们将文件名、MIME 类型和数据作为查询结果返回给客户端。
在客户端中,我们可以使用 window.open 方法打开一个新的窗口,并将数据作为 URL 参数传递给这个窗口。由于 URL 长度有限制,我们需要将数据进行分片,并将分片后的数据作为多个 URL 参数传递给新窗口。
以下是一个下载文件的示例代码:
// www.javascriptcn.com code example
import { gql } from '@apollo/client';
const DOWNLOAD_FILE = gql`
query DownloadFile {
downloadFile {
filename
mimetype
data
}
}
`;
const downloadFile = async () => {
const result = await client.query({
query: DOWNLOAD_FILE,
});
const { filename, mimetype, data } = result.data.downloadFile;
const chunkSize = 1024 * 1024; // 每个 URL 参数的大小限制
const chunks = [];
for (let i = 0; i < data.length; i += chunkSize) {
chunks.push(data.slice(i, i + chunkSize));
}
const url = `data:${mimetype};base64,${chunks[0]}`;
for (let i = 1; i < chunks.length; i++) {
window.open(`${url},${chunks[i]}`, '_blank');
}
};
const downloadButton = document.querySelector('button');
downloadButton.addEventListener('click', downloadFile);在上面的示例代码中,我们使用 DOWNLOAD_FILE 查询定义了一个下载文件的 GraphQL 查询,并使用 client.query 方法获取查询结果。然后,我们将查询结果中的文件名、MIME 类型和数据分别保存到变量中。接着,我们将数据分片,并将分片后的数据作为多个 URL 参数传递给新窗口,以实现文件下载功能。
结语
本文介绍了如何在 GraphQL 中实现文件上传和下载功能,并提供了示例代码。文件上传和下载是前端开发中常用的功能,掌握这些技能可以让我们更好地完成工作。如果你想深入了解 GraphQL,可以参考官方文档和相关书籍。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d29fd2a941bf7134509102