基于预签名URL通过同一API网关实现文件上传与下载
解决方案:S3预签名URL关联API网关并触发浏览器下载
针对你的业务场景(用户上传CSV到S3→Lambda转换为PDF→推送至浏览器下载),以下是两个核心问题的具体实现方案:
1. 将Lambda输出的预签名URL关联至API网关
步骤1:扩展Lambda函数逻辑
修改现有Lambda代码,新增PDF下载的预签名URL生成逻辑,并通过HTTP方法区分上传/下载请求:
const AWS = require('aws-sdk') AWS.config.update({ region: process.env.AWS_REGION }) const s3 = new AWS.S3() const UPLOAD_EXPIRE = 300 // 上传URL有效期(秒) const DOWNLOAD_EXPIRE = 30 // 下载URL最长30秒有效期 // 主入口:根据HTTP方法分发请求 exports.handler = async (event) => { const { httpMethod } = event if (httpMethod === 'POST') return await getUploadURL(event) if (httpMethod === 'GET') return await getDownloadURL(event) return { statusCode: 405, body: JSON.stringify({ msg: '不支持的请求方法' }) } } // 生成CSV上传预签名URL(原有逻辑优化) const getUploadURL = async (event) => { const key = `test.csv` const s3Params = { Bucket: process.env.UploadBucket, Key: key, Expires: UPLOAD_EXPIRE, ContentType: 'text/csv' } const uploadURL = await s3.getSignedUrlPromise('putObject', s3Params) return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ uploadURL, key }) } } // 生成PDF下载预签名URL const getDownloadURL = async (event) => { // 实际场景中可从请求参数获取对应文件Key(比如替换上传CSV的后缀) const pdfKey = `test.pdf` const s3Params = { Bucket: process.env.UploadBucket, Key: pdfKey, Expires: DOWNLOAD_EXPIRE, // 强制浏览器触发下载而非预览 ResponseContentDisposition: 'attachment; filename="转换结果.pdf"' } const downloadURL = await s3.getSignedUrlPromise('getObject', s3Params) return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ downloadURL }) } }
步骤2:配置API网关
- 在现有API下新增
/download资源,设置HTTP方法为GET。 - 将该资源集成到上述Lambda函数,确保API网关传递
httpMethod参数到Lambda(集成请求映射模板保持默认即可)。 - 配置集成响应,将Lambda返回的JSON直接作为响应体返回给客户端(状态码映射为200)。
2. 将预签名URL转发至浏览器触发下载
在前端代码中,上传完成后调用下载接口获取预签名URL,通过动态创建<a>标签触发浏览器下载:
<div> <!-- 原有上传组件 --> <h2 v-if="uploadURL">文件已上传至S3</h2> <button v-if="uploadURL" @click="startDownload">下载转换后的PDF</button> </div> <script> const API_UPLOAD = 'https://*****.execute-api.us-east-1.amazonaws.com/uploads' const API_DOWNLOAD = 'https://*****.execute-api.us-east-1.amazonaws.com/uploads/download' export default { data() { return { uploadURL: null } }, methods: { // 原有获取上传URL的逻辑 async getUploadLink() { const res = await fetch(API_UPLOAD, { method: 'POST' }) const data = await res.json() this.uploadURL = data.uploadURL }, // 触发下载逻辑 async startDownload() { try { const res = await fetch(API_DOWNLOAD, { method: 'GET' }) const data = await res.json() if (data.downloadURL) { // 创建临时a标签触发下载 const link = document.createElement('a') link.href = data.downloadURL link.style.display = 'none' document.body.appendChild(link) link.click() document.body.removeChild(link) } } catch (err) { console.error('下载失败:', err) } } } } </script>
关键说明
- Lambda生成下载URL时,
ResponseContentDisposition参数是强制浏览器触发下载的核心,避免文件被直接预览。 - 预签名URL有效期严格控制为30秒,符合需求。
- 前端通过动态创建a标签的方式,无需跳转页面即可触发下载,提升用户体验。
内容的提问来源于stack exchange,提问作者iJup
相关产品推荐
相关产品推荐

