React前端基于graphql-request发送FormData(图片)的实现咨询
当然可以!不过有个小细节需要注意:graphql-request默认是用JSON格式发送请求的,而上传文件(比如图片)需要采用multipart/form-data格式,所以得调整请求的发送方式来适配。我给你整理了前端的实现示例,再补充一点后端的关键配置建议,帮你打通整个流程。
前端实现示例
下面是React组件中使用graphql-request上传图片的完整代码,核心是手动构造FormData并调整请求配置:
import { request } from 'graphql-request'; const ImageUploadForm = () => { const handleFileUpload = async (e) => { e.preventDefault(); const selectedFile = e.target.fileInput.files[0]; if (!selectedFile) return; // 1. 定义接收文件的GraphQL mutation const uploadMutation = ` mutation UploadImage($file: Upload!) { uploadImage(file: $file) { id url filename } } `; // 2. 构造符合GraphQL multipart规范的FormData const formData = new FormData(); // 添加GraphQL查询语句 formData.append('query', uploadMutation); // 添加变量(这里的file值设为null,对应FormData中的文件项) formData.append('variables', JSON.stringify({ file: null })); // 添加实际的图片文件,键名"0"对应变量中file的索引(多文件时递增) formData.append('0', selectedFile); try { // 3. 发送请求,无需手动设置Content-Type(浏览器会自动添加带boundary的正确头) const uploadResult = await request('/graphql', formData); console.log('图片上传成功:', uploadResult); // 这里可以做后续的UI更新,比如显示上传后的图片 } catch (error) { console.error('图片上传失败:', error.message); } }; return ( <form onSubmit={handleFileUpload}> <input type="file" name="fileInput" accept="image/*" /> <button type="submit" disabled={!e?.target.fileInput?.files?.length}> 上传图片 </button> </form> ); }; export default ImageUploadForm;
后端补充配置建议
因为你用的是express-graphql,它本身不支持文件上传解析,需要搭配graphql-upload中间件来处理multipart/form-data请求,这里给你关键的后端配置代码片段:
const express = require('express'); const { graphqlHTTP } = require('express-graphql'); const { GraphQLUpload, graphqlUploadExpress } = require('graphql-upload'); const { buildSchema } = require('graphql'); const fs = require('fs'); const path = require('path'); const app = express(); // 先添加文件上传解析中间件,限制文件大小和数量 app.use(graphqlUploadExpress({ maxFileSize: 10 * 1024 * 1024, maxFiles: 1 })); // 定义包含Upload标量的Schema const schema = buildSchema(` scalar Upload type Image { id: ID! url: String! filename: String! } type Mutation { uploadImage(file: Upload!): Image! } `); // 根解析器处理文件上传逻辑 const rootResolver = { uploadImage: async ({ file }) => { const { createReadStream, filename } = await file; const uploadDir = path.join(__dirname, 'uploads'); // 确保uploads目录存在 if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir); const filePath = path.join(uploadDir, filename); // 流式写入文件到本地 await new Promise((resolve, reject) => { createReadStream() .pipe(fs.createWriteStream(filePath)) .on('finish', resolve) .on('error', reject); }); // 返回图片的访问信息 return { id: Date.now().toString(), url: `/uploads/${filename}`, filename }; } }; // 配置GraphQL端点 app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: rootResolver, graphiql: true, })); // 静态文件服务,让前端可以访问上传的图片 app.use('/uploads', express.static(path.join(__dirname, 'uploads'))); app.listen(4000, () => { console.log('服务器运行在 http://localhost:4000/graphql'); });
关键注意事项
- 前端不要手动设置
Content-Type: multipart/form-data,浏览器会自动添加包含boundary的正确请求头,手动设置会导致请求解析失败。 - 后端必须安装
graphql-upload依赖(npm install graphql-upload),否则无法解析文件上传请求。 - 如果存在跨域问题,记得在express中添加
cors中间件来允许前端域名的请求。
内容的提问来源于stack exchange,提问作者Jack Hudzenko
相关产品推荐
相关产品推荐

