我正在尝试签署一个巨大的视频上传,因为我想将其直接上传到S3。它适用于localhost,但在我的实际站点上,由于以下原因,它无法签署请求:
Mixed Content: The page at 'https://www.example.com/profile' was loaded
over HTTPS, but requested an insecure XMLHttpRequest endpoint
'http://www.example.com/sign_s3/?file_name=17mbvid.mp4&file_type=video/mp4'.
This request has been blocked; the content must be served over HTTPS.
我在heroku上托管所有内容,每个页面都已经在使用HTTPS,并且无法在HTTP中打开它,因为我将所有流量重定向到HTTPS。我使用的是letsencrypt SSL证书。
到目前为止,我不知道在哪里查找,我发现的唯一信息是我需要一个有效的SSL证书,我有。
这是JS函数:
function getSignedRequest(file) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/sign_s3?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('got signed request');
var response = JSON.parse(xhr.responseText);
console.log(response);
console.log('uploadFile', response.url)
uploadFile(file, response.data, response.url);
} else {
console.log("Could not get signed URL.");
}
}
};
//console.log('send');
xhr.send();
}
在控制台出错后,我看到了这个控制台日志:
Could not get signed URL.
这意味着它在这里失败了:
if (xhr.status === 200)
在服务器上:
@app.route('/sign_s3/', methods=["GET", "POST"])
@login_required
@check_confirmed
def sign_s3():
if "localhost" in request.url_root:
file_name = str(current_user.id) + "local-profil-video." + request.args.get('file_name').split(".")[-1]
else:
file_name = str(current_user.id) + "-profil-video." + request.args.get('file_name').split(".")[-1]
file_type = request.args.get('file_type')
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'
)
s3 = session.client('s3')
presigned_post = s3.generate_presigned_post(
Bucket = 'adultpatreon',
Key = 'videos/' + file_name,
Fields = {"acl": "public-read", "Content-Type": file_type},
Conditions = [
{"acl": "public-read"},
{"Content-Type": file_type}
],
ExpiresIn = 3600
)
if current_user.profile_video != None:
delete_file_from_aws("videos/", current_user.profile_video)
setattr(current_user, "profile_video", file_name)
db_session.commit()
return json.dumps({'data': presigned_post, 'url': 'https://s3.eu-central-1.amazonaws.com/mybucket/' + 'videos/' + file_name})
答案 0 :(得分:0)
经过几个小时的研究后,我决定重建这个功能并使用AJAX get,我更熟悉。我还改变了我以最佳方式传递/接收查询字符串参数的方式,这实际上是在flask / python中使用的。
function getSignedRequest(file) {
$.ajax({
url : "/sign_s3/" + file.name + "/" + file.type,
type : "get",
success : function(response) {
console.log("success file up, follow", response);
var json_response = JSON.parse(response);
console.log(json_response);
uploadFile(file, json_response.data, json_response.url);
},
error : function(xhr) {
console.log("file up failed", xhr);
}
});
}
在服务器端,我更改了file.name
和file.type
收到的方式:
# Sign request for direct file upload through client for video
@app.route('/sign_s3/<path:file_name_data>/<path:file_type_data>', methods=["GET", "POST"])
@login_required
@check_confirmed
def sign_s3(file_name_data, file_type_data):
#etc...
现在它完美无缺。我认为他们接收服务器上的查询字符串参数的方式不正确,可能它也适用于旧的getSignedRequest
函数(未经测试)。