2014-09-05 117 views
7

我使用XMLHttpRequest发送到服务器端创建的可恢复上载url,将基于浏览器的可恢复上载实施到Google Cloud Storage中。在禁用Web安全性时,这种做法完全正常,这是我在开发过程中所做的。XMLHttpRequest CORS到Google Cloud Storage仅适用于预检请求

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

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

请求是使用普通的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); 
} 

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

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 

请求报头:

: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 

查询字符串参数

uploadType:resumable 
name: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 
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 

...,直到所有的数据传送开始PUT请求。但是之后,chrome在没有完成/结束请求的情况下悄悄地记录错误:

XMLHttpRequest无法加载https://www.googleapis.com/upload/storage/v1/b/my-bucket-name ... XXXXXXXX。请求的资源上没有“Access-Control-Allow-Origin”标题。因此不允许访问原产地'https://fake.host'。

这是关于什么的PUT请求铬日志:

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

请求头

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 

查询字符串

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

值得注意的是,在http://client.cors-api.appspot.com/client添加相同的URL时,与发行任何请求,除OPTIONS请求类型之外的所有请求都会失败。看起来云存储api只会为OPTION请求发出正确的响应头,但不会发出PUT/POST/GET/...请求。

那么我在做一些不可能的事情吗?有什么东西坏了吗?这是云存储API中的错误吗?我花了数小时搜索和阅读SO答案,至今没有任何运气。现在,我可以定期检查下载是否传输了100%的数据,并忽略了http请求结果,因为该文件实际上已完全上传到存储分区。但这是一个相当丑陋的解决方法,如果真正的问题可以解决,我真的不想使用它。

+0

你在GCS上的CORS上设置了吗? https://cloud.google.com/storage/docs/cross-origin#Configuring-CORS-on-a-Bucket – Ryan 2014-10-09 21:07:34

+0

当然可以。我猜没有它,预检请求会失败,而没有。上传文件后只有最终响应无效。 – Roben 2014-10-10 13:10:35

+0

你可以显示你使用的json吗?感觉像你忘记了“方法”:[“PUT”,“POST”,“GET”], – Ryan 2014-10-10 16:00:42

回答

3

当请求支援续传的上传URL,则必须包含原点时,试图使用上传网址,否则后续的上传会失败,就像在问题发生的事情(这些选项调用将浏览器将发送看起来不错,但PUT不会)。

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

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

如果您请求在服务器端可恢复上传网址,你可能需要在客户端(浏览器)传递你的来源(例如:location.origin)。

FWIW我使用谷歌的云存储库的Python这一步,并添加起源这样的需要:

myblob.create_resumable_upload_session(mycontenttype, origin=browserorigin) 

注意,你绝对不需要建立CORS为你的水桶。

+1

我想这在三年前是不可能的,但现在看来它是正确的解决方案。 2016年有关于此问题的git问题(即https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1099)。谢谢! – Roben 2017-07-06 08:56:11

3

由于这个问题仍然没有得到答案,仍然得到相当数量的观点,我会尝试在这里发布一些权威性的东西。

在响应中返回到任何PUT请求上传数据总是被设置到在用于the initial POST request给出的origin发起上载,如每current docs'Access-Control-Allow-Origin'头:

当使用可恢复的上传协议,即使您对后续请求使用不同的Origin,始终使用来自第一个 (开始上载)请求的Origin来响应该请求,以决定 Access-Control-Allow-Origin标头。因此,您应该为 对第一个和后续请求使用相同的来源,或者如果 第一个请求与后续请求的来源不同,请使用XML API,并将CORS配置设置为*。

这意味着您必须在发送数据的任何PUT请求之前发送初始POST请求,并且任何后续的PUT请求必须与初始POST具有相同的“起源”。

关于CORS配置GCS设置,这仅适用于调用的XML API,从current docs

注:CORS配置仅适用于XML API请求。对于JSON API请求,云端存储总是返回 Access-Control-Allow-Origin标头与请求的来源。

相关问题