一文帶你徹底搞懂JS前端跨域請求

什麼是跨域請求

  1. 在前端開發編碼過程中,常見的 html 標籤例如:a、form、img、script、link、iframe以及 Ajax 操作都可以指向一個資源地址或者說可以發起對一個資源的請求,那麼這裏所說的請求就存在同域請求還是跨域請求。
  2. 所謂跨域請求就是指:當前發起請求的域與該請求指向的資源所在的域不一致(這裏所有的域是協議、域名和端口號的合集,同域就是所協議、域名和端口號均相同,任何一個不同都是跨域)。

常見的跨域場景如下:

源 URL 請求 URL 是否跨域 說明
http://mcy.com/a http://mcy.com/b 同協議同域名同端口號,不同請求,不算跨域請求
http://mcy.com/a http://mcy.com:8080/b 端口不同
http://mcy.com/a https://mcy.com/b 協議不同
http://www.mcy.com/a http://mcy.a.com/b 主域名相同,但是子域名不相同
http://mcy.com/a http://abc.com/b 域名不相同

爲什麼要使用跨域請求

  1. 在現代前端開發中,我們經常需要調用第三方的服務接口(例如 mock server、fake api),隨着專業化分工的出現有很多專業的信息服務提供商爲前端開發者提供各類接口,這種情況下就需要進行跨域請求(這類前端接口服務很多是採用的 cors 方式來解決跨域問題的)。
  2. 還有一類情況是在前後端分離的項目中,前端後端分屬於不同的服務跨域問題在採用這種架構的時候就存在。而且現在很多項目都採用這種前後分離的方式。

跨域請求實現

一、jsonp 跨域

通常爲了減輕web服務器的負載,我們可以引入其他服務器上的js、css,img等靜態資源,在html頁面中再通過相應的標籤從不同域名下加載靜態資源,而被瀏覽器允許,基於此原理,我們可以通過動態創建script,再請求一個帶參網址實現跨域請求。
1、原生實現

var script = document.createElement('script');
script.type = 'text/javascript';

// 傳參並指定回調執行函數爲onBack
script.src = 'http://machaoyin.top:8080/user/findById?id=1&callback=back';
document.head.appendChild(script);

// 回調執行函數
function back(data) {
	console.log(data);
}

原生實現除了這樣寫,還可以自己使用script標籤請求,具體代碼如下;

// 回調執行函數
function back(data) {
	console.log(data);
} 
//跨域請求
<script src="http://machaoyin.top:8080/user/findById?id=1&callback=back"></script>

後端返回方法(根據id查詢數據)

@GetMapping(value = "findById")
@ApiOperation(value = "根據id獲取用戶信息", notes = "根據id查詢用戶信息")
public String getUser(Integer id, HttpServletRequest request, HttpServletResponse response){
    String callback = (String)request.getParameter("callback");
    User user = userService.findById(id);
    JSONObject jsonObject = JSONObject.fromObject(user);
    String retStr = callback + "(" + jsonObject + ")";
    return retStr;
}

返回查詢的對象數據。其中使用JSONObject把JavaBean對象轉爲json字符串。JSONObject的使用請移步:淺談JSONObject的使用
測試代碼中請求的地址爲我服務器地址,後端請求接口方法使用的Swagger來維護接口規範,詳情請訪問:SpringBoot整合Swagger2
請求的結果如圖:
在這裏插入圖片描述
2、Jquery AJAX實現

$.ajax({
	url: 'http://machaoyin.top:8080/user/findById?id=1',
	type: 'get',
	dataType: 'jsonp',  // 請求方式爲jsonp
	success:function(data){     
		console.log(data);   
	}
}); 

【注】返回結果和原生實現返回的一樣。使用jsonp很方便也很簡單,但有一個缺點就是隻能發送get請求,AJAX設置post方法也是發送get請求。

二、跨域資源共享 CORS

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源(協議 + 域名 + 端口)服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同域使用的限制。
CORS需要瀏覽器和服務器同時支持。它的通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX/Fetch通信沒有差別,代碼完全一樣。瀏覽器一旦發現請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。因此,實現CORS通信的關鍵是服務器。只要服務器端實現了CORS接口,就可以跨域請求。

後端CORS接口案例:

@CrossOrigin(origins = "*")
@PostMapping(value = "/find")
@ApiOperation(value = "根據id獲取用戶信息", notes = "根據id查詢用戶信息")
public User find(Integer id){
    return userService.findById(id);
}

在SpringMVC中可以直接使用註解@CrossOrigin來解決跨域接口的問題。
@CrossOrigin有兩個參數

  1. maxAge:最長響應時間(單位是秒)。
  2. origins:允許對哪些地址進行響應(*不限制)。

web項目中可以通過HttpServletResponse 來設置,具體代碼如下:

@RequestMapping(value = "/find")
@ApiOperation(value = "根據id獲取用戶信息", notes = "根據id查詢用戶信息")
public User find(Integer id, HttpServletResponse  res){
    //允許請求的地址
    res.setHeader("Access-Control-Allow-Origin", "*");
    //請求方式,也可以在請求註解上設置
    res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    //最長響應時間
    res.setHeader("Access-Control-Max-Age", 60);
    return userService.findById(id);
}

前臺跨域請求不需要任何改變,和平常的AJAX請求一樣即可,如下:

$.ajax({
	url: 'http://machaoyin.top:8080/user/find?id=1',
	type: 'post',
	success: function(data){
		console.log(data);
	}
});

請求結果和上面的一樣,這裏就不多展示了。

【注】 jsonp跨域請求和跨域資源共享 CORS最大區別在也jsonp只能發送get請求,而CORS可以發送http的任一請求類型。


最後有什麼不足之處,歡迎大家指出,期待與你的交流。如果感覺對你有幫助,點個贊在走唄 O(∩_∩)O ~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章