【问题标题】:Missing "access-control-allow-origin" in PUT response header of GCS resumable uploadGCS 可恢复上传的 PUT 响应标头中缺少“access-control-allow-origin”
【发布时间】:2017-06-18 13:17:10
【问题描述】:

我目前正在尝试实现从网络浏览器到谷歌云存储桶的可恢复上传。我正在使用以下记录的程序:

1) 通过从网络服务器发送到 GCS 的 http POST 启动可恢复上传。

2) 将返回的上传 url 发送到浏览器,并通过 XmlHttpRequest 发出 Http PUT 来上传数据。

直到最后,一切似乎都运行良好。 IE。浏览器首先发送返回 OK (200) 的 OPTIONS 预检请求,然后发送一个上传文件的 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--cwY7qq2jNHGrru--cwY7 请求方法:OPTIONS
状态码:200
远程地址:[2607:f8b0:4009:811::2010]:443

OPTIONS 响应标头

访问控制允许凭据:true
访问控制允许标头:内容范围、内容类型、x-上传内容类型
访问控制允许方法:PUT
访问控制允许来源:http://www.example.com
alt-svc:quic=":443";马=2592000; v="35,34"
内容长度:0
内容类型:文本/html;字符集=UTF-8
日期:格林威治标准时间 2017 年 2 月 1 日星期三 16:48:18
服务器:上传服务器
状态:200

PUT 请求

请求网址:“https://BUCKET.storage-upload.googleapis.com/1485967698353.e57?upload_id=AEnB2UohgRBG272hoHLZ9i-wLeTn45KKoMjTDEQGu-GoUl-1JQf5_sOnf7IjtpN0wuYzHgzEu3Qi9tpVHGrdw--cw7 请求方法:PUT
状态码:200
远程地址:[2607:f8b0:4009:811::2010]:443

PUT 响应标头

alt-svc:quic=":443";马=2592000; v="35,34"
内容长度:0
内容类型:文本/html;字符集=UTF-8
日期:格林威治标准时间 2017 年 2 月 1 日星期三 16:48:19
etag:“c6f30652db5986aec4c00e80a9d00f25”
服务器:上传服务器
状态:200
不同:产地
x-goog-generation:1485967699029000
x-goog-hash:md5=xvMGUttZhq7EwA6AqdAPJQ==
x-goog-hash:crc32c=/vx4zQ==
x-goog-metageneration:1
x-goog-stored-content-encoding:身份
x-goog-stored-content-length: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”周围有引号来打乱链接)。 “来源”在请求中。

发布“https”://BUCKET.storage-upload.googleapis.com/1485967698353.e57
接受编码:gzip
授权:承载2342342234234234234234234234-234234234234234234234234234234234234234234234234sxx-FSpWkCqI0BCRWoG2342423s423423423A4234_234E23s423i423423423423423423423423423234234234234234234234234234234234234234234234234X结果 用户代理:Google-HTTP-Java-Client/1.22.0 (gzip)
x-goog-resumable: 开始
来源:“http:”/www.example.com
内容长度:0

我可以通过简单地忽略 XmlHttpRequest 错误来解决这个问题,但这会导致客户端出现一些奇怪的编码。理想情况下,有一个答案......

【问题讨论】:

标签: google-cloud-storage


【解决方案1】:

聚会有点晚了,但我目前面临同样的问题。以下是我如何设法在服务器上执行 POST 和在客户端上执行 PUT。

1> 在存储桶上设置 CORS 配置

文档在这里: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 次上传中断。

2> 在初始 POST 中传递“Origin”标头

文档在这里:https://cloud.google.com/storage/docs/xml-api/resumable-upload#step_1wzxhzdk14initiate_the_resumable_upload

在 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'] 保存您需要发送给客户端的 url。您将用于 PUT 请求的那个。

3> 在客户端发出请求

在 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": ["*"]}]

【讨论】:

    【解决方案2】:

    当您最初请求可恢复的上传 url(通常来自您的服务器,这是上面的“POST”)时,您需要指定一个“来源”。这需要是浏览器在开始发送文件时将发送的任何来源,即:浏览器中 location.origin 的值。而且必须准确。

    在我的代码中,我通过在服务器上实现请求可恢复上传功能来实现这一点,但让浏览器将 location.origin 传递给该函数。

    请注意,在上面的问题中,原点被传递,但它看起来不正确(其中有一些奇怪的双引号)。

    【讨论】:

      【解决方案3】:

      在我忘记这篇文章之前,我想留下我最终找到的解决方案。问题出在这些步骤上

      1) 通过从 Web 服务器发送到 GCS 的 http POST 启动可恢复上传。

      2) 将返回的上传 url 发送到浏览器并发出 Http PUT 通过 XmlHttpRequest 上传数据。

      我最终在客户端上同时执行了 1) 和 2)。为此,我为服务器上的初始帖子创建了一个签名的 url,并将其发送到浏览器。然后浏览器同时发出 POST 启动上传和随后的 PUT 发送文件。

      这里的一些解决方案建议您可以在服务器上执行初始 POST,但这对我不起作用。

      【讨论】:

      • 嗨,我已经处理这个问题好几天了。终于有了一些工作,它上传文件但以同样的问题结束,一个 200 但仍然缺少 CORS 标头“Access-Control-Allow-Origin”。我正在使用 XML api 通过服务器发送 POST 并将位置传递给客户端并使用 Jquery ajax 调用。您能否分享一下您是如何在服务器上签署网址的,我也遇到了问题,而且我还没有实施上传的可恢复部分以防中断,如果您能分享一下,我将不胜感激。谢谢
      • 对 url 签名有很好的记录。我刚用谷歌搜索,找到了谷歌云文档。我最终使用了storage.googleapis.com 端点。希望这会有帮助。在任何情况下,通过从客户端执行 POST 和 PUT,您都处于正确的轨道上。
      • 最后,我通过 XML API 在服务器上使用 POST,然后将返回的位置传递给客户端。您只需将客户端的来源作为标头放在服务器上的 POST 中即可避免 CORS 问题。我刚刚在客户端实现简历代码
      猜你喜欢
      • 2015-01-15
      • 2014-06-08
      • 2020-05-12
      • 1970-01-01
      • 1970-01-01
      • 2019-02-07
      • 2018-03-28
      • 2021-07-15
      • 1970-01-01
      相关资源
      最近更新 更多