2012-11-10 35 views
4

我建立一個基於Backbone.js的應用程序,並面臨一個奇怪的問題。爲什麼一個OPTIONS請求失敗,當答案跟進請求是204?

在某一點的應用程序請求集合資源和Chrome內(和Safari)我得到這樣一個錯誤:

XMLHttpRequest cannot load http://api.mydomain.net/v1/foos/00000d/bars/000014/boots Origin http://localhost:3501 is not allowed by Access-Control-Allow-Origin. 

好吧,CORS的問題,我想和我的指責API。然後通過捲曲請求這個非常的資源:

curl -i -H'Accept: application/json' -H'X-Auth-Token: pAWp5hrCmXA83GgFzgHC' -XOPTIONS 'http://api.mydomain.net/v1/foos/00000d/bars/000014/boots' 
HTTP/1.1 200 OK 
Status: 200 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Methods: POST, GET, OPTIONS 
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Auth-Token 
Content-Length: 0 

看起來不錯,現在GET:

curl -i -H'Accept: application/json' -H'X-Auth-Token: pAWp5hrCmXA83GgFzgHC' -XGET 'http://api.mydomain.net/v1/foos/00000d/bars/000014/boots' 
HTTP/1.1 204 No Content 
Status: 204 
Cache-Control: no-cache 
Content-Length: 0 
Content-Type: text/plain 

如果我要求靴子的集合,包含至少一個對象,一切工作正常。我的服務器的CORS標題響應arr完全正常,我認爲。那麼爲什麼瀏覽器會報告一個跨源資源問題?

是否由於我的204條回覆中的內容類型text/plain

預檢(OPTIONS)在開發工具的要求: OPTIONS

中止響應的請求頭: GET

+0

確保問題確實是由CORS引起的,而不是某些服務器端故障。使用'--disable-web-security'標誌運行Chrome並仔細檢查服務器的響應。 –

+0

不幸的是,當使用該命令行開關啓動時,OSX上的最新Chrome(非dev)會死亡。 – GeorgieF

+0

檢查您的服務器的錯誤日誌。 –

回答

7

你必須還包括在第二請求的響應頭的Access-Control-Allow-Origin。這不是客戶端問題,而是後端問題。

此行爲是根據CORS specification,在以下的說明(section 7.1.5 "Cross-Origin Request with Preflight")施加:

  1. 預檢請求(details略)
  2. 「設置cross-origin request status以預檢完成」。
  3. 「這是實際的請求。(...)在發出請求時遵守下面的請求規則。」
    • 如果響應具有301的HTTP狀態代碼302,303,或307不適用
    • 如果最終用戶取消請求不適用
    • 如果有網絡錯誤不適用
    • 否則
      執行resource sharing check 。如果它返回失敗,則應用高速緩存和網絡錯誤步驟。

請求已失敗在resource sharing check的第一步驟:

  1. 如果響應包括零個或一個以上的Access-Control-Allow-Origin標頭值,返回失敗並終止本算法。

我提供說明您的問題一個簡單的例子的NodeJS。
您當前後端的行爲,如:

require('http').createServer(function(request, response) { 
    if (request.method == 'OPTIONS') { // Handle preflight 
     response.writeHead(200, { 
      "Access-Control-Allow-Origin": "*", 
      "Access-Control-Allow-Headers": "X-Foo" 
     }); 
    } else {       // Handle actual requests 
     response.writeHead(204, { 
      //"Access-Control-Allow-Origin": "*" 
     }); 
    } 
    response.end(); 
}).listen(12345); 

現在,發出請求,體驗失敗

var x = new XMLHttpRequest; 
x.open('GET', 'http://localhost:12345'); 
x.setRequestHeader('X-Foo','header to trigger preflight'); 
x.send(); 

回到我提供的代碼,並能夠在響應Access-Control-Allow-Origin頭,並再次測試。您的請求現在會成功。

+0

204根本沒有包括CORS頭文件... thx所有的努力和偉大的答案! – GeorgieF