2014-02-15 52 views
24

我是新來與跨源資源共享工作,並試圖讓我的web應用程序對CORS請求作出迴應。我的webapp是一個運行在Tomcat 7.0.42上的Spring 3.2應用程序。困惑如何處理CORS OPTIONS預檢要求

在我的webapp的web.xml,我已經啓用了Tomcat的CORS過濾器:

<!-- Enable CORS (cross origin resource sharing) --> 
<!-- http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter --> 
<filter> 
    <filter-name>CorsFilter</filter-name> 
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>CorsFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

我的客戶(與AngularJS 1.2.12寫的)正試圖訪問一個REST端點使用基本身份驗證功能。當它使得它的GET請求,瀏覽器首先預檢請求,但是從服務器接收403禁止響應:

Request URL:http://dev.mydomain.com/joeV2/users/listUsers 
Request Method:OPTIONS 
Status Code:403 Forbidden 
Request Headers: 
    OPTIONS /joeV2/users/listUsers HTTP/1.1 
    Host: dev.mydomain.com 
    Connection: keep-alive 
    Cache-Control: max-age=0 
    Access-Control-Request-Method: GET 
    Origin: http://localhost:8000 
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36 
    Access-Control-Request-Headers: accept, authorization 
    Accept: */* 
    Referer: http://localhost:8000/ 
    Accept-Encoding: gzip,deflate,sdch 
    Accept-Language: en-US,en;q=0.8 
Response Headers: 
    HTTP/1.1 403 Forbidden 
    Date: Sat, 15 Feb 2014 02:16:05 GMT 
    Content-Type: text/plain; charset=UTF-8 
    Content-Length: 0 
    Connection: close 

我不完全知道如何着手。 The Tomcat filter, by default,接受OPTIONS頭來訪問資源。

的問題,我認爲,這是我的資源(請求URL)http://dev.mydomain.com/joeV2/users/listUsers被配置爲只接受GET方法:

@RequestMapping(method=RequestMethod.GET, value="listUsers", produces=MediaType.APPLICATION_JSON_VALUE) 
@ResponseBody 
public List<User> list(){ 
    return userService.findAllUsers(); 
} 

這是否意味着我必須作出這樣的方法/端點接受OPTIONS方法好?如果是這樣,這是否意味着我必須明確地讓每個REST端點接受OPTIONS方法?除了混亂的代碼之外,我很困惑這將如何工作。從我所瞭解的OPTIONS預檢中,瀏覽器可以驗證瀏覽器是否可以訪問指定的資源。我的理解是,我的控制器方法甚至不應該在預檢期間被調用。因此,將OPTIONS指定爲可接受的方法將會適得其反。

應的Tomcat是響應OPTIONS直接要求,甚至沒有訪問我的代碼?如果是這樣,我的配置中是否有缺少的東西?

回答

40

我坐了下來,並通過org.apache.catalina.filters.CorsFilter調試找出原因的請求被禁止的。希望這可以幫助未來的人。

根據該W3 CORS Spec Section 6.2 Preflight Requests,預檢必須如果提交任何頭不匹配所允許的標題拒絕該請求。

default configuration for the CorsFiltercors.allowed.headers(與您的一樣)不包括與請求一起提交的Authorization標頭。

我更新了cors.allowed.headers過濾器設置,接受authorization標題,並且預檢請求現已成功。

<filter> 
    <filter-name>CorsFilter</filter-name> 
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> 
    <init-param> 
     <param-name>cors.allowed.headers</param-name> 
     <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value> 
    </init-param>  
</filter> 

當然,我不知道爲什麼authorization頭默認情況下不被CORS過濾允許的。

+0

好奇,如果你嘗試了我的答案第一位?我使用的是Apache,並且不需要設置'authorization'標頭。檢查Access Control-Request-Headers設置的'httpProvider'設置。您的獲取請求正在等待授權頭接受。使用'$ httpProvider.defaults.headers.common = {}''配置你的'$ httpProvider'應該重置它。 (這就是爲什麼我想知道你是否嘗試過)。我更喜歡將我可以用作安全規則的最適用的Tomcat設置。通過CORS設置進行通用可以爲您解決問題。 –

+0

@BrianVanderbusch不 - 我實際上沒有得到您的迴應,直到我完成調試TC並找出問題出在哪裏。我也會用你提出的解決方案進行測試,儘管我並不完全確定考慮到授權標題是什麼引發了這個問題,這是否重要。在我的情況下,我需要授權頭,因爲它是一個REST端點,我需要爲每個請求進行認證。 –

+1

@Eric這裏有點晚,但'授權'標題實際上不應該伴隨預檢請求,根據規範[這裏](http://www.w3.org/TR/cors/#cross-origin) - 請求與 - 預檢-0)。預檢的要點純粹是爲了確保方法(您的情況下爲GET)和標頭有效發送到服務器。沒有授權/認證 –

4

我想嘗試的第一件事就是設置你的共同標題爲您HTTP請求的角度調度,通過模塊上插入下面的配置塊:

.config(function($httpProvider){ 
    $httpProvider.defaults.headers.common = {}; 
    $httpProvider.defaults.headers.post = {}; 
    $httpProvider.defaults.headers.put = {}; 
    $httpProvider.defaults.headers.patch = {}; 
}) 

這些都應該是在默認情況下已經設置,但我發現我經常必須在我的配置中手動執行此操作,因爲來自其他模塊的任何重寫或內部角引導過程。

您的CORS過濾器應該在服務器端足以允許這些類型的請求,但有時您需要指定請求方法以及您的來源以及接受的內容類型。 tomcat文檔有這個高級塊,它解決了這些問題。

<filter> 
    <filter-name>CorsFilter</filter-name> 
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> 
    <init-param> 
    <param-name>cors.allowed.origins</param-name> 
    <param-value>*</param-value> 
    </init-param> 
    <init-param> 
    <param-name>cors.allowed.methods</param-name> 
    <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value> 
    </init-param> 
    <init-param> 
    <param-name>cors.allowed.headers</param-name> 
    <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value> 
    </init-param> 
    <init-param> 
    <param-name>cors.exposed.headers</param-name> 
    <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value> 
    </init-param> 
    <init-param> 
    <param-name>cors.support.credentials</param-name> 
    <param-value>true</param-value> 
    </init-param> 
    <init-param> 
    <param-name>cors.preflight.maxage</param-name> 
    <param-value>10</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>CorsFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

如果第一個它自己不工作,儘量提高你的過濾器,尤其是:

<init-param> 
     <param-name>cors.allowed.methods</param-name> 
     <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value> 
     </init-param> 
     <init-param> 
     <param-name>cors.allowed.headers</param-name> 
     <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value> 
     </init-param> 
     <init-param> 
     <param-name>cors.exposed.headers</param-name> 
     <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value> 
     </init-param> 
+0

這幫了我。謝謝! –