我们正在通过云存储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并报告结果。