Ajax 跨域解決(一)——SpringBoot學習
·
什麼是跨域
在目前的前後端分離開發模式下,前端使用 Ajax 訪問後端提供的介面獲取資料,產生報錯。
跨域發生的原因
1. 瀏覽器的限制
2. 發生跨域訪問
3. 傳送的是 XHR(XMLHttpRequst) 請求
三者同時發生,就會發生跨域問題
解決方式
因為是三者同時發生,才能發生跨域問題,因此針對三者,處理其中的一個即可。
首先是瀏覽器的限制,需要指定引數讓瀏覽器不做校驗,但方法不太合理,需要每個人都去做修改。其次是傳送的請求不要是 XHR 型別的,解決方式是 JSONP 。最後是針對跨域,分為兩點,一是讓被呼叫方支援跨域,在響應頭中新增引數,表示支援跨域訪問,核心是支援跨域,二是讓呼叫方在請求中使用代理,將從 A 域名傳送到 B 的請求通過代理,讓 B 認為是從本域名來的,核心是隱藏跨域。
具體解決方式
針對瀏覽器,通過命令列的方式啟動,讓其不要做跨域校驗即可。
1 eg:chrome --disable-web-security
針對 XHR 方式,本身瀏覽器傳送的是 json 請求,通過 jsonp 的方式,將其變為 js 的方式,核心是通過動態新增 script 的方式來封裝了請求,從而解決跨域問題。
使用這種方式需要修改服務端的程式碼,修改方式如下:
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice (
public JsonpAdvice() {
super("callback");
}
}
前端通過制定 dataType 的方式來發送請求,如下所示
$.ajax({
url:base+"/get1",
dataType: "jsonp",
jsonp: "callback",
cache: true,
type:"post",
success:function(json){
result = json;
}
})
但使用這種方式仍然是不好的方式,其有如下弊端
1. 需要伺服器端改變程式碼,如果涉及呼叫第三方介面,根本無法完成;
2. 只支援 GET 請求,在真是的業務場景中十分受限;
3. 因為改變了請求的型別,從 XHR 變為了 js 方式,因此 XHR 的很多優良特性無法使用。
因此,解決跨域問題最好的方式還是通過解決跨域訪問來解決,使用伺服器端支援跨域或呼叫端隱藏跨域來解決。
呼叫方解決跨域(支援跨域)的3種解決方式
1. 伺服器端實現
2. Nginx 配置
3. Apache 配置
使用 Filter 來實現
通過過濾器在所有請求的 Response 中新增欄位來支援跨域訪問。
1 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 2 3 HttpServletRequest req = (HttpServletRequest) request; 4 5 HttpServletResponse res = (HttpServletResponse) response; 6 7 String origin =req.getHeader("Origin"); 8 9 if (!StringUtils.isEmpty(origin)){ // 動態新增訪問地址,使得所有的域名都可以跨域訪問 10 11 res.addHeader("Access-Control-Allow-Origin",origin); 12 13 } 14 15 String headers = req.getHeader("Access-Control-Request-Headers"); 16 17 if (!StringUtils.isEmpty(headers)){ // 動態新增自定義訪問頭 18 19 res.addHeader("Access-Control-Allow-Headers",headers); 20 21 } 22 23 res.addHeader("Access-Control-Allow-Methods","*"); 24 25 res.addHeader("Access-Control-Max-Age","3600"); 26 27 res.addHeader("Access-Control-Allow-Credentials","true"); 28 29 chain.doFilter(request,response); 30 31 } 32 33 34 35 @Bean 36 37 FilterRegistrationBean registrationBean(){ 38 39 FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean(); 40 41 filterRegistrationBean.addUrlPatterns("/*"); 42 43 filterRegistrationBean.setFilter(new CrosFilter()); 44 45 filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); 46 47 filterRegistrationBean.setName("Ajax"); 48 49 return filterRegistrationBean; 50 51 }
被呼叫方解決跨域(隱藏跨域)的解決方式
在 Spring 框架中的解決方式:在需要的類或方法上加上註解, @CrossOrigin
Nginx 配置
Apache 配置
Nginx 和 Apache 的解決方式因為涉及到其兩個框架的方式,因為還沒有深入瞭解過,所以在這沒有敘述,以後深入學習過後,再詳細編寫。