我有一个 Google App Engine 应用程序,当一切都在一台主机上运行时,它在生产环境中运行良好,而当网络应用程序在单独的主机上运行时,它主要运行良好。与服务器 ( GET
, POST
, PUT
, DELETE
) 之间的所有查询都按预期运行。这向我表明我在整个系统中正确配置了所有 CORS(我在几周前进行了那场战斗并且一切都解决了)。
我唯一不能做的是文件上传。我正在使用django
, djangoappengine
,django-cors-headers
和filetransfers
, 一切的最终结果是从远程服务器运行时我无法上传文件,但其他一切工作正常。在 Chrome 的 JavaScript 控制台中,我看到以下错误:
XMLHttpRequest cannot load http://localhost:8080/_ah/upload/ahl...<truncated>.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:9000' is therefore not allowed
access. The response had HTTP status code 405.
这显然是一个 CORS 错误,所以我大致知道需要发生什么。除了我不知道如何对我的配置进行必要的更改来克服这个问题。
这是我的整体设置:
dev_appserver.py
在端口 8080 上提供 APIgrunt serve
在端口 9000 上为客户端应用程序提供服务- CORS 设置:
- 发展:
CORS_ORIGIN_ALLOW_ALL = True
- 生产:
CORS_ORIGIN_WHITELIST = [ '(app.domain.com for my app)' ]
- 发展:
在生产中,我相信解决方法是在我的 bucket 上配置 CORS,但我并不积极。但是,我不知道如何为此配置本地开发服务器,以便在部署之前测试整体数据流。
这是最终失败的 JavaScript(应用程序正在使用AngularJS
):
var form = angular.element('#media-form');
var data = new FormData(form);
// have the API return a URL using prepare_upload in
// filetransfers module to upload to:
var uploadActionUrl = https://api.domain.com/upload_url/';
$http.get(uploadActionUrl)
.then(function(response) {
// I get here with no problem
$http.post(response.data.action, formData)
.then(function(response) {
console.log('got:', response);
}, function(error) {
console.log('upload error:', error); // <- this is where I end up
});
}, function(error) {
console.log('get upload URL error:', error);
});
同样,当从同一主机运行时,非常类似于此的代码可以正常运行(因此 API 本身可以正常运行),并且(重要的是)所有 HTTP 方法都可以在所有端点上运行,而不是上传我的文件,因此 CORS 本身已正确设置为与 App Engine 的交互。只有文件上传部分不起作用。
我突然想到,也许修复包括使用 JSON 而不是组装我的上传表单FormData
,但我过去从未找到这样做的方法。
--- 更新添加 ---
作为澄清点,导致此错误的端点并不直接在我的应用程序中,它位于由单独的 Google 服务处理的 URL 处。给我网址的代码是:
from google.appengine.ext.blobstore import create_upload_url
def prepare_upload(request, url, **kwargs):
return create_upload_url(
url,
gs_bucket_name = settings.GOOGLE_CLOUD_STORAGE_BUCKET
), {}
我返回的 URL 的格式为/_ah/upload/<one-time key>
,并且在该 URL 上发生的所有事情(似乎)都超出了我的控制范围,包括添加标题。