谷歌应用引擎 - 没有带有可断点续传的"访问控制允许来源"标头



我们正在通过云存储JSON API从我们的应用引擎应用程序生成可恢复的上传url,该应用程序用于移动和web应用程序。在web应用程序中,使用XmlHttpRequest上传具有可恢复上传url的文件,我们会收到以下错误:

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

在Chrome开发工具中,网络日志显示第一个OPTIONS请求,其中包含相应的"Origin"请求标头和"Access Control Allow Origin"响应标头,但以下PUT请求失败,如上所述。

我们bucket上的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>

欢迎提出任何建议。

谢谢。

遇到此问题,发现这是由于来自应用程序引擎的初始POST请求中缺少"origin"标头所致。

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

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

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

我的解决方法是创建一个新的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");

这是使用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配置,并始终允许对请求中的"origin"进行跨origin访问。

因此,如果您使用JSON API的可恢复上载,它将只使用第一个请求中的"origin",并将"access-control-allow-origin"头设置为该origin。因此,如果后续上传请求中的来源发生更改,它们将无法工作。

目前你有两种方法来解决这个问题:

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

2) 切换为使用XML API,并将CORS配置设置为<原点><起源>。

问题不在于上面显示的COR文档。如果xhr请求是表单数据,则可以使用xhr上传文件,如下所述:http://www.html5rocks.com/en/tutorials/file/xhr2/#toc-发送。如果请求不是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

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

确保您为您的bucket配置了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并报告结果。

最新更新