跨域問題及常用的 4 種解決方案

跨域問題產生、原理、解決方案

文章導讀

前言

  跨域問題指的是在 Web 開發中,由於瀏覽器的同源策略限制,當一個網頁嘗試訪問與它不同源(協議、域名或端口不同)的資源時,可能會遇到安全限制導致無法正常訪問的問題。這種策略旨在防止惡意網站讀取或修改其他網站的數據,保護用戶信息安全。

這樣說可能有點抽象,下面具體展開說明。

跨域問題演示

  通常情況下,我們主流的開發模式是:前後端分離。當我們從瀏覽器 80 訪問服務端 81 應用

下面我們用一個 Web 工程,一個後端工程具體簡單演示下。

1、Web 工程結構:

spring.application.name=springboot-cross-web
server.port=8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta >
    <title>測試跨域請求頁面</title>
    <script src="js/jquery-3.5.1.min.js"></script>
</head>
<body>
<div>
    <input type="button" onclick="crossSubmit()" value="跨域測試">
</div>
<script>
    function crossSubmit() {
        // 發送跨域請求
        jQuery.ajax({
            url: "http://localhost:8081/api/cross",
            type: "POST",
            data: {"key""Cross"},
            success: function (result) {
                alert("返回數據:" + result.data);
            }
        });
    }
</script>
</body>
</html>

2、後端工程結構:

spring.application.name=springboot-cross
server.port=8081
@RestController
public class CrossAppController {

    @RequestMapping("/api/cross")
    public HashMap<String, Object> crossTest() {
        return new HashMap<String, Object>() {{
            put("state", 200);
            put("data""success");
        }};
    }
}

3、啓動並測試

瀏覽器報錯產生跨域問題。

爲什麼產生跨域問題?

一般來講,通常產生跨域問題有以下幾種原因:

  1. 協議不同:如 https 和 http;

  2. 端口不同

  3. 域名不同

這就是常說的同源策略的問題。產生跨域問題的根源就是請求不同源。

如何解決跨域問題?

從上邊的問題來看,主要在於瀏覽器保護,對參數 "Access-Control-Allow-Origin"的設置。

主要有下解決方案:

一、使用 @CrossOrigin 註解

@RestController
@CrossOrigin(origins = "*")
public class CrossAppController {

    @RequestMapping("/api/cross")
    public HashMap<String, Object> crossTest() {
        return new HashMap<String, Object>() {{
            put("state", 200);
            put("data""success");
        }};
    }
}

演示結果:

二、使用全局跨域配置

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/cross")
                .allowedOrigins("*")
                .allowedMethods("GET""POST""PUT""DELETE")
                .allowedHeaders("*");
                //.allowCredentials(true);
    }
}

三、使用 CorsFilter 跨域

@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        // 設置允許的來源
        response.setHeader("Access-Control-Allow-Origin""*");
        // 處理預檢請求
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }
}

四、使用 Nginx 來實現跨域

server {  
    listen 80;  

    server_name your.domain.com;  

    location / {  
        # 添加CORS相關的響應頭  
        add_header 'Access-Control-Allow-Origin' '*';  
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';  

        # 對於OPTIONS請求,直接返回204狀態碼  
        if ($request_method = 'OPTIONS') {  
            return 204;  
        }  

        # 其他配置...  

        # 代理到後端服務或其他配置...  
        # proxy_pass http://your_backend/;  
        # 其他proxy_...指令...  
    }  
}

總結

參考文章: https://mp.weixin.qq.com/s/YQr0q4qeZb5p1s-FVEdJvg

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Ru05rz8kN2_uWWUx0XKd_A