Part1:跨域問題剖析
1.跨域問題出現(xiàn)的原因
跨域問題:一般是A瀏覽器請求了非同源牵寺,例如B服務(wù)器的URI時钉汗,所導(dǎo)致的問題。
2.瀏覽器為什么要限制同源闷尿?
同源目的:是為了保證用戶信息的安全葫慎,防止惡意的網(wǎng)站竊取數(shù)據(jù)衔彻。eg:比如銀行用戶的cookie信息。
3.同源的3個指標(biāo)
所謂"同源"指的是"三個相同"偷办。
1>協(xié)議相同
2>域名相同
3>端口相同
4.非同源受限制的3個行為
1>Cookie米奸、LocalStorage 和 IndexDB 無法讀取。
2>DOM 無法獲得爽篷。
3>AJAX 請求不能發(fā)送悴晰。
其中第3條開發(fā)時碰到的最多。
5.解決非同源AJAX請求報錯
同源政策規(guī)定逐工,AJAX請求只能發(fā)給同源的網(wǎng)址铡溪,否則就報錯。
除了架設(shè)服務(wù)器代理(瀏覽器請求同源服務(wù)器泪喊,再由后者請求外部服務(wù))棕硫,有三種方法規(guī)避這個限制。
1>JSONP
2>WebSocket
3>CORS
Part2:SpringMVC通過CORS協(xié)議解決跨域問題
1.CORS介紹
CORS是一個W3C標(biāo)準(zhǔn)袒啼,全稱是"跨域資源共享"(Cross-origin resource sharing)哈扮。
它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest
請求蚓再,從而克服了AJAX只能同源使用的限制滑肉。
CORS需要瀏覽器和服務(wù)器同時支持。目前摘仅,所有瀏覽器都支持該功能靶庙,IE瀏覽器不能低于IE10。
整個CORS通信過程娃属,都是瀏覽器自動完成六荒,不需要用戶參與护姆。對于開發(fā)者來說,CORS通信與同源的AJAX通信沒有差別掏击,代碼完全一樣卵皂。瀏覽器一旦發(fā)現(xiàn)AJAX請求跨源,就會自動添加一些附加的頭信息砚亭,有時還會多出一次附加的請求灯变,但用戶不會有感覺。
因此钠惩,實現(xiàn)CORS通信的關(guān)鍵是服務(wù)器柒凉。只要服務(wù)器實現(xiàn)了CORS接口族阅,就可以跨源通信篓跛。
2.方法1:Spring-自定義Fliter:在response中添加CORS響應(yīng)頭(Access-Control-Allow*)
3.方法2:SpringMVC4提供了非常方便的實現(xiàn)跨域的方法。在requestMapping中使用注解坦刀。
@CrossOrigin(origins = “http://kbiao.me”)
Part3:自己實際測試
1.跨域情境模擬:
前端index.html在電腦A上愧沟,頁面中有個submit按鈕來發(fā)送ajax請求。且請求url定位到后臺對應(yīng)Handler:http://192.168.0.218:8080/InsureService/crossOrigin/detail
鲤遥;
后臺服務(wù)器在電腦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.跨域問題重現(xiàn):
在上述情境準(zhǔn)備下盖奈,前端請求的源
Origin為null
混坞,后端源
Origin為http://192.168.0.218:8080
。兩者不同源钢坦,所以前端的ajax請求究孕,無法到達(dá)后臺的Handler,也就不能被處理爹凹。(前端源為null厨诸,因為在本地電腦A直接在瀏覽器加載html文件發(fā)起請求導(dǎo)致。)
谷歌瀏覽器測試禾酱,截圖:
3.跨域問題解決:使用Spring的@CrossOrigin注解
@CrossOrigin注解微酬,可以放在Controller類上,允許Controller中所有方法可被某個源
跨域請求颤陶;也可以放在Controller類中某一個方法上颗管,指明當(dāng)前方法可以被哪些源
跨域請求。
示例代碼中:將@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
}
分析:
瀏覽器針對'非簡單請求'的跨域滓走,會根據(jù)CORS協(xié)議在底層會發(fā)起兩次request:
(1)使用HTTP協(xié)議OPTIONS方法忙上,發(fā)起的預(yù)檢請求
(preflight request);
(2)發(fā)起正常請求
谷歌瀏覽器測試結(jié)果:
參考文章(干貨滿滿)
1.阮一峰---瀏覽器同源政策及其規(guī)避方法
2.阮一峰---跨域資源共享 CORS 詳解
3.Spring MVC通過CROS協(xié)議解決跨域問題