You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于预签名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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 14:01:35