如何阻止Lambda向客户端返回流式输出?解决PDF上传S3显示问题
问题:流式传输PDF到S3时避免客户端显示PDF内容
我正在将远程PDF流式传输至S3存储桶,但PDF的二进制内容会在客户端显示。请问如何修改以下代码,避免客户端显示该PDF?我已尝试调整pipeline等流式命令,但未达到预期效果。
原代码:
const stream = require('stream'); const pipeline = require('util').promisify(stream.pipeline); const { S3Client } = require("@aws-sdk/client-s3"); const { Upload } = require("@aws-sdk/lib-storage"); exports.handler = awslambda.streamifyResponse(async (event, responseStream) => { const requestStream = new stream.PassThrough(); const url = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' require('https').get(url, (response) => { try { response.pipe(requestStream); const parallelUploads3 = new Upload({ client: new S3Client(), params: { Bucket: 'my-bucket', Key: 'wow.pdf', Body: requestStream } }); parallelUploads3.done(); } catch (e) { console.log(e); } }); responseStream = awslambda.HttpResponseStream.from(responseStream); await pipeline(requestStream, responseStream); });
解决方案
问题根源在于你把同一个requestStream同时传给了S3上传和客户端响应流,导致PDF二进制数据被直接输出到客户端。需要断开这个流向客户端的管道,改为在上传完成后返回普通的响应信息。
修改后的代码:
const stream = require('stream'); const { S3Client } = require("@aws-sdk/client-s3"); const { Upload } = require("@aws-sdk/lib-storage"); const https = require('https'); exports.handler = awslambda.streamifyResponse(async (event, responseStream) => { const response = awslambda.HttpResponseStream.from(responseStream); try { const requestStream = new stream.PassThrough(); const url = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf'; // 封装HTTP请求为Promise,确保捕获请求错误 await new Promise((resolve, reject) => { https.get(url, (res) => { res.pipe(requestStream); res.on('end', resolve); res.on('error', reject); }).on('error', reject); }); // 执行S3并行上传,等待上传完成 const parallelUploads3 = new Upload({ client: new S3Client(), params: { Bucket: 'my-bucket', Key: 'wow.pdf', Body: requestStream } }); await parallelUploads3.done(); // 返回成功响应给客户端 response.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': Buffer.from('PDF上传完成').length }); response.end('PDF上传完成'); } catch (e) { console.error('上传失败:', e); // 返回错误响应 response.writeHead(500, { 'Content-Type': 'text/plain', 'Content-Length': Buffer.from('PDF上传失败').length }); response.end('PDF上传失败'); } });
关键修改点:
- 移除了
await pipeline(requestStream, responseStream),不再将PDF流输出到客户端 - 用Promise封装
https.get,确保能正确捕获请求过程中的错误 - 等待
parallelUploads3.done()完成,保证上传操作执行完毕 - 上传成功/失败时,返回对应的HTTP状态码和文本提示,而非PDF二进制内容
- 统一了错误处理逻辑,确保异常情况也能返回合理响应
内容的提问来源于stack exchange,提问作者Ryan W
相关产品推荐
相关产品推荐

