【免费下载链接】context-hub
本篇技术指南以仓库 content/aws/docs/s3-presigned-post/javascript/DOC.md 为主体,系统讲解如何使用 AWS SDK for JavaScript v3 的@aws-sdk/s3-presigned-post包,在受信任的后端生成面向浏览器或其他 multipart 客户端的 S3 HTML 表单上传(Presigned POST)。文章覆盖安装、前置条件、服务端签名、浏览器直传、POST 策略约束、常见陷阱与版本说明,并结合本仓库(Context Hub)中的同源文档与 CLI 用法,帮助读者快速落地一套“后端签名、前端直传、文件不经过应用服务器”的完整上传链路。
包定位:何时该用s3-presigned-post
@aws-sdk/s3-presigned-post解决的核心场景是:后端生成一个 S3 HTML 表单上传,交给浏览器或其他 multipart 客户端直接提交文件。调用createPresignedPost()后,包会返回一个表单url和一组已签名的fields。上传方需要把这些fields与文件一起,以multipart/form-data的 POST 请求发回 S3,S3 校验签名与策略后完成对象写入。
关键区分点在于:如果你的需求是预签名的PUTURL(即把请求本身签名成一个可直接访问的 URL),而不是浏览器表单 POST,那么应该改用@aws-sdk/s3-request-presigner。本仓库也收录了对应文档 content/aws/docs/s3-request-presigner/javascript/DOC.md,其中明确写着“Use@aws-sdk/s3-presigned-postinstead when you need a browser form POST policy rather than a signed request URL”,两份文档互为补充,可按场景二选一。
安装
使用 npm 安装客户端与签名包(同一 AWS SDK v3 应用中建议保持版本一致):
npm install @aws-sdk/client-s3@3.1007.0 @aws-sdk/s3-presigned-post@3.1007.0@aws-sdk/client-s3:提供S3Client实例,承载区域与凭证配置;@aws-sdk/s3-presigned-post:提供核心函数createPresignedPost()。
前置条件
后端凭证环境变量
调用createPresignedPost()的代码只需要正常的 AWS SDK v3 S3 配置即可工作:
AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_SESSION_TOKEN=... AWS_PROFILE=default S3_BUCKET=my-upload-bucket安全红线:必须在受信任的后端创建 presigned POST,绝不能把长期有效的 AWS 凭证暴露在浏览器代码中。浏览器端只应收到最终的url与fields。
桶的 CORS 规则
浏览器直传场景下,目标桶还需要一条允许前端源发送POST请求的 CORS 规则。以下命令允许http://localhost:3000发起POST并暴露ETag:
aws s3api put-bucket-cors \ --bucket "$S3_BUCKET" \ --cors-configuration '{ "CORSRules": [ { "AllowedOrigins": ["http://localhost:3000"], "AllowedMethods": ["POST"], "AllowedHeaders": ["*"], "ExposeHeaders": ["ETag"] } ] }'需要注意:合法的签名并不会绕过跨域限制——浏览器上传时桶的 CORS 依然生效,跨域请求必须被 CORS 规则放行。
在服务端创建 presigned POST
初始化S3Client后,调用createPresignedPost()并传入目标桶、对象键以及希望 S3 强制执行的表单约束:
import { S3Client } from "@aws-sdk/client-s3"; import { createPresignedPost } from "@aws-sdk/s3-presigned-post"; const s3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-1", }); export async function createImageUpload({ key, contentType }) { const bucket = process.env.S3_BUCKET; if (!bucket) { throw new Error("Set S3_BUCKET"); } const { url, fields } = await createPresignedPost(s3, { Bucket: bucket, Key: key, Fields: { "Content-Type": contentType, success_action_status: "201", }, Conditions: [ { "Content-Type": contentType }, { success_action_status: "201" }, ["content-length-range", 0, 5 * 1024 * 1024], ], Expires: 600, }); return { url, fields, key }; }核心参数说明:
| 参数 | 作用 |
|---|---|
Bucket | 目标桶名称,必填 |
Key | 对象键(存储路径),必填;可写成固定路径,也可由调用方传入动态 key |
Fields | 预填进表单的字段,S3 会按这些字段生成签名;浏览器上传时必须原样携带 |
Conditions | POST 策略中的约束条件,决定 S3 接受哪些请求;支持精确匹配对象条件与starts-with、content-length-range等数组形式条件 |
Expires | presigned POST 的有效期,单位是秒 |
两个容易被忽略的细节:
Expires是 presigned POST 的存活时间(秒),示例中600表示签名在 10 分钟内有效,过期后 S3 会拒绝该表单。- 想让 S3 强制某个字段值(如
Content-Type)时,必须同时把它放进Fields和Conditions。只放Fields只是预填默认值,不构成强制约束;只有Conditions里的约束才会写进 POST 策略并被 S3 校验。
从本仓库内容结构看,该文档被组织为aws作者下的多语言变体:content/aws/docs/s3-presigned-post/javascript/DOC.md,其 frontmatter(name: s3-presigned-post、metadata.versions: 3.1007.0、source: maintainer、tags等)遵循仓库 docs/content-guide.md 规定的 DOC.md 规范,供 Agent 通过 CLI 检索定位。
从浏览器上传文件
整体流程:前端把上传意图发给后端 → 后端返回已签名的表单载荷 → 前端把fields与文件组装成FormData,直接 POST 到 S3。
export async function uploadFile(file) { const key = `uploads/${crypto.randomUUID()}-${file.name}`; const presignResponse = await fetch("/api/uploads/presign", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ key, contentType: file.type || "application/octet-stream", }), }); if (!presignResponse.ok) { throw new Error("Failed to create presigned POST"); } const { url, fields } = await presignResponse.json(); const formData = new FormData(); for (const [name, value] of Object.entries(fields)) { formData.append(name, value); } formData.append("file", file); const uploadResponse = await fetch(url, { method: "POST", body: formData, }); if (!uploadResponse.ok) { throw new Error(`S3 upload failed with ${uploadResponse.status}`); } return { key }; }关键要求:上传方必须把返回的fields原样送回。这些签名值本身就是 POST 策略的一部分,任何缺失、改动或顺序不符都会导致 S3 拒绝请求;文件字段则统一以file为字段名追加到FormData末尾。fetch(url, { method: "POST", body: formData })会自动把请求体编码为multipart/form-data——这也是 S3 表单上传要求的编码格式,该包不生成签名的PUTURL,务必用 POST 提交。
常见策略模式
精确匹配:后端已知字段值
当后端已经知道某个字段的确切取值(例如头像固定为 PNG)时,使用对象形式的精确匹配条件:
const post = await createPresignedPost(s3, { Bucket: process.env.S3_BUCKET, Key: "uploads/avatar.png", Fields: { "Content-Type": "image/png", }, Conditions: [ { "Content-Type": "image/png" }, ["content-length-range", 0, 1 * 1024 * 1024], ], Expires: 300, });这里{ "Content-Type": "image/png" }强制上传的 Content-Type 必须是image/png,content-length-range把文件大小限制在 1 MiB 以内。
starts-with:一份签名接受多种取值
当需要在同一份签名策略下接受多种取值(例如所有image/*类型)时,使用starts-with条件:
const post = await createPresignedPost(s3, { Bucket: process.env.S3_BUCKET, Key: "uploads/image-upload", Conditions: [ ["starts-with", "$Content-Type", "image/"], ["content-length-range", 0, 10 * 1024 * 1024], ], Expires: 300, });注意starts-with的写法:第一项是字面量"starts-with",第二项是带$前缀的字段名$Content-Type,第三项是前缀值"image/"。该模式下不需要在Fields里写死具体值,浏览器可自行选择任意image/*类型,文件大小上限放宽到 10 MiB。
重要陷阱清单
- 签名必须产生于你控制的后端,浏览器只应收到最终的
url和fields,杜绝长期凭证暴露。 - 必须以
multipart/form-dataPOST 到返回的url;本包不生成签名的PUTURL(需要 PUT URL 时改用@aws-sdk/s3-request-presigner,见 content/aws/docs/s3-request-presigner/javascript/DOC.md)。 - 需要 S3 强制表单字段值时,把该值同时放进
Fields和Conditions,二者缺一不可。 - 桶的 CORS 依然生效:合法签名不能绕过跨域限制,浏览器直传必须配好 CORS 规则。
S3Client使用的 IAM 凭证仍需具备目标桶与对象键的权限(如s3:PutObject),签名不能越权。- 从包根路径导入:
import { createPresignedPost } from "@aws-sdk/s3-presigned-post",不要从深层子路径导入。
版本说明与配套
- 本文档覆盖
@aws-sdk/s3-presigned-post版本3.1007.0,与仓库内 content/aws/docs/s3-presigned-post/javascript/DOC.md 的 frontmatter 中versions: "3.1007.0"一致。 - 需与
@aws-sdk/client-s3搭配,二者应保持在同一个 AWS SDK v3 依赖集合中,避免不必要的版本漂移。
在 Context Hub 中获取与定位本文档
本文档是 Context Hub 仓库中按“作者 → 类型 → 条目 → 语言”结构组织的多语言文档变体(结构规则见 docs/content-guide.md)。Agent 或开发者可以通过 CLI 直接检索并拉取该文档:
chub search "s3 presigned post" # 检索相关文档 chub get aws/s3-presigned-post --lang js # 拉取 JavaScript 变体(即本文档)文档 frontmatter 中的name、description、metadata.tags等字段(见 content/aws/docs/s3-presigned-post/javascript/DOC.md 顶部)正是供chub search检索、供 Agent 快速判断内容与版本匹配度的元数据。围绕本文档,仓库还收录了配套的s3-request-presigner文档(content/aws/docs/s3-request-presigner/javascript/DOC.md),可在需要预签名PUT/GETURL 时对照查阅,形成完整的 S3 签名上传/下载方案。
【免费下载链接】context-hub
相关推荐
使用 AWS SDK for .NET (v4) 实操 Amazon S3:从 Hello 入门到 Presigned POST 全流程
使用 AWS SDK for .NET v4 实操 Amazon S3:从 Hello 入门到 Presigned POST 全流程 导读 本文围绕 dotne
示例工程教程后端AWS SDK for JavaScript v3 中的 Amazon S3 代码示例解析
AWS SDK for JavaScript v3 中的 Amazon S3 代码示例解析 概述 Amazon Simple Storage Service A
示例工程教程后端Django S3 Presigned URLs 实战指南:从 `.url()` 自动签名到浏览器直传上传(基于 claude-skills 的 django-storages-s3 技能)
Django S3 Presigned URLs 实战指南:从 .url 自动签名到浏览器直传上传(基于 claude skills 的 django stor
AI 技能AI 插件后端前端DevOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考