什麼是 ajax 跨域
主流的前後端分離模式下,當前端調用後臺接口時,由於是在非同一個域下的請求,從而會引發瀏覽器的自我安全保護機制,最終結果是接口成功請求並響應,但前端不能正常處理該返回數據。
因此,當同時滿足以下三個條件的情況下,就會出現跨域問題:
- 瀏覽器限制
- 非同源請求(跨域)
- 發送的是 XHR ( XMLHttpRequest ) 請求
解決方案
想要徹底解決跨域問題,只需要破壞以上三個條件的任一即可:
1. 修改瀏覽器(不推薦)
添加瀏覽器啟動參數:chrome --disable-web-security,但是極不推薦這種解決方式。
2. JSONP請求(不常用)
Jsonp,全稱 JSON with Padding,一種非官方的協議,而是一種約定;前端通過向後臺發送>
所以,後臺也需要做相應的處理。以 Java 為例,添加如下配置即可:
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
// 前後端約定的jsonp參數名,默認值是callback
super("callback");
}
}
注意,Spring 4.1 版本之後,官方已不再推薦使用上述允許 jsonp 請求的配置,建議使用 CROS 配置來解決跨域問題,詳情可查看這裡
綜上,jsonp 請求存在以下幾個弊端:
- 服務端需要改動代碼進行支持;
- 只支持發送 Get 請求,請求頭中更改其它類型的請求方式是無效的;
- 發送的不是 XHR 請求,而是>
3. 調用方隱藏跨域
用 Nginx 或 Apache 來代理調用方的請求(客戶端變更為相對路徑請求,而非絕對路徑),此時對於瀏覽器來說,由於請求是同源的,因此就不存在跨域問題。
4. 被調用方允許跨域(最常用)
- 服務端配置
以 Java 應用為例,添加如下全局配置:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允許跨域的接口
.allowedOrigins("*") // 允許跨域的請求源
.allowedMethods("*") // 允許跨域的請求方式
.allowedHeaders("*") // 允許跨域的請求頭
.allowCredentials(true) // 帶cookie請求的時候需要開啟,且allowedOrigins需要指定為具體的請求源(最好是動態配置)
.maxAge(60 * 60 * 24); // 設定options請求預檢命令的緩存時長
}
}
如果只想針對某個類下的接口,或者是某個具體的接口配置允許跨域,只需要在相應的地方添加註解 @CrossOrigin 即可。
- Nginx 配置
如果配置了 nginx 作為代理服務器,那麼只需要為 nginx 添加支持跨域請求即可:
server {
listen 80;
server_name xxx.com;
location / {
proxy_pass http://localhost:8080/;
# 配置允許跨域
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
# 對於options預檢請求,直接響應200
if ($request_method = OPTIONS) {
return 200;
}
}
}
擴展思考
Q1:瀏覽器在執行跨域請求時,是先執行後判斷,還是先判斷後執行?
A1:都有可能,這需要根據所發送的請求是簡單請求還是非簡單請求來判斷;如果是非簡單請求,瀏覽器每次在執行真正的請求之前,還會先發送一個 options 請求方式的預檢命令【
Q2:如果是允許帶(被調用方) cookie 的跨域請求,此時服務端同樣配置為 Access-Control-Allow-Origin 等於 *,前端是否還可以請求成功?
A2:不可以,此時要將 Access-Control-Allow-Origin 指定為調用方具體的域【 可以先取得調用方的域再動態配置,這樣就不存在多個域請求的限制問題 】,並且添加配置 Access-Control-Allow-Credentials 為 true。
我自己是一名從事了多年的前端老程序員,小編為大家準備了新出的前端編程學習資料,免費分享給大家!
如果你也想學習前端,那麼幫忙轉發一下然後再關注小編後私信【1】可以得到我整理的這些前端資料了(私信方法:點擊我頭像進我主頁有個上面有個私信按鈕)
閱讀更多 前端明澈 的文章