Python3+Flask+jQuery-File-Upload直传S3遇405方法不允许错误求助
看起来你遇到的405错误核心问题出在客户端表单的Action URL设置错误,再结合几个小细节调整就能解决。我帮你一步步拆解和修复:
1. 修复表单Action的核心错误
你现在手动拼接了表单的Action URL:
$('#direct_s3_profile_video_form').attr('action', 'https://mybucket.s3.amazonaws.com/videos/' + response_json_data.created_file_name);
这是错误的——S3的Presigned Post上传要求POST请求发送到Bucket的根URL,而不是带具体文件路径的URL。你应该直接使用服务端返回的presigned_post中的url字段,也就是你注释掉的那行:
// 删掉手动拼接的那行,打开这行 $('#direct_s3_profile_video_form').attr('action', response_json_data.data.url);
原因:当你POST到带videos/xxx.mp4的URL时,S3会将其识别为对已有对象的PUT请求(而非创建新对象的POST请求),即使你的CORS允许PUT,Presigned Post的签名是针对Bucket根的POST请求,因此会返回405错误。
2. 调整jQuery File Upload的iframe设置
你设置了forceIframeTransport: true,注释说这是解决405的关键,但实际上这可能是另一个隐患:
- 这个选项是为了兼容不支持XHR2的旧浏览器,现代浏览器完全可以去掉它,改用XHR上传,这样能更好地处理S3的响应。
- 如果必须保留这个选项,请确保你的表单设置了
enctype="multipart/form-data"(jQuery File Upload通常会自动处理,但最好手动确认),同时你的success_action_status已经设为200,这能让iframe正确解析S3的响应。
3. 验证服务端IAM权限
你的Bucket策略只允许公开读取GetObject,这没问题,但生成Presigned Post的AWS IAM用户必须拥有s3:PutObject权限。请检查你的IAM用户策略是否包含类似内容:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::mybucket/videos/*" } ] }
没有这个权限的话,即使签名生成成功,上传时也会被S3拒绝。
4. 客户端代码的小修复
你的fileuploadprocessalways事件最后有个未完成的.p,这是语法错误,会导致JS中断,影响上传流程。比如补充完整:
if (index + 1 === data.files.length) { data.context.find('button') .text('Upload') .prop('disabled', false); // 补充完整这部分 }
另外,你在AJAX请求中传递了fileData,但服务端并没有使用这个参数(所有必要信息都通过URL传递了),可以删掉data: {'file': fileData},这一行,简化请求。
5. 确认CORS配置生效
你的CORS配置看起来是正确的,但S3的CORS配置可能需要几分钟才能生效。如果调整完上述内容还是有问题,可以尝试添加ExposeHeader来暴露必要的响应头:
<CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>*</AllowedHeader> <ExposeHeader>ETag</ExposeHeader> <!-- 添加这行,方便客户端获取上传后的文件标识 --> </CORSRule>
按照这些步骤调整后,应该就能解决405错误,实现大视频的客户端直传了。
内容的提问来源于stack exchange,提问作者Roman

