使用apollo-upload-client上传S3后图片URL无法正常显示问题
问题修复方案
你遇到的问题是S3中存储的文件内容/元数据异常,导致浏览器无法识别为图片,按以下优先级排查修复即可:
1. 补全S3上传参数
你当前的上传代码遗漏了ContentEncoding配置,从你提供的File对象可以看到文件编码为7bit,未配置的情况下S3会使用默认编码解析文件,导致浏览器识别错误。同时建议给S3的Key增加文件后缀,避免部分CDN/浏览器识别异常:
export async function uploadImageResolver( _parent, { file }: MutationUploadImageArgs, context: Context, ): Promise<string> { // identify(context); // 新增解构encoding const { createReadStream, filename, mimetype, encoding } = await file; // 提取文件后缀 const fileSuffix = filename.split('.').pop(); const response = await s3 .upload({ ACL: 'public-read', Bucket: environment.bucketName, Body: createReadStream(), Key: `${uuid()}.${fileSuffix}`, // 新增后缀 ContentType: mimetype, ContentEncoding: encoding, // 新增编码配置 }) .promise(); return response.Location; }
修改后先测试,若仍异常继续往下处理。
2. 流转Buffer后再上传
部分版本的apollo-upload-client/graphql-upload返回的ReadStream直接传给S3 SDK时会出现内容截断/格式异常,将流转为Buffer后再上传即可解决:
export async function uploadImageResolver( _parent, { file }: MutationUploadImageArgs, context: Context, ): Promise<string> { const { createReadStream, filename, mimetype, encoding } = await file; const fileSuffix = filename.split('.').pop(); // 流转Buffer const chunks = []; for await (const chunk of createReadStream()) { chunks.push(chunk); } const fileBuffer = Buffer.concat(chunks); const response = await s3 .upload({ ACL: 'public-read', Bucket: environment.bucketName, Body: fileBuffer, // 替换为Buffer Key: `${uuid()}.${fileSuffix}`, ContentType: mimetype, ContentEncoding: encoding, }) .promise(); return response.Location; }
3. 检查Apollo Server上传配置
如果你使用的是Apollo Server 3及以上版本,框架默认禁用了内置上传功能,未手动配置上传中间件的情况下解析出的文件流本身就是错误的,需要按以下步骤配置:
- 安装依赖
npm install graphql-upload
- 修改服务启动配置
import { ApolloServer } from 'apollo-server-express'; import { graphqlUploadExpress } from 'graphql-upload'; const server = new ApolloServer({ typeDefs, resolvers, uploads: false, // 禁用默认上传逻辑 }); // 启动服务后注册上传中间件 await server.start(); app.use(graphqlUploadExpress({ maxFileSize: 10 * 1024 * 1024, // 按需设置最大文件大小,示例为10MB maxFiles: 10 })); server.applyMiddleware({ app });
完成以上配置后即可正常上传可访问的图片。你也可以直接在S3控制台对比代码上传的文件和手动上传的文件元数据差异,快速定位问题。
内容的提问来源于stack exchange,提问作者Michal Ružička Ružička
相关产品推荐
相关产品推荐

