情況描述:
最近在部署一個前后端分離的項目出現了跨域問題*,
項目使用jwt進行鑒權,需要前端請求發起攜帶TOKEN的請求*,請求所帶的token無法成功發送給后端,
使用跨域后出現了兼容性問題:Chrome、Firefox瀏覽器正常,而IE還是報跨域錯誤
一、跨域問題在項目中可以使用CORS解決
方式一
@CrossOrigin
在每個controller類加上
方式二 直接在spring-mvc中加入配置
<!-- 接口跨域配置 -->
<mvc:cors>
<mvc:mapping path="/**"
allowed-origins="*"
allowed-methods="POST, GET, OPTIONS, DELETE, PUT"
allowed-headers="Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
allow-credentials="true" />
</mvc:cors>
方式三 可以在interceptor中向response增加header
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "86400");
response.setHeader("Access-Control-Allow-Headers", "Authorization,Overwrite, Destination, Content-Type, Depth, User-Agent, Translate, Range, Content-Range, Timeout, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Location, Lock-Token, If");
上面三種方式對一般的簡單跨域請求有效,可以滿足大部分需要。但遇到非簡單跨域請求的情況,就會出現問題,需要做一下調整。
二、復雜請求下需要對options預檢請求進行處理
前后端分離的項目中,瀏覽器請求中經常會出現非簡單跨域請求,這將會發送請求2次,第一條由瀏覽器發起請求為options的預檢請求,再根據服務器的返回內容由瀏覽器判斷服務器是否允許此次請求,第二條才是method中的get,post或者put等,並且第一條無任何數據返回,第二條才正常返回數據。
所以我們會遇到:我們處理token的攔截器(非簡單情況,在header的authorization攜帶了token進行鑒權),在接收到option的時候將這個預檢請求當成正常的請求,而options請求時無法在header攜帶token的,因此后端將會把第一個請求打回,導致第二個請求無法正常發起。
非簡單情況(含以下之一):
- 請求方式:PUT、DELETE
- 自定義頭部字段
- 發送json格式數據
- 正式通信之前,瀏覽器會先發送OPTION請求,進行預檢,這一次的請求稱為“預檢請求”
- 服務器成功響應預檢請求后,才會發送真正的請求,並且攜帶真實數據
解決方式 在后端中對options請求進行直接給通過(只要返回200、204,瀏覽器即判斷服務器允許請求)
增加一個CorsInterceptor
public class CorsInterceptor implements HandlerInterceptor { //使用了方式三、進行CORS配置 response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "86400"); response.setHeader("Access-Control-Allow-Headers", "Authorization,Overwrite, Destination, Content-Type, Depth, User-Agent, Translate, Range, Content-Range, Timeout, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Location, Lock-Token, If"); if(HttpMethod.OPTIONS.toString().equals(httpServletRequest.getMethod())){ response.setStatus(HttpStatus.NO_CONTENT.value()); System.out.println("是options請求、跳過"); return false; } return true; } }
在spring-mvc中加載這個CorsInterceptor,置於token處理之前
<mvc:interceptor> <mvc:mapping path="/**" /> <bean class="cn.gdyvc.interceptor.CorsInterceptor" /> </mvc:interceptor>
三、CORS瀏覽器兼容問題
最后部署完成,但是Chrome、Firefox瀏覽器正常,而IE還是報跨域錯誤,遇到了Internet Explorer與Access-Control-Allow-Methods的CORS問題
剛開始跨域配置根據網上的的設置將Access-Control-Allow-Headers對應設置為“*”,而Ie的是不能夠響應*的,需要將header的各列單獨列出來
參考鏈接:
https://www.jianshu.com/p/5c637bfcc674
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers