java&angularjs,惱人的No 'Access-Control-Allow-Origin' 解決方案

由于公司的新項目決定使用java 與angularjs進行開發(fā),前后端分離,因此我需要對前端的請求框架進行搭建。接觸angularjs是在上一個ionic的項目,感覺angularjs的mvc架構非常出色,尤其對大型項目很有好處。
angularjs的請求是通過ajax的,在請求過程中,有一個很麻煩的問題,那就是跨域。在這次的項目中,打算在請求的http header中加入自token進行身份驗證,結果遇到了麻煩。于是現(xiàn)在把解決方案寫下來,希望能給自己留一個記憶,并希望能夠幫助遇到問題的小伙伴。
首先,任何請求都需要在http header中加入token,我了解到了angularjs里的一個很重要的機制:攔截。
可在config中加入:

config(['$httpProvider', function($httpProvider) {  
$httpProvider.interceptors.push('sessionInjector');
$httpProvider.defaults.headers.mbs-common['X-Requested-With'];  }]);

factory中加入sessionInjector如下:

testService.factory('sessionInjector', ['$localStorage','HOST', function($localStorage,HOST) 
{  var sessionInjector = {    
request: 
function(config) {      
config.headers = config.headers || {};     
 if(config.url.indexOf(HOST.URL)>=0) {   
if ($localStorage.u && $localStorage.u.token) {  
            config.headers.token = $localStorage.u.token;       
 }      
}      
return config;   
}  
};  
return sessionInjector;}]);

代碼寫好,跑起來一看,token已經成功加入到http header中,很好!但是請求出錯了!報:No 'Access-Control-Allow-Origin' 錯誤。看到這個報錯,我的第一反映是跨域問題。但是我前一個ionic+angularjs項目在java端已經解決了跨域問題了,而這個新的項目用的框架與上個項目幾乎一樣的,為何還會跨域呢?我感覺自己對跨域的理解不夠徹底,于是又開始漫長的搜索,各種google,stackoverflow。終于找到了跨域的原因,wiki上說得很清楚:https://en.wikipedia.org/wiki/Cross-origin_resource_sharing 。
核心問題在于跨域時會先進行一個OPTIONS請求,如果成功了才會進行GET或POST請求。于是馬上通過chrome查看OPTIONS請求的結果,果然OPTIONS報403錯誤。

Paste_Image.png

看到OPTIONS請求的403錯誤,我就蒙了!怎么回事呢,我明明在java代碼中寫了一個CorsFilter,并且我也加入了跨域的允許代碼:


HttpServletResponse httpResponse = (HttpServletResponse) response;
  HttpServletRequest httpRequest = (HttpServletRequest) request;
  httpResponse.setContentType("text/html;charset=UTF-8");
  httpResponse.setHeader("Access-Control-Allow-Origin",httpRequest.getHeader("Origin"));
  httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
  httpResponse.setHeader("Access-Control-Max-Age", "0");
  httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,authorization,mbs_token");
  httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
  httpResponse.setHeader("XDomainRequestAllowed","1");
         
  chain.doFilter(request, response);

網上說:Access-Control-Allow-Origin不能用"*",而是需要指定請求的域名:httpRequest.getHeader("Origin")

然后我再跑了一次,查看后臺日志,發(fā)現(xiàn)CorsFilter根本就沒有跑!
于是又經過了各種google與stackoverflow,轉眼兩天下來了,還是無果!心里真是有說不出的郁悶!??!

然后,我懷疑是不是tomcat層面攔截了OPTIONS請求,于是看了一下TOMCAT的請求日志,發(fā)現(xiàn)果然有攔截記錄,可是不應該TOMCAT層攔截的呀!于是我做了一個HELLO WORD 發(fā)現(xiàn)跨域是沒問題的,于是放棄這個想法,再繼續(xù)找原因!

最后,我懷疑是不是Web.xml有問題,這個web.xml有部分是直接復制人家配置好的,沒有好好去分析各個節(jié)點,于是我一句一句核對,終于發(fā)現(xiàn)一個關鍵地方:

<security-constraint>
        <web-resource-collection>
                <web-resource-name>SSL</web-resource-name>
                <url-pattern>/*</url-pattern>
                <http-method>PUT</http-method>
                <http-method>DELETE</http-method>
                <http-method>HEAD</http-method>
                <http-method>OPTIONS</http-method>
                <http-method>TRACE</http-method>
        </web-resource-collection>  
        <auth-constraint></auth-constraint>
 </security-constraint>

沒錯,就是這里?。?br> <http-method>OPTIONS</http-method>

我立即把這段文字刪除了,然后跑了一下,奇跡出現(xiàn)了,跨域解決了?。?!當時心里真是無比興奮,從開始解決到完工,我整整花了三天,而且后兩天是雙休!

于是我花時間了解一下這個關鍵的<security-constraint>,網上對于這個節(jié)點的說明比較少,經過google的查閱發(fā)現(xiàn):
web.xml中<security-constraint> 的子元素 <http-method> 是可選的,如果沒有 <http-method> 元素,這表示將禁止所有 HTTP 方法訪問相應的資源。
子元素 <auth-constraint> 需要和 <login-config> 相配合使用,但可以被單獨使用。如果沒有 <auth-constraint> 子元素,這表明任何身份的用戶都可以訪問相應的資源。也就是說,如果 <security-constraint> 中沒有 <auth-constraint> 子元素的話,配置實際上是不起中用的。

<security-constraint> 是java servlet的安全配置,
可參考:http://openhome.cc/Gossip/ServletJSP/DeclarativeSecurityBasic.html

關鍵的一句:如果加入了 <auth-constraint> 子元素,但是其內容為空,這表示所有身份的用戶都被禁止訪問相應的資源。
其實在解決的過程中我也注意到過:<http-method>OPTIONS</http-method>,當時我的理解是,允許這個求請方法!
總結:任何技術疑問都不能馬虎,要徹底理解才行?。?/p>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容