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