3

我有一款Google App Engine应用程序,当一切正在一台主机上运行时,它可以在生产环境中正常运行,并且大多数情况下可以在Web应用程序在单独的主机上运行时运行。所有查询到/从服务器(GET,POST,PUT,DELETE)的行为都如预期。这告诉我,我已经在整个系统中正确配置了所有的CORS(我几周前参加了这场战斗,并且全部解决了这个问题)。XMLHttpRequest错误

我无法做的唯一工作就是文件上传。我正在使用django,djangoappengine,django-cors-headersfiletransfers,而最终的结果是,从远程服务器运行时无法上载文件,但其他所有内容都正常工作。在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服务的API端口8080
  • grunt serve端口服务的客户端应用程序9000个
  • CORS设置:
    • 发展:CORS_ORIGIN_ALLOW_ALL = True
    • 生产:CORS_ORIGIN_WHITELIST = [ '(app.domain.com for my app)' ]

在生产中,我相信修复将是configure CORS on my bucket,但我还不能肯定。但是,我有没有的想法如何配置本地开发服务器,以便我可以在部署之前测试整个数据流。

这里是一个的最终失败(应用程序正在使用AngularJS)JavaScript的:

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来组装我的表单,但我从来没有找到过这样做的方法。

---更新,增加了---

作为澄清一点,这是造成这个错误并不直接我的应用程序内的端点,它是由单独的谷歌服务处理的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的一切是(似乎)我的控制范围之外,包括添加标题。

+0

当我说“在同一主机上运行时,该工作”,我要澄清。由于之前的应用程序并未使用AngularJS,因此发布和响应处理的细节稍有不同;有可能我在这里也做了其他一些稍微错误的事情,但在解决CORS问题之前,我无法解决任何问题。 – seawolf

+0

'url'的处理程序是否发送CORS头文件?这里是你需要做的工作的一个例子:https://github.com/GoogleCloudPlatform/appengine-python-blobstore-cors-upload/blob/master/main.py –

+0

为什么不直接POST文件formData到端点,而不是先获取然后发布?像'var input = $('selector'); var data = new FormData(); data.append('name',input.name); data.append('type',input.type); data.append(input.name,input.files [0]); $阿贾克斯({ URL: 'URL', 类型: 'POST', 过程数据:假的, 的contentType:假的,//用于jqXHR 数据重要:数据} .done()' – dliu

回答

1

一种方法是设置HTTP标头为特定的URL在app.yaml

因此,例如:

handlers: 
- url: /_ah/upload.... 
    ... 
    http_headers: 
    Access-Control-Allow-Origin: http://localhost:9000 
+3

此特定设置仅适用于静态文件处理程序(请参见[静态文件处理程序](https://cloud.google.com/appengine/docs/python/config/appconfig))。据我所知,几天前我第一次发现时,我非常有希望,但在这种情况下,这并没有帮助。 – seawolf

0

你的HTTP处理程序必须具有用于发送CORS标头到浏览器选项的方法。

例如; Chrome始终会在发出PUT请求以检查CORS标头之前向相同的URL发送OPTIONS请求。如果浏览器无法获得OPTIONS请求的响应,则cors将失败。

检查这个应用程序引擎webapp2的例子。

class BaseRestHandler(webapp2.RequestHandler): 
    def options(self, *args, **kwargs): 
     self.response.headers['Access-Control-Allow-Origin'] = '*' 
     self.response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept' 
     self.response.headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE' 

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

+1

这已经完成,并适用于所有其他端点。它是我的代码库之外的单个端点(由App Engine环境中的外部服务处理)不提供这些标头。 – seawolf