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

由于公司的新项目决定使用java 与angularjs进行开发,前后端分离,因此我需要对前端的请求框架进行搭建。接触angularjs是在上一个ionic的项目,感觉angularjs的mvc架构非常出色,尤其对大型项目很有好处。
angularjs的请求是通过ajax的,在请求过程中,有一个很麻烦的问题,那就是跨域。在这次的项目中,打算在请求的http header中加入自token进行身份验证,结果遇到了麻烦。于是现在把解决方案写下来,希望能给自己留一个记忆,并希望能够帮助遇到问题的小伙伴。
首先,任何请求都需要在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")

然后我再跑了一次,查看后台日志,发现CorsFilter根本就没有跑!
于是又经过了各种google与stackoverflow,转眼两天下来了,还是无果!心里真是有说不出的郁闷!!!

然后,我怀疑是不是tomcat层面拦截了OPTIONS请求,于是看了一下TOMCAT的请求日志,发现果然有拦截记录,可是不应该TOMCAT层拦截的呀!于是我做了一个HELLO WORD 发现跨域是没问题的,于是放弃这个想法,再继续找原因!

最后,我怀疑是不是Web.xml有问题,这个web.xml有部分是直接复制人家配置好的,没有好好去分析各个节点,于是我一句一句核对,终于发现一个关键地方:

<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>

没错,就是这里!:
<http-method>OPTIONS</http-method>

我立即把这段文字删除了,然后跑了一下,奇迹出现了,跨域解决了!!!当时心里真是无比兴奋,从开始解决到完工,我整整花了三天,而且后两天是双休!

于是我花时间了解一下这个关键的<security-constraint>,网上对于这个节点的说明比较少,经过google的查阅发现:
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>,当时我的理解是,允许这个求请方法!
总结:任何技术疑问都不能马虎,要彻底理解才行啊!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容