前言
本文將講解前后端項目中跨域問題的常見解決方案,其中后端基於SpringBoot,前端使用了jQuery、axios等框架用於實戰代碼的講解。本文將不涉及跨域的解釋和SpringBoot等框架,或者是Nginx的使用,將主要講解前后端分離項目中跨域問題的解決,不過如果你遇到了問題,也歡迎一起交流學習。
跨域解決
-
JSONP方式這種方式只能用於
Get請求,因此如果需要以Post請求方式獲取數據,則可以先看后面CORS解決方式,以下就講解兩種基於JSONP原理的解決方案,首先先看后端的接口:@RestController @RequestMapping("/api/customer") public class HelloController { @GetMapping("/getAllCustomerInfo") public String getAllCustomerInfo() { // 返回的數據必須包含在 getAllCustomerInfo() 字符串中 // 以便在返回到前端后,可以自動執行回調函數,獲取數據 // getAllCustomerInfo() 與前端的回調函數名對應 return "getAllCustomerInfo(" + getCustomerList() + ")"; } private String getCustomerList() { List<Customer> list = new ArrayList<>(Arrays.asList( new Customer(1, "張三", "123456"), new Customer(2, "李四", "654321"), new Customer(3, "王五", "123123") )); return new Gson().toJson(list); } }下面就來分別講解以下兩種方式的解決方案:
-
js原生解決方案// 首先設置 src 並將結點添加到 <head> 中 const script = document.createElement('script') script.src = 'http://localhost:8080/api/customer/getAllCustomerInfo' document.head.appendChild(script) // 回調函數名與接口中返回的名字對應 const getAllCustomerInfo = res => { console.table(res, ['id', 'username', 'password']) }通過以上設置就可以在
Console中看到以下結果:
-
jQuery的ajax解決方案// 記得需要引入 jQuery <script src="https://cdn.staticfile.org/jquery/1.10.0/jquery.js"></script> $.ajax({ url: 'http://localhost:8080/api/customer/getAllCustomerInfo', type: 'get', dataType: 'jsonp', jsonpCallback: "getAllCustomerInfo" }) // 回調函數同上 const getAllCustomerInfo = res => { console.table(res, ['id', 'username', 'password']) }
-
-
CORS解決方案跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求,詳細解釋請看鏈接。
-
后端接口中進行設置
通過利用
CORS,我們在前端只需要利用正常的ajax請求方式即可,無需再設置回調函數,在這里我們使用了axios,在展示后端代碼之前,我們先看后端代碼的改變,為了區別於JSONP只能進行Get請求,我們這里將接口改成了Post:@RestController @RequestMapping("/api/customer") public class HelloController { @PostMapping("/getAllCustomerInfo") public List<Customer> getAllCustomerInfo(HttpServletResponse response) { // 設置響應頭 response.setHeader("Access-Control-Allow-Origin", "*"); // 不再需要將結果放在回調函數中 return new ArrayList<>(Arrays.asList( new Customer(1, "張三", "123456"), new Customer(2, "李四", "654321"), new Customer(3, "王五", "123123") )); } }然后前端代碼直接使用
ajax請求即可:// 首先需要引入 axios <script src="https://cdn.staticfile.org/axios/0.1.0/axios.js"></script> axios.post('http://localhost:8080/api/customer/getAllCustomerInfo') .then(res => { console.table(res, ['id', 'username', 'password']) }) -
Nginx反向代理關於反向代理的知識,這里不做詳細解析,感興趣的話,可以查看該鏈接。通過使用
Nginx的反向代理,我們在后端接口中就可以去掉響應頭的代碼設置:@RestController @RequestMapping("/api/customer") public class HelloController { @PostMapping("/getAllCustomerInfo") public List<Customer> getAllCustomerInfo() { return new ArrayList<>(Arrays.asList( new Customer(1, "張三", "123456"), new Customer(2, "李四", "654321"), new Customer(3, "王五", "123123") )); } }然后是
nginx.conf中的修改:server { # 監聽80端口, 前端不再直接訪問8080端口, 改為訪問80端口即可 listen 80; server_name localhost; location / { root html; # 添加頭 add_header Access-Control-Allow-Origin *; # 代理轉發到8080后端端口 proxy_pass http://localhost:8080; index index.html index.htm; } }然后再將前端中訪問的接口修改為80:
// 首先需要引入 axios <script src="https://cdn.staticfile.org/axios/0.1.0/axios.js"></script> // 80為 http 默認端口,可省略 axios.post('http://localhost/api/customer/getAllCustomerInfo') .then(res => { console.table(res, ['id', 'username', 'password']) })然后開啟
Nginx服務器,Console中再次出現了我們想看到的結果:
-

總結
本文並沒有包括跨域問題的所有解決方案,不過相信對於大部分的跨域問題,都已經可以解決了,本文在之后也可能會繼續更新,講解更多種解決跨域問題的方法,也歡迎各位一起交流學習。
