使用预签名请求上传含Unicode文件名的文件至S3时出现403 Forbidden错误的解决咨询
预签名请求上传含Unicode文件名的文件至S3时出现403 Forbidden错误的解决咨询
我最近碰到了一个特别棘手的问题:如果文件名是由Unicode码点构成的,使用预签名请求上传到S3时就会返回403 Forbidden,而且没有任何响应体,调试起来完全摸不着头绪。后来我试着把像ä这样的Unicode字符换成ASCII的a,上传就正常了——这还是我看其他相关问题提到文件名URL编码才想到的测试方向。
先给大家看看我的后端生成预签名URL的代码:
$userId = ...; // 这里的逻辑不影响问题 $filename = ...; // 从POST请求中获取的原始文件名 $safeName = trim(preg_replace('/[^a-z0-9\-_.]/i', '-', $filename), '-'); // AWS只允许特定字符作为对象键 $key = sprintf('user-documents/%s/%s', $userId, $safeName); $metadata = [ 'type' => 'USER_DOCUMENT', 'userId' => $userId, 'filename' => $filename, // 这里用的是POST过来的原始文件名 ]; $s3 = new S3Client([ 'region' => getenv('AWS_REGION'), 'version' => 'latest', 'credentials' => CredentialProvider::env(), ]); $uploadUrl = $s3->createPresignedRequest( $s3->getCommand('PutObject', [ 'Bucket' => getenv('AWS_BUCKET_USER_DATA'), 'Key' => $key, 'Metadata' => $metadata, ]), '+1 hour', )->getUri(); $response = [ 'uploadUrl' => $uploadUrl, 'metadata' => $metadata, ];
然后是前端负责上传文件到S3的代码:
const file = fileInput.files[0]; const response = await getUploadUrl(file.name); // 这里的file.name就是传给后端POST的文件名 await fetch(response.uploadUrl, { method: 'PUT', headers: { 'x-amz-meta-type': response.metadata.type, 'x-amz-meta-userid': response.metadata.userId, 'x-amz-meta-filename': response.metadata.filename }, body: file, }).then(resp => { if (!resp.ok) { throw new Error('File upload failed: ' + resp.status + ' ' + resp.statusText) } });
我现在的困惑点在于:
- 生成的
uploadUrl里已经包含了URL编码后的原始文件名,按道理AWS那边应该会自动解码吧?毕竟这是他们自己的SDK处理的编码啊 - 元数据头里我传的是原始未编码的文件名
我实在搞不清楚问题出在哪里,到底需要修改哪部分代码才能解决这个Unicode文件名导致的403问题?另外我的AWS PHP SDK版本是aws/aws-sdk-php@3.334.2,不知道这个版本会不会有影响。
备注:内容来源于stack exchange,提问作者jurchiks
相关产品推荐
相关产品推荐

