我正在尝试对一个巨大的视频上传进行签名,因为我想将它直接上传到 S3。它在本地主机上工作,但在我的实时站点上它无法签署请求,因为:
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})
最佳答案
经过几个小时的研究,我决定重建这个函数并使用我更熟悉的 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
函数(未经测试)。
关于javascript - XMLHttpRequest 端点在签署 S3 请求时被阻止,因为没有 HTTPS,尽管一切都在 HTTPS 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50352091/