我目前正在尝试从网络浏览器实施可恢复上传到谷歌云存储桶。我使用的文件化程序如下:
1)通过从Web服务器发送到GCS的http POST发起可恢复上传。
2)将返回的上传URL发送到浏览器并通过XmlHttpRequest发出Http PUT以上传数据。
一切似乎都很好,直到最后。即浏览器首先发送OPTIONS预检请求,该请求返回OK(200),然后发送文件上传的PUT请求。 PUT也返回OK(200),但在标题中不包含Access-Control-Allow-Origin。这将导致XmlHttpRequest触发错误。
我无法弄清楚为什么不返回此标头字段。我认为从GCS一侧上传成功,因为文件实际上出现在存储桶中。但是,浏览器认为发生了错误。以下是从Chrome开发人员控制台中获取的HTTP记录。
选项请求
请求网址:“https://”BUCKET.storage-upload.googleapis.com/1485967698353.e57?upload_id=AEnB2UohgRBG272hoHLZ9i-wLeTn45KKoMjTDEQGu-GoUl-1JQf5_sOnf7IjtpN0wuYzHgzEu3Qi9tpVHGrru--cwY7q2jNQdw
请求方法:选项
状态代码:200
远程地址:[2607:f8b0:4009:811 :: 2010]:443
选项响应标题
访问 - 控制 - 允许的凭证:真
access-control-allow-headers:内容范围,内容类型,x-upload-content-type
访问控制允许的方法:PUT
存取控制允许来源:http://www.example.com
ALT-SVC:QUIC = “:443”; MA = 2592000; V = “35,34”
内容长度:0
内容类型:文本/ HTML;字符集= UTF-8
日期:2017年2月1日星期三16:48:18 GMT
服务器:UploadServer
状态:200
PUT请求
请求网址:“https:”// BUCKET.storage-upload.googleapis.com/1485967698353.e57?upload_id=AEnB2UohgRBG272hoHLZ9i-wLeTn45KKoMjTDEQGu-GoUl-1JQf5_sOnf7IjtpN0wuYzHgzEu3Qi9tpVHGrru--cwY7q2jNQdw
请求方法:PUT
状态代码:200
远程地址:[2607:f8b0:4009:811 :: 2010]:443
PUT响应标头
ALT-SVC:QUIC = “:443”; MA = 2592000; V = “35,34”
内容长度:0
内容类型:文本/ HTML;字符集= UTF-8
日期:2017年2月1日星期三16:48:19 GMT
ETAG: “c6f30652db5986aec4c00e80a9d00f25”
服务器:UploadServer
状态:200
变化:产地
的x goog代:1485967699029000
的x goog哈希:MD5 = xvMGUttZhq7EwA6AqdAPJQ ==
的x goog哈希:CRC32C = / vx4zQ ==
的x goog-metageneration:1个
的x goog存储的内容编码:身份
的x goog存储的内容长度:743424
x-guploader-uploadid:AEnB2UohgRBG272hoHLZ9i-wLeTn45KKoMjTDEQGu-GoUl-1JQf5_sOnf7IjtpN0wuYzHgzEu3Qi9tpVHGrru - cwY7q2jNQdw
因此,PUT响应中没有“access-control-allow-origin”。当我使用签名的URL执行上载时,GCS实际上返回“Access-Control-Allow-Origin”。然而,这不是我绝对需要的可恢复上传。
此问题几乎与
相同XMLHttpRequest CORS to Google Cloud Storage only working in preflight request
但是那里给出的解决方案没有效果。这是启动上传的原始请求(令牌不是真实的,并且“http / s”周围有引用加扰链接)。 “原产地”在请求中。
POST“https”:// BUCKET.storage-upload.googleapis.com/1485967698353.e57
Accept-Encoding:gzip
授权:承载2342342234234234234234234234-234234234234234234234234234234234234234234234234sxx-FSpWkCqI0BCRWoG2342423s423423423A4234_234E23s423i423423423423423423423423423234234234234234234234234234234234234234234234234X
User-Agent:Google-HTTP-Java-Client / 1.22.0(gzip)
x-goog-resumable:开始
来源:“http:”/ www.example.com
内容长度:0
我可以通过简单地忽略XmlHttpRequest错误来解决这个问题,但这会导致客户端上出现一些奇怪的编码。理想情况下,这是一个答案......
答案 0 :(得分:0)
在我忘记这篇文章之前,我想留下我最终找到的解决方案。问题在于这些步骤
1)通过从Web服务器发送到GCS的http POST启动可恢复上传。
2)将返回的上传URL发送到浏览器并发出Http PUT 通过XmlHttpRequest上传数据。
我最终在客户端上做了1)和2)。为此,我在服务器上为初始帖子创建了一个签名URL并将其发送到浏览器。然后浏览器发出POST,启动上传,后续PUT发送文件。
这里的一些解决方案建议您可以在服务器上执行初始POST,但这对我不起作用。
答案 1 :(得分:0)
当您最初请求可恢复的上传网址(通常来自您的服务器,这是上面的“POST”)时,您需要指定“原始”。这需要是浏览器在开始发送文件时发送的来源,即:浏览器中location.origin的值。它需要准确。
在我的代码中,我通过在服务器上实现请求可恢复上传功能,但让浏览器将location.origin传递给此函数来实现此目的。
请注意,在上面的问题中,原点正在传递,但看起来不正确(其中有一些奇怪的双引号)。
答案 2 :(得分:0)
派对有点晚了,但我目前面临同样的问题。以下是我如何设法在服务器上执行POST以及在客户端上执行PUT。
Doc在这里:https://cloud.google.com/storage/docs/gsutil/commands/cors
首先,您必须在正在使用的存储桶上正确设置CORS。为此你可以使用gsutils。
使用您的CORS配置创建文件cors.json并将其设置在您的存储桶
$> cat cors.json
[{"method": ["PUT", "POST"], "origin": ["http://localhost:3000"]}]
$> gsutil cors set cors.json gs://your-bucket-name
$> gsutil cors get gs://user-upload
[{"method": ["PUT", "POST"], "origin": ["http://localhost:3000"]}]
现在,您的存储桶将根据来自" http://localhost:3000"的请求传递正确的PUT和POST标头。您必须允许POST,因为稍后您将原始标头传递给它。请记住,它实际上是一次上传.2。
在python中,您的请求应如下所示:
req = session.post(url, data="", headers={
'Content-Length': '0',
'x-goog-resumable': 'start',
'Authorization': 'Bearer ' + creds.get_access_token().access_token,
'Origin': 'http://localhost:3000'
})
req.raise_for_status()
return req.headers['location']
注意:
根据您的存储桶上的ACL,可能需要也可能不需要授权。我个人永远不会向所有人打开一个桶,我建议您使用严格的ACL,只有您的服务器才能访问并使用'授权'报头中。
req.headers [' location']保存您需要发送给客户端的网址。您将用于PUT请求的那个。
在javascript中它看起来像这样:
const xhr = new XMLHttpRequest();
xhr.open("PUT", signedUrl, true);
xhr.setRequestHeader('Content-type', file.type); # if you specified it when building the signed url
xhr.onload = function () {
console.log("Success"
}
xhr.send(file);
如果您仍然遇到问题,请尝试将CORS配置更改为以下内容(仅用于调试目的):
[{"method": ["*"], "origin": ["*"]}]