XMLHttpRequest CORS到Google Cloud Storage仅适用于预检请求 [英] XMLHttpRequest CORS to Google Cloud Storage only working in preflight request

查看:115
本文介绍了XMLHttpRequest CORS到Google Cloud Storage仅适用于预检请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用XMLHttpRequest发送到服务器端创建的可恢复上传url,将基于浏览器的可恢复上传实施到Google的云端存储中。这在禁用网络安全性的时候是完全正常的,我在开发过程中也是如此。



但是现在在现实世界中,CORS一直在制造麻烦。我也试着用其他浏览器(没有成功),但坚持铬进行进一步测试。



注意: fake.host / etc / HOSTS 中的code>条目被用来欺骗铬以避免本地主机限制。尽管如此,我们的在线测试服务器的真实域也是如此。



请求通过一个普通的XMLHttpRequest调用开始:

  var xhr = this.newXMLHttpRequest(); 
xhr.open('PUT',url,true);

xhr.setRequestHeader('Content-Type',this.currentInputFile.type);
xhr.setRequestHeader('Content-Range','bytes'+ startByte +' - '+(this.currentInputFile.size - 1)+'/'+ this.currentInputFile.size);

xhr.onload = function(e){
...
};

...

if(startByte> 0){
xhr.send(this.currentInputFile.slice(startByte));
} else {
xhr.send(this.currentInputFile);
}

然后,浏览器成功启动预检请求:

 远程地址:173.194.71.95:443 
请求URL:https://www.googleapis.com/upload/storage/v1/b/ my-bucket-name / o?uploadType = resumable& name = aa%20spacetestSMALL_512kb.mp4& upload_id = XXXXXXXXX
请求方法:选项
状态码:200 OK



请求标题:

 :host:www .googleapis.com 
:method:OPTIONS
:path:/ upload / storage / v1 / b / my-bucket-name / o?uploadType = resumable& name = aa%20spacetestSMALL_512kb.mp4& upload_id = XXXXXXXXX
:scheme:https
:版本:HTTP / 1.1
接受:* / *
接受编码:gzip,放气
接受语言:en-US ,en; q = 0.8,de; q = 0.6
访问控制请求标题:内容范围,内容类型
访问控制请求方法:PUT
origin: https://fake.host
referer:https://fake.host/upload.xhtml
user-agent:Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_4)AppleWebKit / 537.36(KHTML,如Gecko)Chrome / 37.0.2062.94 Safari / 537.36
x-client-data:YYYYYY

查询字符串参数

  uploadType:可恢复
名称:aa spacetestSMALL_512kb。 mp4
upload_id:XXXXXXXXX

响应标题

  access-control-allow-credentials:true 
access-control-allow-headers:content-range,content-type
access-control-allow -methods:PUT
访问控制允许来源:https://fake.host
替代协议:443:quic
content-length:0
content-type :text / html的; charset = UTF-8
日期:星期五,2014年9月05日14:11:21 GMT
服务器:UploadServer(建于2014年8月18日11:58:36(1408388316))
status:200 OK
version:HTTP / 1.1

...并启动PUT-请求直到所有数据传输完毕。但之后,chrome默默无误地记录了一个错误,但未完成/结束请求: XMLHttpRequest无法加载 https://www.googleapis.com/upload/storage/v1/b/my-bucket-name ... XXXXXXXX。请求的资源上没有Access-Control-Allow-Origin标题。原因' https://fake.host '因此不被允许访问。



这是关于PUT请求的chrome日志: p $ p $ 请求URL:https://www.googleapis.com /upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX

请求标题

 临时标题显示
Content-Range:bytes 0-3355302 / 3355303
Content-Type:video / mp4
Origin:https://fake.host
Referer:https://fake.host/upload.xhtml
User-Agent:Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_4)AppleWebKit / 537.36(KHTML,如Gecko)Chrome / 37.0.2062.94 Safari / 537.36
X-DevTools-Emulate-Network-Conditions-Client-Id :YYYYYYY

查询字符串

  uploadType:resumable 
name:aa spacetestSMALL_512kb.mp4 $ b $ upload_id:XXXXXXXXX

值得注意的是,当在 http://client.cors- api.appspot.com/client 并发出任何请求,除 OPTIONS 请求类型之外的所有请求都会失败。看起来云存储api只会为OPTION请求发出正确的响应头信息,而不是PUT / POST / GET / ...请求。



不可能?有什么东西坏了吗?这是云存储API中的错误吗?我花了数小时搜索和阅读SO答案,至今没有任何运气。

现在,我可以定期检查下载是否传输了100%的数据,并忽略了http请求结果,因为该文件实际上已完全上传到存储桶。但是,这是一个相当丑陋的解决方法,如果真正的问题可以得到解决,我真的不想使用它。 当解决方案

请求一个可恢复的上传url,你必须包含浏览器在尝试使用该上传url时发送的来源,否则随后的上传将失败,就像问题中发生的一样(OPTIONS调用看起来不错,但PUT会不)。



