javascript - XMLHttpRequest 端点在签署 S3 请求时被阻止,因为没有 HTTPS,尽管一切都在 HTTPS 上
问题描述
我正在尝试签署一个巨大的视频上传,因为我想将它直接上传到 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
函数(未经测试)。
推荐阅读
- sql-server - Invoke-SqlServerQuery 使用错误的域和用户名
- javascript - Redux 使用扩展存储形状
- java - 只异步运行一个方法10秒android
- react-native - 在反应原生类函数中处理这个关键字
- r - 从格式为 JSON 的 csv 列中提取信息
- r - 在 For 循环中使用 quantmod 函数 getSymbols 时下载失败
- vb.net - 标签不包含位置属性
- ios - 使用 NSLayoutAnchor 不好吗?
- python - 使用映射创建新的 ElasticSearch 索引
- android - 弹出片段后,所有 Editexts 都将替换为相同的值