在签署S3请求时阻止XMLHttpRequest端点,因为没有HTTPS,尽管HTTPS上的所有内容都是如此

时间:2018-05-15 13:55:22

标签: javascript python ssl xmlhttprequest

我正在尝试签署一个巨大的视频上传,因为我想将其直接上传到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})

1 个答案:

答案 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.namefile.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函数(未经测试)。