Laravel中用预签名URL上传S3遇SignatureDoesNotMatch错误
解决S3预签名URL上传时的SignatureDoesNotMatch错误
以下是导致签名不匹配的几个关键问题及修复方案:
1. Content-Type不匹配或格式错误
预签名URL生成时如果未指定Content-Type,实际请求中新增的Content-Type会导致签名校验失败。同时你设置的'MP4'不是标准MIME类型,正确值应为'video/mp4'。
修复:
生成预签名命令时明确指定Content-Type,确保和请求时一致:
$cmd = $s3Client->getCommand('PutObject', [ 'Bucket' => config('filesystems.disks.s3.bucket'), 'Key' => $path, 'Content-Type' => 'video/mp4' // 添加此行,与请求保持一致 ]);
同时修正curl请求的headers:
$headers = [ 'Content-Type: video/mp4', // 改为标准MIME类型格式 ];
2. CURL参数混用错误
同时使用CURLOPT_PUT和CURLOPT_POSTFIELDS会导致请求格式异常,对于PUT上传,应使用文件流方式传递内容,既保证请求正确性又避免大文件内存溢出问题。
修复:
替换curl相关代码为:
$ch = curl_init($presignedUrl); // 启用上传模式 curl_setopt($ch, CURLOPT_UPLOAD, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 打开文件流 $fileHandle = fopen($file, 'r'); curl_setopt($ch, CURLOPT_INFILE, $fileHandle); // 使用文件实际大小,避免二进制文件长度计算错误 curl_setopt($ch, CURLOPT_INFILESIZE, filesize($file)); $response = curl_exec($ch); // 关闭文件流 fclose($fileHandle); curl_close($ch);
3. Content-Length计算错误
strlen($fileContents)不适用于MP4这类二进制文件,会导致长度计算不准确,进而触发签名校验失败。改用filesize($file)直接获取文件实际大小即可解决。
额外检查项
- 确认AWS凭证(key/secret)和区域配置完全正确,无拼写错误
- 确保生成预签名URL的
$path与实际上传的对象Key完全一致,S3的Key区分大小写
内容的提问来源于stack exchange,提问作者vinita darji
相关产品推荐
相关产品推荐

