????工作中粥鞋,與前端聯(lián)調(diào)時經(jīng)常會碰到跨域問題。指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本裕膀。它是由瀏覽器的同源策略造成的员串,是瀏覽器施加的安全限制。所以與客戶端交互的時候就不會碰到這個問題昼扛〈缙耄跨域問題,有多種解決方式抄谐,比如說前端進行代理渺鹦,本文主要結合自己的實際開發(fā),從服務器端的角度解決這個問題的蛹含。
????對于非簡單請求(具體可以這篇文章毅厚,跨域資源共享),在正式訪問請求前浦箱,瀏覽器會發(fā)送一個預檢請求吸耿,就是option請求祠锣。針對option請求,必須保證如下2點咽安,后面的正式請求才會訪問:第一伴网,要能返回Access-Control-Allow-Origin 等字段,告訴瀏覽器你這個請求域名我服務端是可以支持的妆棒。第二澡腾,對于跨域的預檢請求,要能返回成功糕珊。
ht我們一般使用servlet來處理http請求动分,開發(fā)中一般是子類繼承httpservlet。option請求會到httpservlet的doOptions(HttpServletRequest req, HttpServletResponse resp)方法進行處理放接。? ? ?
我們可以看到httpservlet的默認doOptions方法中刺啦,請求頭中只加了一個"Allow",不滿足我們說的第一個條件,option請求過不去纠脾,后面的請求也無法訪問玛瘸。所以我們要么子類重寫doOptions方法,在方法里面解決苟蹈,要么在進入這個方法前就解決跨域問題糊渊。接下來我會講述2種不同的方式來解決這個問題。
1.基于java體系過濾器處理
我們可以使用過濾器fiter,http請求會在到達servlet的service(ServletRequest req, ServletResponse res)方法前被攔截慧脱。我們可以在doFilter方法中進行處理渺绒。
注意:option請求,不會攜帶參數(shù)菱鸥,和cookie信息宗兼,一般直接攔截掉,不進入后面的邏輯處理氮采。 這種方式基于java本身體系殷绍,容易理解,也很方便鹊漠,推薦使用這種模式主到。
2.基于spring體系的攔截器處理
在項目中,我們一般使用springmvc躯概,可以使用攔截器Interceptor來處理跨域問題登钥。? ? ? ? ? ? ? ? ? ? springmvc只要靠DispatcherServlet這個類來處理http請求的。
請求進到DispaterServlet的doOptions方法中娶靡,然后調(diào)用processRequest(request, response)方法處理請求邏輯牧牢,調(diào)用鏈比較長,最終會進入到doDispatcher方法。
這個方法處理邏輯也比較復雜结执,我們主要關注幾點度陆,找到請求對應的HandlerExecutionChain,這個mappedHandler包括對應的處理器和interceptor集合献幔,然后找到對應的適配器,然后執(zhí)行攔截器的prehandle()方法趾诗,我們需要在攔截器的prehandle()處理下跨域即可蜡感。
同樣針對跨域請求,需要攔截掉恃泪,因為option不帶參數(shù)郑兴,會對后面的業(yè)務邏輯有影像。
這種基于spring體系的攔截器處理跨域問題贝乎,需要對spring的源碼有一定的理解情连,不然會出現(xiàn)問題,下面講一下用這種方法踩過的坑览效。
1.之前有一個項目却舀,我用攔截器這種方式怎么都不能解決跨域問題,百思不得其解锤灿,有的項目可以挽拔,有的項目用攔截器就不行,遂用過濾器的方法解決但校。后面閱讀了一下源碼才發(fā)現(xiàn)是spring的版本問題導致的螃诅。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 那個項目的spring是3.8版本的,之前的doOption()方法長這樣状囱。
我們可以看到术裸,只有this.dispatchOptionsRequest為true的時候,才會進入到processRequest(request, response)方法亭枷,后面進行攔截器處理袭艺。但是this.dispatchOptionsReques默認為false,如果你不配置的話奶栖,后面的攔截器永遠不會執(zhí)行匹表。會進入父類的doOptions()方法,前面講過宣鄙,原始的doOptions()方法無法處理跨域問題袍镀。如果要使用的話,需要到web.xml文件中配置一下
spring4.0的版本后面優(yōu)化這段邏輯冻晤,可以看下上面的那個截圖苇羡,是基于spring4.2的,默認option請求鼻弧,直接進入后面的邏輯设江。
2.前面講過锦茁,doDisPatch()方法會去找對應的handler和攔截器,一般是通過requestmapping來查找叉存,默認是根據(jù)url來查找
這種情況下码俩,會根據(jù)url,method聯(lián)合查找處理器,因為我們這個請求是option請求歼捏,會報一個405異常稿存,后面的請求會攔截掉了。解決辦法瞳秽,要么去掉method瓣履,在實際開發(fā)中,這個個人感覺沒多大用练俐,或者在method后面加一個OPTIONS袖迎。