它必须与浏览器的原点完全匹配(您可以在javascript中使用location.origin)。

这是本文档中启动可恢复上传会话的步骤:
https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload



如果您在服务器端请求可恢复的上传url,则可能需要客户端(浏览器)将其源(例如:location.origin)传递给您。



fwiw我为这一步使用了Google的云存储库for python,并且需要添加像这样的源代码:

  myblob.create_resumable_upload_session(mycontenttype,origin = browserorigin)

请注意,您绝对不需要为您的存储桶设置CORS。


I implemented browser based resumable uploads into Google's Cloud Storage using an XMLHttpRequest send to a server-side created resumable upload url. This works completely fine when disabling web security, which I did during development.

But now in the real world, CORS keeps making trouble. I tried this with other browsers (without success), too, but sticked to chrome for further testing.

Note: A fake.host entry in /etc/HOSTS is used to trick chrome into avoiding localhost-restrictions. Nevertheless, same happens with the "real" domain of our online test server.

The request is started using a normal XMLHttpRequest call:

var xhr = this.newXMLHttpRequest();
xhr.open('PUT', url, true);

xhr.setRequestHeader('Content-Type', this.currentInputFile.type);
xhr.setRequestHeader('Content-Range', 'bytes ' + startByte + '-' + (this.currentInputFile.size - 1) + '/' + this.currentInputFile.size);

xhr.onload = function(e) {
   ...
};

...

if (startByte > 0) {
    xhr.send(this.currentInputFile.slice(startByte));
} else {
    xhr.send(this.currentInputFile);
}

The browser then successfully initiates a preflight request:

Remote Address:173.194.71.95:443
Request URL:https://www.googleapis.com/upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX
Request Method:OPTIONS
Status Code:200 OK

Request Headers:

:host:www.googleapis.com
:method:OPTIONS
:path:/upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX
:scheme:https
:version:HTTP/1.1
accept:*/*
accept-encoding:gzip,deflate
accept-language:en-US,en;q=0.8,de;q=0.6
access-control-request-headers:content-range, content-type
access-control-request-method:PUT
origin:https://fake.host
referer:https://fake.host/upload.xhtml
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36
x-client-data:YYYYYY

Query String Parameters

uploadType:resumable
name:aa spacetestSMALL_512kb.mp4
upload_id:XXXXXXXXX

Response Headers

access-control-allow-credentials:true
access-control-allow-headers:content-range, content-type
access-control-allow-methods:PUT
access-control-allow-origin:https://fake.host
alternate-protocol:443:quic
content-length:0
content-type:text/html; charset=UTF-8
date:Fri, 05 Sep 2014 14:11:21 GMT
server:UploadServer ("Built on Aug 18 2014 11:58:36 (1408388316)")
status:200 OK
version:HTTP/1.1

... and starts the PUT-request until all data is transferred. But afterwards chrome silently logs an error without completing/ending the request:

XMLHttpRequest cannot load https://www.googleapis.com/upload/storage/v1/b/my-bucket-name…XXXXXXXX. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fake.host' is therefore not allowed access.

This is what chrome logs about the PUT request:

Request URL:https://www.googleapis.com/upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX

Request Headers

Provisional headers are shown
Content-Range:bytes 0-3355302/3355303
Content-Type:video/mp4
Origin:https://fake.host
Referer:https://fake.host/upload.xhtml
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36
X-DevTools-Emulate-Network-Conditions-Client-Id:YYYYYYY

Query String

uploadType:resumable
name:aa spacetestSMALL_512kb.mp4
upload_id:XXXXXXXXX

Notably, when adding the same url in http://client.cors-api.appspot.com/client and issuing any request, all but the OPTIONS request types fail, too. It seems like the cloud storage api only issues the correct response headers for OPTION requests, but not PUT/POST/GET/... requests.

So am I doing something impossible? Is there something broken? Is this a bug in the cloud storage api? I've spend hours googling and reading SO answers, without any luck so far.

For now, I could periodically check if the download transferred 100% of the data and just ignore the http request outcome, as the file is in fact completely uploaded to the storage bucket. But this is a rather ugly workaround which I really don't want to use if the real issue can be solved.

解决方案

When requesting a resumable upload url, you MUST include the origin the browser will send when trying to use that upload url, or else the subsequent uploading will fail, just as is happening in the question (the OPTIONS call will look good, but the PUT will not).

It must exactly match the browser's origin (which you can get as location.origin in javascript).

This is the step "Initiating a resumable upload session" in this documentation: https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload

If you're requesting the resumable upload url on the server side, you'll probably need the client side (the browser) to pass you its origin (eg: location.origin).

fwiw I was using Google's Cloud Storage library for python for this step, and needed to add the origin like this:

myblob.create_resumable_upload_session(mycontenttype, origin=browserorigin)

Note that you definitely do not need to set up CORS for your bucket.

这篇关于XMLHttpRequest CORS到Google Cloud Storage仅适用于预检请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