No' Access-Control-Allow-Origin'标题与可恢复上传

时间:2014-04-23 15:16:36

标签: google-app-engine google-api xmlhttprequest google-cloud-storage

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

XMLHttpRequest无法加载https://www.googleapis.com/upload/storage/v1beta2/b/ ... No' Access-Control-Allow-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>

欢迎任何建议。

感谢。

5 个答案:

答案 0 :(得分:6)

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

我的POST请求包含content-length(设置为0),x-upload-content-type和origin,一切都很好。

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

答案 1 :(得分:3)

我遇到了同样的问题,解决方案是在初始可恢复请求中添加标题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"};

我的解决方法是创建一个新的HttpRequest,其中包含一个允许更新Origin标头的库。我在我的案例中使用了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");

答案 2 :(得分:2)

这是使用JSON API使用可恢复上传的已知问题。我假设&#34;起源&#34;用于启动可恢复上传和&#34;来源&#34;用于上传的数据在你的情况下是不同的,对吗?

这个问题涉及两个部分:

1)使用可恢复上传协议时,&#34;来源&#34;从第一个(开始上传)请求始终用于决定&#34; access-control-allow-origin&#34;响应中的标题,即使您使用不同的&#34;来源&#34;对于后续请求。

2)GCS中的CORS配置仅适用于XML API。我认为我们的文档可以使用一些改进来使其更加清晰,现在它只是这里提到的那种(https://developers.google.com/storage/docs/cross-origin#Sending-a-Cross-Domain_Request)如果你点击链接看看哪些请求URI将响应CORS配置。 JSON API忽略CORS配置,并始终允许&#34;来源&#34;在请求中。

因此,如果您使用带有JSON API的可恢复上传,它将只使用&#34;来源&#34;从第一个请求开始,设置&#34; access-control-allow-origin&#34;标题到那个起源。因此,如果原点在后续上传请求中发生变化,则它们将无效。

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

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

2)切换到使用XML API,并将CORS配置设置为&lt; Origin&gt; *&lt; / Origin&gt;。

答案 3 :(得分:1)

问题不在于上面显示的CORs文档。如果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

答案 4 :(得分:-1)

端点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> 

如果仍未设置<Origin>*</Origin>,请尝试使用curl并报告结果。