No 'Access-Control-Allow-Origin' header wi

2019-01-22 13:18发布

We are generating resumable upload url through the cloud storage JSON API from our App Engine application which are used on mobile as well as a web app. In the web app, using XmlHttpRequest to upload a file with the resumable upload url we get the following error :

XMLHttpRequest cannot load https://www.googleapis.com/upload/storage/v1beta2/b/... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://ourapp.appspot.com' is therefore not allowed access.

In Chrome developer tools, the network log show a first OPTIONS request with the appropriate "Origin" request header and "Access-Control-Allow-Origin" response header but the following PUT request fails as mentioned.

The cors xml on our bucket looks like this:

<?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>

Any suggestions are welcome.

Thanks.

5条回答
来,给爷笑一个
2楼-- · 2019-01-22 13:39

The problem is not with the CORs document shown above. One can upload files with xhr if the xhr request is formdata as described here: http://www.html5rocks.com/en/tutorials/file/xhr2/#toc-sending . If the request is not FormData we get the 'Access-Control-Allow_Origin' error.

This works for me:

$("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);
}

See a full working node.js example here: https://github.com/sfarthin/crop-rotate-and-sample-in-browser

查看更多
祖国的老花朵
3楼-- · 2019-01-22 13:40

Ran into this problem and discovered that it was due to a missing "origin" header in the initial POST request coming from App Engine.

My POST request contains content-length (set to 0), x-upload-content-type, and origin and all is well.

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

查看更多
兄弟一词,经得起流年.
4楼-- · 2019-01-22 13:42

I had the same problem, and the solution was to add a Header Origin: "https://ourapp.appspot.com" to the initial resumable request.

However, some librares, for example sun.net.www.protocol.http.HttpURLConnection doesn't allow you to change the Origin header because of the following variable :

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"};

My workaround was to create a new HttpRequest with a library that allows to update the Origin header. I used Okhttp in my case (as former Android developper).

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");
查看更多
Summer. ? 凉城
5楼-- · 2019-01-22 13:44

This is a known problem with using resumable upload with the JSON API. I assume the "origin" used to start the resumable upload and the "origin" used to upload data are different in your case, right?

There are two parts involved in this issue:

1) When using resumable upload protocol, the "origin" from the first (start upload) request is always used to decide the "access-control-allow-origin" header in the response, even if you use a different "origin" for subsequent requests.

2) The CORS config in GCS only works for the XML API. I think our documentation could use some improvement to make this more clear, right now it's only kind of mentioned here (https://developers.google.com/storage/docs/cross-origin#Sending-a-Cross-Domain_Request) if you click through the link to see what request URIs will be responsive to the CORS config. The JSON API ignores the CORS config, and will always allow cross-origin access for the "origin" in the request.

So if you use resumable upload with JSON API, it will only use the "origin" from the first request, and set "access-control-allow-origin" header to that origin. Thus, if the origin changes in subsequent upload requests, they will not work.

Currently you have two ways to work around this issue:

1) Use the same origin for the first and subsequent requests.

2) Switch to use the XML API, and set the CORS config to <Origin>*</Origin>.

查看更多
Ridiculous、
6楼-- · 2019-01-22 13:52

The endpoint https://www.googleapis.com is not allowing Cross-Origin Resource Sharing (CORS). That means all browsers will prevent requests when issued from a website which is not running on the origin host (www.googleapis.com).

Make sure you configured CORS for your bucket e.g.:

<?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> 

If it is still not working set <Origin>*</Origin>, try with curl and report the outcome.

查看更多
登录 后发表回答