如何在GraphQL Mutation中跟踪图片上传进度
在GraphQL Mutation上传图片时获取上传进度
GraphQL本身没有原生提供上传进度追踪能力,但可以通过前端自定义逻辑、客户端扩展或后端配合的方式实现,以下是几种可行方案:
方案1:基于Fetch API的流监听(通用方案)
如果你的GraphQL客户端底层基于Fetch API,可以通过包装文件流来追踪上传进度:
- 编写进度追踪的文件包装函数:
function createProgressTrackingFile(file, onProgress) { const fileStream = file.stream(); const totalBytes = file.size; let uploadedBytes = 0; const trackedStream = new ReadableStream({ async start(controller) { const reader = fileStream.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; uploadedBytes += value.length; const progress = (uploadedBytes / totalBytes) * 100; onProgress(progress, uploadedBytes, totalBytes); controller.enqueue(value); } controller.close(); } }); return new File([trackedStream], file.name, { type: file.type }); }
- 调用Mutation时使用包装后的文件:
const handleUpload = (file) => { const trackedFile = createProgressTrackingFile(file, (progress, uploaded, total) => { // 这里可以更新UI显示进度 console.log(`上传进度:${progress.toFixed(2)}%,已上传${uploaded}字节/共${total}字节`); }); AddCaptainScanLicense({ // 替换原变量中的file为trackedFile file: trackedFile, // 其他Mutation变量... }); };
方案2:Apollo Client扩展(若使用Apollo)
如果你的useAddCaptainLicenseScanMutation基于Apollo Client,可通过apollo-upload-client自定义上传链接来监听进度:
- 自定义带进度追踪的上传链接:
import { createUploadLink } from 'apollo-upload-client'; const uploadLink = createUploadLink({ uri: graphqlEndpoint, fetch: async (uri, options) => { if (options?.body instanceof FormData) { const formData = options.body; const fileEntries = Array.from(formData.entries()).filter(([_, val]) => val instanceof File); if (fileEntries.length === 0) return fetch(uri, options); const totalSize = fileEntries.reduce((sum, [_, file]) => sum + file.size, 0); let uploadedSize = 0; // 替换FormData中的文件为带进度监听的流 fileEntries.forEach(([key, file]) => { const trackedStream = file.stream().pipeThrough(new TransformStream({ transform(chunk, controller) { uploadedSize += chunk.length; const progress = (uploadedSize / totalSize) * 100; console.log(`上传进度:${progress.toFixed(2)}%`); controller.enqueue(chunk); } })); formData.set(key, new File([trackedStream], file.name, { type: file.type })); }); } return fetch(uri, options); } });
- 将该链接配置到Apollo Client实例中,后续所有文件上传都会触发进度监听。
方案3:后端配合的Subscription实时进度(适合大文件)
如果后端支持分块接收文件,可以通过GraphQL Subscription实时获取上传进度:
- 前端同时发起Mutation和Subscription:
// 生成唯一上传ID const uploadId = crypto.randomUUID(); // 发起上传Mutation AddCaptainScanLicense({ file: yourFile, uploadId: uploadId, // 其他变量... }); // 订阅进度更新 const { data: progressData } = useSubscription( gql` subscription UploadProgress($uploadId: ID!) { uploadProgress(uploadId: $uploadId) { uploadedBytes totalBytes progress } } `, { variables: { uploadId } } ); // 处理进度数据 if (progressData) { const { uploadedBytes, totalBytes, progress } = progressData.uploadProgress; console.log(`已上传${uploadedBytes}字节,总大小${totalBytes}字节,进度${progress}%`); }
- 后端需要在接收文件的过程中,定期向Subscription推送进度数据,具体实现取决于后端技术栈。
内容的提问来源于stack exchange,提问作者Aditya Singh
相关产品推荐
相关产品推荐

