使用Serverless Framework上传至S3时出现异常PUT 403错误
排查S3文件上传403 Forbidden问题
咱们先从最常见的几个环节排查,结合你给出的Serverless配置,大概率是权限或者预签名逻辑出了问题:
1. Lambda函数缺少S3 PutObject权限
这是最容易踩坑的点——你虽然在Resources里定义了S3桶,但Serverless默认不会给Lambda函数自动添加操作这个桶的权限。你需要在provider段的iamRoleStatements里明确赋予Lambda上传文件的权限:
provider: name: aws # 其他配置... iamRoleStatements: - Effect: Allow Action: - s3:PutObject # 注意要指定桶下的所有对象路径,而不是桶本身 Resource: "arn:aws:s3:::${self:custom.s3BucketName}/*"
这里一定要用/*结尾,因为s3:PutObject是针对桶内具体对象的操作,只指定桶ARN会导致权限不足。
2. 预签名URL生成逻辑有误(如果用预签名上传)
如果你的Lambda是用来生成预签名URL给前端上传,那要确保几个关键参数正确:
- HTTP方法必须是
PUT,和你CORS里允许的方法一致 - 指定的
Bucket和Key要准确,Key就是上传后文件在桶里的路径/名称 - 前端上传的
Content-Type必须和预签名里指定的一致,否则会直接返回403
举个Node.js的正确示例:
const AWS = require('aws-sdk'); const s3 = new AWS.S3(); exports.handler = async (event) => { // 从请求参数里获取文件名和内容类型 const { fileName, contentType } = JSON.parse(event.body); const presignedParams = { Bucket: process.env.S3_BUCKET_NAME, // 可以通过环境变量传入桶名 Key: fileName, Expires: 3600, // URL有效期1小时 ContentType: contentType // 必须和前端上传的Content-Type匹配 }; const uploadUrl = s3.getSignedUrl('putObject', presignedParams); return { statusCode: 200, body: JSON.stringify({ uploadUrl }) }; };
3. 检查S3桶策略的额外限制
虽然你设置了AccessControl: Private,但如果桶有附加的自定义桶策略,可能会意外拒绝PutObject请求。你可以登录AWS控制台,找到这个桶的“权限”->“桶策略”,确认没有类似Deny规则阻止了上传操作。
另外,AWS的权限逻辑是默认拒绝,所以必须确保有明确的Allow规则(要么来自IAM角色,要么来自桶策略)。
4. 确认CORS配置生效
你的CORS配置看起来是正确的,但有时候Serverless部署后CORS规则需要几分钟才能生效。可以手动去S3控制台的“权限”->“跨域资源共享(CORS)”里确认规则是否和你配置的一致:
CorsConfiguration: CorsRules: - AllowedMethods: - PUT - HEAD AllowedOrigins: - "*" AllowedHeaders: - "*"
如果规则没同步上去,可以尝试重新部署一次Serverless服务。
先从Lambda的IAM权限开始排查,这是90%以上这类问题的根源,然后再检查预签名逻辑和桶策略,应该就能解决403的问题了。
内容的提问来源于stack exchange,提问作者Darrell Brogdon
相关产品推荐
相关产品推荐

