Part1:跨域問題剖析
1.跨域問題出現的原因
跨域問題:一般是A瀏覽器請求了非同源,例如B服務器的URI時,所導致的問題。
2.瀏覽器為什么要限制同源?
同源目的:是為了保證用戶信息的安全,防止惡意的網站竊取數據。eg:比如銀行用戶的cookie信息。
3.同源的3個指標
所謂"同源"指的是"三個相同"。
1>協議相同
2>域名相同
3>端口相同
4.非同源受限制的3個行為
1>Cookie、LocalStorage 和 IndexDB 無法讀取。
2>DOM 無法獲得。
3>AJAX 請求不能發送。
其中第3條開發時碰到的最多。
5.解決非同源AJAX請求報錯
同源政策規定,AJAX請求只能發給同源的網址,否則就報錯。
除了架設服務器代理(瀏覽器請求同源服務器,再由后者請求外部服務),有三種方法規避這個限制。
1>JSONP
2>WebSocket
3>CORS
Part2:SpringMVC通過CORS協議解決跨域問題
1.CORS介紹
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務器,發出XMLHttpRequest
請求,從而克服了AJAX只能同源使用的限制。
CORS需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。
整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對于開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。
因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。
2.方法1:Spring-自定義Fliter:在response中添加CORS響應頭(Access-Control-Allow*)
3.方法2:SpringMVC4提供了非常方便的實現跨域的方法。在requestMapping中使用注解。
@CrossOrigin(origins = “http://kbiao.me”)
Part3:自己實際測試
1.跨域情境模擬:
前端index.html在電腦A上,頁面中有個submit按鈕來發送ajax請求。且請求url定位到后臺對應Handler:http://192.168.0.218:8080/InsureService/crossOrigin/detail
;
后臺服務器在電腦B上,Spring項目中書寫一個測試controller接收HTTP請求。代碼如下:
@Controller
@RequestMapping("/crossOrigin")
public class CrossOriginController {
@RequestMapping(value = "/detail", method = RequestMethod.POST)
@ResponseBody
public String savePayAndTrip(HttpServletRequest request){
String reqStr = HttpUtils.getReqeustData(request);
System.out.println("請求報文:" + reqStr);
return reqStr;
}//end method
}
2.跨域問題重現:
在上述情境準備下,前端請求的源
Origin為null
,后端源
Origin為http://192.168.0.218:8080
。兩者不同源,所以前端的ajax請求,無法到達后臺的Handler,也就不能被處理。(前端源為null,因為在本地電腦A直接在瀏覽器加載html文件發起請求導致。)
谷歌瀏覽器測試,截圖:
1.跨域錯誤前端信息
3.跨域問題解決:使用Spring的@CrossOrigin注解
@CrossOrigin注解,可以放在Controller類上,允許Controller中所有方法可被某個源
跨域請求;也可以放在Controller類中某一個方法上,指明當前方法可以被哪些源
跨域請求。
示例代碼中:將@CrossOrigin加在Controller類上:
@Controller
@RequestMapping("/crossOrigin")
@CrossOrigin(origins = "*") //跨域核心配置
public class CrossOriginController {
@RequestMapping(value = "/detail", method = RequestMethod.POST)
@ResponseBody
public String savePayAndTrip(HttpServletRequest request){
String reqStr = HttpUtils.getReqeustData(request);
System.out.println("請求報文:" + reqStr);
return reqStr;
}//end method
}
分析:
瀏覽器針對'非簡單請求'的跨域,會根據CORS協議在底層會發起兩次request:
(1)使用HTTP協議OPTIONS方法,發起的預檢請求
(preflight request);
(2)發起正常請求
谷歌瀏覽器測試結果:
1.OPTIONS預檢請求
參考文章(干貨滿滿)
1.阮一峰---瀏覽器同源政策及其規避方法
2.阮一峰---跨域資源共享 CORS 詳解
3.Spring MVC通過CROS協議解決跨域問題