没有可恢复上传的“Access-Control-Allow-Origin”标头

Posted

技术标签:

【中文标题】没有可恢复上传的“Access-Control-Allow-Origin”标头【英文标题】:No 'Access-Control-Allow-Origin' header with resumable upload 【发布时间】:2014-06-08 12:55:45 【问题描述】:

我们正在通过我们的 App Engine 应用程序中的云存储 JSON API 生成可恢复的上传 URL,该应用程序可用于移动设备和网络应用程序。 在 web 应用程序中,使用 XmlHttpRequest 上传带有可恢复上传 url 的文件,我们收到以下错误:

XMLHttpRequest 无法加载 https://www.googleapis.com/upload/storage/v1beta2/b/... 请求的资源上不存在“Access-Control-Allow-Origin”标头。因此不允许访问 Origin 'https://ourapp.appspot.com'。

在 Chrome 开发人员工具中,网络日志显示第一个 OPTIONS 请求,其中包含适当的“Origin”请求标头和“Access-Control-Allow-Origin”响应标头,但如前所述,以下 PUT 请求失败。

我们存储桶上的 cors xml 如下所示:

<?xml version="1.0" encoding="UTF-8"?>
    <CorsConfig>
      <Cors>
        <Origins>
          <Origin>*</Origin>
        </Origins>
        <Methods>
          <Method>PUT</Method>
          <Method>GET</Method>
          <Method>POST</Method>
          <Method>HEAD</Method>
          <Method>DELETE</Method>
          <Method>OPTIONS</Method>
        </Methods>
        <ResponseHeaders>
          <ResponseHeader>*</ResponseHeader>
        </ResponseHeaders>
        <MaxAgeSec>1800</MaxAgeSec>
      </Cors>
    </CorsConfig>

欢迎提出任何建议。

谢谢。

【问题讨论】:

我遇到了同样的问题——CORS 设置正确,并且我对任何其他服务端点都没有问题。你修过吗? @ovangle 不,我们暂时放弃使用上传 URL,我们改用 XML Api。 您是否在 PUT 请求中使用了cors query string parameter? 我实际上遇到了完全相同的问题。 @akgill 我相信 ?cors 查询字符串用于更改与存储桶关联的 cors 标头。不是为了像我们在这里尝试的那样向存储桶发出可恢复的上传请求。 您不需要在存储桶上设置 CORS。只需在请求可恢复上传 url 时正确设置原点即可。 【参考方案1】:

遇到这个问题,发现这是由于来自 App Engine 的初始 POST 请求中缺少“origin”标头。

我的 POST 请求包含内容长度(设置为 0)、x-upload-content-type 和来源,一切正常。

[1]https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload

【讨论】:

我只是想指出,我们有同样的问题,但我们的问题是原始请求在我们的域末尾有一个 /,Google 不接受。所以我们的起源是http://our-domain.com/ 而不是http://our-domain.com。错误是一样的,很难找到。【参考方案2】:

我遇到了同样的问题,解决方法是在初始可恢复请求中添加一个 Header Origin: "https://ourapp.appspot.com"

但是,由于以下变量,某些库(例如 sun.net.www.protocol.http.HttpURLConnection)不允许您更改 Origin 标头:

restrictedHeaders = new String[]"Access-Control-Request-Headers", "Access-Control-Request-Method", "Connection", "Content-Length", "Content-Transfer-Encoding", "Host", "Keep-Alive", "Origin", "Trailer", "Transfer-Encoding", "Upgrade", "Via";

我的解决方法是使用允许更新 Origin 标头的库创建一个新的 HttpRequest。我在我的案例中使用了 Okhttp(作为前 android 开发人员)。

OkHttpClient client = new OkHttpClient();
AppIdentityService appIdentityService = credential.getAppIdentityService();
Collection<String> scopes = credential.getScopes();
String accessToken = appIdentityService.getAccessToken(scopes).getAccessToken();
Request request = new Request.Builder()
        .url("https://www.googleapis.com/upload/storage/v1/b/" + bucket + "/o?name=" + fileName + "&uploadType=resumable")
        .post(RequestBody.create(MediaType.parse(mimeType), new byte[0]))
        .addHeader("X-Upload-Content-Type", mimeType)
        .addHeader("X-Upload-Content-Length", "" + length)
        .addHeader("Origin", "https://ourapp.appspot.com")
        .addHeader("Origin", "*")
        .addHeader("authorization", "Bearer "+accessToken)
        .build();
Response response = client.newCall(request).execute();
return response.header("location");

【讨论】:

【参考方案3】:

这是通过 JSON API 使用可恢复上传的已知问题。我假设用于开始可恢复上传的“原点”和用于上传数据的“原点”在您的情况下是不同的,对吧?

这个问题涉及到两个部分:

1) 使用可恢复上传协议时,始终使用来自第一个(开始上传)请求的“来源”来决定响应中的“访问控制允许来源”标头,即使您使用不同的“源”用于后续请求。

2) GCS 中的 CORS 配置仅适用于 XML API。我认为我们的文档可以使用一些改进来使这一点更清楚,现在它只是在这里提到的(https://developers.google.com/storage/docs/cross-origin#Sending-a-Cross-Domain_Request),如果您单击链接以查看哪些请求 URI 将响应 CORS 配置。 JSON API 会忽略 CORS 配置,并始终允许对请求中的“源”进行跨源访问。

因此,如果您通过 JSON API 使用可恢复上传,它将仅使用第一个请求中的“来源”,并将“访问控制允许来源”标头设置为该来源。因此,如果后续上传请求中的来源发生变化,它们将无法正常工作。

目前您有两种方法可以解决此问题:

1) 对第一个请求和后续请求使用相同的来源。

2) 切换到使用 XML API,并将 CORS 配置设置为 *

【讨论】:

因为这个问题,我们最终切换到 AWS。 您好,我们已经尝试使用 XML API 来配置 cors 并初始化可恢复上传,但我们仍然无法获取 access-control-allow-origin 标头。你有更多关于如何解决这个问题的细节吗?谢谢! P.S 我们按照这个文档来实现续传:cloud.google.com/storage/docs/concepts-techniques#resumable【参考方案4】:

问题不在于上面显示的 COR 文档。如果 xhr 请求是 formdata,则可以使用 xhr 上传文件,如下所述:http://www.html5rocks.com/en/tutorials/file/xhr2/#toc-sending。如果请求不是 FormData,我们会收到“Access-Control-Allow_Origin”错误。

这对我有用:

$("input[type=file]").change(function() 

    var formData = new FormData();

    formData.append("field, ...);
    formData.append("field, ...);
    formData.append("file", filesList[0]);

    var xhr = new XMLHttpRequest();
    xhr.open('POST', "https://my-bucket.storage.googleapis.com/", true);
    xhr.onload = function(e)  
        console.log("File Uploaded!")
    ;

    xhr.send(formData);

在此处查看完整的 node.js 示例:https://github.com/sfarthin/crop-rotate-and-sample-in-browser

【讨论】:

我真的无法让它正常工作,即使 chrome 仍然显示相同的错误,它也会上传文件。存储桶上的文件还包含 webkit 表单边界。 你有例子可以看吗?我会在接下来的几天内将一个工作示例推送到 github。 虽然我没有使用 App Engine。刚刚使用 node.js 签名的网址 @Jkmn 要将 webkit 表单边界保留在云存储桶上的文件之外,请将其作为 blob 而不是 formdata 上传。示例function doUpload(uri, file) var blob = new Blob([file], type: file.type || 'application/octet-stream') return $j.ajax( dataType: 'json', url: uri, data: blob, processData: false, contentType: false, type: 'POST' ); 这是一个将画布转换为图像并上传到 GCS 的示例:github.com/sfarthin/crop-rotate-and-sample-in-browser/blob/… 对我来说效果很好,希望它有用。【参考方案5】:

端点 https://www.googleapis.com 不允许跨域资源共享 (CORS)。这意味着所有浏览器都会阻止从不在源主机 (www.googleapis.com) 上运行的网站发出的请求。

确保您为存储桶配置了 CORS,例如:

<?xml version="1.0" encoding="UTF-8"?>
<CorsConfig>
  <Cors>
    <Origins>
      <Origin>https://ourapp.appspot.com</Origin>
    </Origins>
    <Methods>
      <Method>GET</Method>
      <Method>HEAD</Method>
      <Method>PUT</Method>
    </Methods>
  </Cors>
</CorsConfig> 

如果它仍然不工作集&lt;Origin&gt;*&lt;/Origin&gt;,请尝试使用 curl 并报告结果。

【讨论】:

我很确定它与here 所描述的一样,我看到它可以处理 GET 请求。 检查您是否将 PUT 列为存储桶 CORS 配置中方法的一部分。 我已经允许使用 cors 配置中的每个方法的任何来源,但它没有帮助。

以上是关于没有可恢复上传的“Access-Control-Allow-Origin”标头的主要内容,如果未能解决你的问题,请参考以下文章

将 Tus 可恢复文件上传协议与 Gin-Gonic CORS 问题集成

GCS 可恢复上传速度

Golang谷歌存储可恢复上传HTTP 401

大文件 (> 500MB) 的 HTML5 可恢复和分块上传

sh 可恢复媒体的脚本上传到Twitter

可恢复上传的“临时文件”是不是计入每月存储费? (谷歌云存储)