前后端分離項目跨域問題解決方案總結


前言

本文將講解前后端項目中跨域問題的常見解決方案,其中后端基於SpringBoot,前端使用了jQueryaxios等框架用於實戰代碼的講解。本文將不涉及跨域的解釋和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);
        }
    
    }
    

    下面就來分別講解以下兩種方式的解決方案:

    1. 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中看到以下結果:

      image-20200915142859045

    2. jQueryajax解決方案

      // 記得需要引入 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 請求,詳細解釋請看鏈接

    1. 后端接口中進行設置

      通過利用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'])
      	})
      
    2. 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中再次出現了我們想看到的結果:

image-20200915150523876

總結

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM