没有可恢复上传的“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>
如果它仍然不工作集<Origin>*</Origin>
,请尝试使用 curl 并报告结果。
【讨论】:
我很确定它与here 所描述的一样,我看到它可以处理 GET 请求。 检查您是否将PUT
列为存储桶 CORS 配置中方法的一部分。
我已经允许使用 cors 配置中的每个方法的任何来源,但它没有帮助。以上是关于没有可恢复上传的“Access-Control-Allow-Origin”标头的主要内容,如果未能解决你的问题,请参考以下文章
将 Tus 可恢复文件上传协议与 Gin-Gonic CORS 问题集成