我正在使用Python 3 + Flask将视频文件直接上传到我的S3存储空间,但我得到Method not allowed 405
此外,上传必须在客户端工作,因为视频文件没有大小限制并且会很大。这会导致服务器超时。
这是我的CORS&铲斗政策:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Bucket Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/*"
}
]
}
在服务器端,我用它来签署请求:
# Sign request for direct file upload through client for video
@app.route('/sign_s3/<path:file_name_data>/<path:file_type_data>/<up_type>', methods=["GET", "POST"])
@login_required
@check_confirmed
def sign_s3(file_name_data, file_type_data, up_type):
if "localhost" in request.url_root:
if up_type == "profile_vid":
file_name = str(current_user.id) + get_random_code(5) + "local-profil-video." + file_name_data.split(".")[-1]
else:
file_name = str(current_user.id) + str(randint(1,100)) + "local-post-video-temp." + file_name_data.split(".")[-1]
else:
if up_type == "profile_vid":
file_name = str(current_user.id) + get_random_code(5) + "-profil-video." + file_name_data.split(".")[-1]
else:
file_name = str(current_user.id) + str(randint(1,100)) + "-post-video-temp." + file_name_data.split(".")[-1]
file_type = file_type_data
session = boto3.Session(
aws_access_key_id=app.config['MY_AWS_ID'],
aws_secret_access_key=app.config['MY_AWS_SECRET'],
region_name='eu-central-1'
)
presigned_post = s3.generate_presigned_post(
Bucket = 'mybucket',
Key = 'videos/' + file_name,
Fields = {"acl": "public-read", "Content-Type": file_type},
Conditions = [
{"acl": "public-read"},
{"Content-Type": file_type}
],
ExpiresIn = 3600
)
if up_type == "profile_vid":
if current_user.profile_video != None:
delete_file_from_aws("videos/", current_user.profile_video)
setattr(current_user, "profile_video", file_name)
else:
print ('post video has been uploaded, no need to delete or set here')
db_session.commit()
return json.dumps({'data': presigned_post, 'url': 'https://s3.eu-central-1.amazonaws.com/mybucket/' + 'videos/' + file_name, 'created_file_name' : file_name})
这里是客户端Jquery File Uploade代码:
/************************
* Upload for video
*************************/
$('#NEW_fileupload_video').fileupload({
autoUpload: false,
maxNumberOfFiles: 1,
disableVideoPreview: false,
// new
forceIframeTransport: true, // VERY IMPORTANT. you will get 405 Method Not Allowed if you don't add this.
singleFileUploads: true, //default anyway
// end new
maxFileSize: 9999999000
}).on('fileuploadadd', function (e, data) {
if ($('#NEW_fileupload_video_files div')[0]) {
$('#NEW_fileupload_video_files div').remove();
}
var files = data.files || [];
var nextInQueue = files[0]; //this is a queue, not a list
if (!nextInQueue) return;
var fileData = {name: nextInQueue.name, mime: nextInQueue.type, size: nextInQueue.size};
$.ajax({
url: "/sign_s3/" + data.files[0].name + "/" + data.files[0].type + "/" + 'profile_vid',
type: 'POST',
dataType: 'json',
// I am giving the data through the URL, probably a bad idea
data: {'file': fileData},
async: false,
success: function(res) {
var response_json_data = res;
$('input[name="key"]').val(response_json_data.data.fields['key']);
$('input[name="AWSAccessKeyId"]').val(response_json_data.data.fields['x-amz-credential']);
$('input[name="policy"]').val(response_json_data.data.fields['policy']);
$('input[name="signature"]').val(response_json_data.data.fields['x-amz-signature']);
$('input[name="acl"]').val( response_json_data.data.fields['acl']);
$('input[name="success_action_status"]').val("200");
$('input[name="Content-Type"]').val(nextInQueue.type);
//$('#direct_s3_profile_video_form').attr('action', response_json_data.url);
$('#direct_s3_profile_video_form').attr('action', 'https://mybucket.s3.amazonaws.com/videos/' + response_json_data.created_file_name);
data.submit();
}
});
}).on('fileuploadprocessalways', function (e, data) {
console.log("NEW always");
var index = data.index,
file = data.files[index],
node = $(data.context.children()[index]);
if (file.preview) {
node
.prepend('<br>')
.prepend(file.preview);
}
if (file.error) {
node
.append('<br>')
.append($('<span class="text-danger"/>').text(file.error));
console.log("here", file.error);
}
if (index + 1 === data.files.length) {
data.context.find('button')
.text('Upload')
.prop('disabled', !!data.files.error);
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#NEW_progress_fileupload_video .progress-bar').css(
'width',
progress + '%'
);
}).on('fileuploaddone', function (e, data) {
console.log("done client side video up profile");
}).on('fileuploadfail', function (e, data) {
console.log("fail", e, data);
})
这是HTML:
<form id="direct_s3_profile_video_form" class="form-horizontal" role="form" method="POST" enctype="multipart/form-data">
<input id="NEW_fileupload_video" type="file" name="NEW_fileupload_video_files[]" accept="video/*">
<input type="hidden" name="key">
<input type="hidden" name="AWSAccessKeyId">
<input type="hidden" name="policy">
<input type="hidden" name="signature">
<input type="hidden" name="acl">
<input type="hidden" name="success_action_status">
<input type="hidden" name="Content-Type">
<div id="NEW_progress_fileupload_video" class="progress">
<div class="progress-bar progress-bar-success"></div>
</div>
<div id="NEW_fileupload_video_files" class="files"></div>
<button type="submit"> Upload </button>
</form>
我知道很多代码。我非常接近理解这一切是如何运作的。我想我错过了一些简单的东西。欢迎任何想法!我真的很感激。
修改
以下是DEV控制台的标题:
GENERAL:
Request URL: https://s3.eu-central-1.amazonaws.com/mybucket/videos/3rBHwNlocal-profil-video.mp4
Request Method: POST
Status Code: 405 Method Not Allowed
Remote Address: 52.219.74.48:443
Referrer Policy: no-referrer-when-downgrade
响应标题:
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Origin: *
Allow: HEAD, DELETE, GET, PUT
Connection: close
Content-Type: application/xml
Date: Wed, 23 May 2018 15:18:49 GMT
Server: AmazonS3
Transfer-Encoding: chunked
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-id-2: SOME DATA
x-amz-request-id: MY ID
请求标题:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 1057282
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5gUAipNLOHxSqN8F
Host: s3.eu-central-1.amazonaws.com
Origin: http://localhost:5000
Referer: http://localhost:5000/profile
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36