跨域問題的解決方案

一、跨域問題的本質

1.1 同源策略的三要素

瀏覽器的同源策略(Same-Origin Policy)要求請求的 協議、域名、端口 完全一致,否則視為跨域:

  • 協議不同httphttps
  • 域名不同a.comb.com
  • 端口不同http://a.com:80http://a.com:8080

1.2 跨域請求的分類

  • 簡單請求(Simple Request):
    • HTTP方法:GETPOSTHEAD
    • 請求頭:僅允許 AcceptAccept-LanguageContent-Type(且 Content-Type 僅限 text/plainmultipart/form-dataapplication/x-www-form-urlencoded
  • 預檢請求(Preflight Request):
    • 當請求包含自定義頭(如 Authorization)或使用非簡單方法(如 PUTDELETE)時,瀏覽器會先發送 OPTIONS 請求,詢問服務器是否允許該請求。

二、解決方案一:CORS 標準實現

2.1 CORS 工作原理

CORS 通過 預檢協商機制 解決跨域問題:

  1. 預檢請求(OPTIONS)
    • 瀏覽器發送 OPTIONS 請求,攜帶請求方法(Access-Control-Request-Method)和頭字段(Access-Control-Request-Headers)。
    • 服務端響應中必須包含允許的 originmethodsheaders,否則瀏覽器阻止后續請求。
  2. 實際請求
    • 若預檢通過,瀏覽器發送真實請求,并攜帶 Origin 頭。
    • 服務端在響應頭中明確允許的 Access-Control-Allow-Origin,瀏覽器才會將數據返回給前端。
2.2.1 Spring Boot 實現
// 全局CORS配置(application.properties)
spring.mvc.cors.enabled=true
spring.mvc.cors.allow-origins=http://client.example.com
spring.mvc.cors.allow-methods=GET,POST,PUT,DELETE,OPTIONS
spring.mvc.cors.allow-headers=Authorization,Content-Type,X-Requested-With
spring.mvc.cors.exposed-headers=X-Total-Count
spring.mvc.cors.allow-credentials=true
spring.mvc.cors.max-age=3600// 或通過Java配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://client.example.com").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("Authorization", "Content-Type").exposedHeaders("X-Total-Count").allowCredentials(true).maxAge(3600);}
}
2.2.2 預檢請求處理(關鍵點)

Spring Boot 默認會自動處理 OPTIONS 請求,但需確保:

  • allowedMethods 包含 OPTIONS
  • allowedHeaders 包含所有自定義頭字段
2.3 安全加固
  • 動態驗證來源
    @Bean
    public CorsWebFilter corsFilter() {return (serverWebExchange, chain) -> {String origin = serverWebExchange.getRequest().getHeaders().getOrigin();if (allowedOrigins.contains(origin)) {// 設置CORS頭serverWebExchange.getResponse().getHeaders().add("Access-Control-Allow-Origin", origin);return chain.filter(serverWebExchange);}return Mono.error(new AccessDeniedException("Invalid origin"));};
    }
    

三、解決方案二:JSONP

3.1 JSONP 工作原理

JSONP 利用 <script> 標簽的跨域特性,通過動態注入腳本實現數據回傳:

  1. 前端動態注入
    • 創建 <script> 標簽,src 指向服務端接口,附加 callback 參數。
  2. 服務端封裝數據
    • 將數據包裝在 callback 函數中,返回類似 handleResponse({data: "value"}) 的字符串。
  3. 前端執行回調
    • 瀏覽器解析腳本,執行 handleResponse 函數,獲取數據。
3.2 后端代碼
@RestController
public class JsonpController {@GetMapping("/jsonp")public String handleJsonp(@RequestParam String callback // 接收前端傳遞的回調函數名) {// 生成模擬數據Map<String, Object> data = new HashMap<>();data.put("name", "Alice");data.put("age", 25);// 防XSS攻擊:校驗callback參數格式if (!callback.matches("^[a-zA-Z0-9_]+$")) {throw new IllegalArgumentException("Invalid callback parameter");}// 將數據封裝到回調函數中return callback + "(" + new Gson().toJson(data) + ")";}
}
3.3 優缺點對比
優點缺點
無需服務端配置CORS僅支持GET請求
兼容性好(支持舊瀏覽器)存在XSS風險(需嚴格校驗callback)
實現簡單不支持復雜認證(如JWT)

四、解決方案三:Nginx反向代理

4.1 反向代理原理

Nginx 作為反向代理,將客戶端請求轉發到后端服務,使瀏覽器認為請求與當前頁面同源:

  1. 請求轉發
    • 客戶端請求 http://frontend.com/api/data
    • Nginx 將請求轉發到 http://backend.com:3000/data
  2. 響應頭偽造
    • Nginx 可修改響應頭,如 Access-Control-Allow-Origin,使瀏覽器認為請求是同源的。
4.2 配置示例(支持WebSocket與HTTPS)
server {listen 443 ssl;server_name frontend.com;ssl_certificate /path/to/cert.pem;ssl_certificate_key /path/to/key.pem;location /api/ {# 反向代理到后端proxy_pass http://backend:3000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;# CORS配置add_header Access-Control-Allow-Origin $http_origin;add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";add_header Access-Control-Allow-Headers "Authorization";add_header Access-Control-Allow-Credentials "true";# WebSocket支持proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";}# 處理OPTIONS預檢location ~ ^/api/ {if ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Origin' '$http_origin';add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';add_header 'Access-Control-Max-Age' 86400;return 204;}}
}
4.3 安全加固
  • 限制來源
    map $http_origin $allowed_origin {default '';~^(http://client\.example\.com|https://another\.domain\.com)$ $http_origin;
    }server {add_header Access-Control-Allow-Origin $allowed_origin always;if ($allowed_origin = '') {return 403;}
    }
    

五、解決方案四:API網關(微服務場景)

5.1 API網關核心原理

API網關作為微服務的統一入口,集中處理跨域、認證、限流等邏輯:

  1. 集中配置CORS
    • 在網關層統一設置 Access-Control-Allow-Origin,避免每個微服務重復配置。
  2. 路由與安全策略
    • 根據請求路徑路由到對應服務,同時執行身份驗證(如JWT校驗)。
5.2 Spring Cloud Gateway 實現
// 配置全局CORS
@Bean
public CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.setAllowedOrigins(List.of("http://client.example.com"));config.setAllowedMethods(List.of("GET", "POST"));config.setAllowedHeaders(List.of("Authorization"));UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return new CorsWebFilter(source);
}// 動態路由配置
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("user-service", r -> r.path("/api/user/**").filters(f -> f.addRequestHeader("X-Forwarded-Proto", "https")).uri("lb://user-service")).build();
}
5.3 優勢與適用場景
優點適用場景
集中式管理跨域與安全策略微服務架構、需要統一鑒權的系統
支持復雜路由與負載均衡高并發、多服務交互的場景

六、解決方案五:代理服務器(Node.js示例)

6.1 代理服務器原理

代理服務器(如Nginx、Node.js)接收客戶端請求,轉發到目標服務,并修改響應頭以繞過跨域限制。

6.2 Node.js實現(http-proxy-middleware)
// proxy.config.js
module.exports = {'/api': {target: 'http://backend.example.com:3000',changeOrigin: true,onProxyReq: (proxyReq, req, res) => {// 動態修改請求頭proxyReq.setHeader('X-Forwarded-For', req.ip);proxyReq.setHeader('X-Real-IP', req.ip);},onProxyRes: (proxyRes, req, res) => {// 添加CORS頭proxyRes.headers['Access-Control-Allow-Origin'] = req.headers.origin;}}
};
6.3 安全建議
  • 限制來源
    const allowedOrigins = ['http://client.example.com'];
    if (!allowedOrigins.includes(req.headers.origin)) {return res.status(403).send('Forbidden');
    }
    

七、解決方案六:服務器端渲染(SSR)

7.1 SSR原理

在服務器端生成完整HTML頁面,直接返回給瀏覽器,避免瀏覽器發起跨域AJAX請求。

7.2 Next.js 實現
// pages/index.js
export async function getServerSideProps() {const res = await fetch('http://api.example.com/data', {headers: {Authorization: 'Bearer YOUR_TOKEN'}});const data = await res.json();return { props: { data } };
}export default function Home({ data }) {return <div>{JSON.stringify(data)}</div>;
}
7.3 優勢與局限
優點局限
首屏加載快、SEO友好僅適用于靜態或半動態頁面
無跨域問題開發復雜度較高

八、方案選擇決策樹

場景推薦方案原因技術棧
單頁應用(SPA)開發Nginx反向代理 / 代理服務器開發與生產環境統一配置,避免前后端分離的復雜性Node.js, Nginx
微服務架構API網關統一處理集中式管理,支持動態路由與權限控制Spring Cloud Gateway, Kong
舊項目兼容第三方APIJSONP無需后端改造,快速集成Vanilla JS
需要嚴格安全控制CORS標準實現 + 白名單細粒度配置,支持所有HTTP方法Spring Boot, Express.js
WebSocket跨域Nginx反向代理 + WebSocket支持需要處理Upgrade頭和Connection頭Nginx
服務端渲染(SSR)服務器端直接請求避免瀏覽器發起跨域請求Next.js, Nuxt.js

九、常見問題與最佳實踐

9.1 預檢請求(OPTIONS)的深度處理

  • 問題:當請求包含自定義頭或使用非簡單方法(如PUT/DELETE)時,瀏覽器會先發送OPTIONS請求。
  • 解決方案
    • 在后端顯式返回 Access-Control-Allow-MethodsAccess-Control-Allow-Headers
    • 對OPTIONS請求返回204 No Content狀態碼
9.1.1 Spring Boot示例
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("Authorization", "Content-Type", "X-Requested-With");}
}

9.2 安全性建議

  • 避免使用 *allowCredentials 同時開啟
    // 錯誤配置
    app.use(cors({ origin: '*', credentials: true }));
    
  • 限制 allowedOrigins 為可信域名列表
    allowedOrigins: ["http://client.example.com", "https://another-domain.com"]
    
  • 對敏感接口啟用CSRF防護
    app.use(csrf());
    app.use((req, res, next) => {res.cookie('XSRF-TOKEN', req.csrfToken());next();
    });
    

十、擴展知識點

10.1 WebSocket跨域解決方案

通過Nginx配置支持WebSocket:

location /ws/ {proxy_pass http://backend-ws.example.com;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";add_header Access-Control-Allow-Origin $http_origin;
}

10.2 跨域Cookie處理

  • 前端設置
    fetch('http://api.example.com', {credentials: 'include' // 允許攜帶Cookie
    });
    
  • 后端配置
    add_header Set-Cookie "SameSite=None; Secure"; // HTTPS下強制跨域Cookie
    

十一、總結

跨域問題的解決需要結合項目架構、安全需求與開發效率綜合考量。CORS作為標準方案應優先采用,而Nginx、API網關等則適用于復雜場景。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73685.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73685.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73685.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux 上使用 Docker 部署 Kafka 集群

在 Linux 上使用 Docker 部署 Kafka 集群的步驟如下 1. 準備工作 確保已安裝&#xff1a; Docker Docker Compose 2. 創建 Docker Compose 文件 (docker-compose.yml) version: 3.8services:zookeeper:image: wurstmeister/zookeepercontainer_name: zookeeperports:- &quo…

【性能優化點滴】odygrd/quill 中一個簡單的標記位作用--降低 IO 次數

在 StreamSink 類中&#xff0c;成員變量 _write_occurred 的作用是 跟蹤自上次刷新&#xff08;Flush&#xff09;以來是否有寫入操作發生&#xff0c;其核心目的是 優化 I/O 性能。以下是詳細解析&#xff1a; _write_occurred 的作用 1. 避免不必要的刷新&#xff08;Flush…

Ubuntu Linux安裝PyQt5并配置Qt Designer

一 安裝 PyQt5 借助 apt 包管理器來安裝 PyQt5 及其相關的開發工具&#xff1a; sudo apt install python3-pyqt5 pyqt5-dev-tools 假如報錯&#xff0c; You might want to run apt --fix-broken install to correct these. 直接執行&#xff1a; sudo apt --fix-…

2025清華大學:DeepSeek教程全集(PDF+視頻精講,共10份).zip

一、資料列表 第一課&#xff1a;Deepseek基礎入門 第二課&#xff1a;DeepSeek賦能職場 第三課&#xff1a;普通人如何抓住DeepSeek紅利 第四課&#xff1a;讓科研像聊天一樣簡單 第五課&#xff1a;DeepSeek與AI幻覺 第六課&#xff1a;基于DeepSeek的AI音樂詞曲的創造法 第…

容器C++

string容器 string構造函數 #include<iostream> using namespace std; #include<string.h> void test01() {string s1;//默認構造const char* str "hello world";string s2(str);//傳入char*cout << "s2" << s2 << endl;s…

【2.項目管理】2.4 Gannt圖【甘特圖】

甘特圖&#xff08;Gantt&#xff09;深度解析與實踐指南 &#x1f4ca; 一、甘特圖基礎模板 項目進度表示例 工作編號工作名稱持續時間(月)項目進度&#xff08;周&#xff09;1需求分析3▓▓▓???????2設計建模3?▓▓▓??????3編碼開發3.5???▓▓▓▓??…

C++List模擬實現|細節|難點|易錯點|全面解析|類型轉換|

目錄 1.模擬代碼全部 2.四大塊代碼理解 1.最底層&#xff1a;ListNode部分 2.第二層&#xff1a;ListIterator部分 3.第三層&#xff1a;ReserveListIterator部分 4最終層&#xff1a;List 1.模擬代碼全部 using namespace std; template<class T> struct ListNode …

【深度學習與實戰】2.1、線性回歸模型與梯度下降法先導

import numpy as np# 數據準備 X np.array([1, 2, 3]) y np.array([3, 5, 7])# 參數初始化 w0, w1 0, 0 alpha 0.1 n len(X)# 迭代10次 for epoch in range(10):# 計算預測值y_pred w1 * X w0# 計算梯度grad_w0 (1/n) * np.sum(y_pred - y)grad_w1 (1/n) * np.sum((y_…

銳捷EWEB路由器 timeout.php任意文件上傳漏洞代碼審計(DVB-2025-9003)

免責聲明 僅供網絡安全研究與教育目的使用。任何人不得將本文提供的信息用于非法目的或未經授權的系統測試。作者不對任何由于使用本文信息而導致的直接或間接損害承擔責任。如涉及侵權,請及時與我們聯系,我們將盡快處理并刪除相關內容。 一:產品介紹 銳捷EWEB路由器是銳…

flask開發中設置Flask SQLAlchemy 的 db.Column 只存儲非負整數(即 0 或正整數)

如果你想控制一個 Flask SQLAlchemy 的 db.Column 只存儲非負整數&#xff08;即 0 或正整數&#xff09;&#xff0c;你可以在模型中使用驗證來確保這一點。一種常見的方法是使用模型的 validate 方法或者在執行插入或更新操作時進行檢查。 以下是實現這一目標的幾種方法&…

sqlmap 源碼閱讀與流程分析

0x01 前言 還是代碼功底太差&#xff0c;所以想嘗試閱讀 sqlmap 源碼一下&#xff0c;并且自己用 golang 重構&#xff0c;到后面會進行 ysoserial 的改寫&#xff1b;以及 xray 的重構&#xff0c;當然那個應該會很多參考 cel-go 項目 0x02 環境準備 sqlmap 的項目地址&…

vscode連接服務器失敗問題解決

文章目錄 問題描述原因分析解決方法徹底刪除VS Code重新安裝較老的版本 問題描述 vscode鏈接服務器時提示了下面問題&#xff1a; 原因分析 這是說明VScode版本太高了。 https://code.visualstudio.com/docs/remote/faq#_can-i-run-vs-code-server-on-older-linux-distribu…

企業網站源碼HTML成品網站與網頁代碼模板指南

在當今數字化時代&#xff0c;企業網站已成為展示品牌形象、吸引客戶和提供在線服務的重要工具。對于許多企業來說&#xff0c;使用現成的HTML網站源碼模板是快速搭建網站的高效方式。本文將詳細介紹企業網站源碼、HTML成品網站以及網頁代碼模板的相關內容&#xff0c;幫助你快…

計算機網絡 - OSI 七層模型

OSI 七層模型 OSI&#xff08;Open System Interconnection&#xff0c;開放系統互聯&#xff09;模型由 ISO&#xff08;國際標準化組織&#xff09; 制定&#xff0c;目的是為不同計算機網絡系統之間的通信提供一個標準化的框架。它將網絡通信劃分為 七個層次&#xff0c;每…

flutter-實現瀑布流布局及下拉刷新上拉加載更多

文章目錄 1. 效果預覽2. 結構分析3. 完整代碼4. 總結 1. 效果預覽 在 Flutter 應用開發中&#xff0c;瀑布流布局常用于展示圖片、商品列表等需要以不規則但整齊排列的內容。同時&#xff0c;下拉刷新和上拉加載更多功能&#xff0c;能夠極大提升用戶體驗&#xff0c;讓用戶方…

在 Ubuntu 下通過 Docker 部署 Nginx 服務器

1. Docker 和 Nginx 簡介以及實驗環境 Docker 是一個開源的容器化平臺&#xff0c;允許開發者將應用程序及其依賴項打包成一個輕量級的、可移植的容器。通過 Docker&#xff0c;開發者可以在任何支持 Docker 的環境中運行應用&#xff0c;從而實現一致的開發和生產環境。Docke…

IoT平臺實時監測機器人狀態的實現方案

通過IoT平臺實時監測機器人狀態的實現方案與可執行路徑 一、整體架構設計 #mermaid-svg-6xMlDfFSZM4Wc8tA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6xMlDfFSZM4Wc8tA .error-icon{fill:#552222;}#mermaid-sv…

mybatis里in關鍵字拼接id問題

我們一般會把ids集合用StrUtil.join(‘,’)轉成"1,2,3"這種形式 然后放入in中 我們會這么寫: select id, nick_name, icon from tb_user where id in (#{ids}) order by FIELD(id, #{ids})結果發現sql執行是這樣的: select id, nick_name, icon from tb_user where…

4.用 Excel 錄入數據

一 用 Excel 錄入數據的兩種方式 用鼠標鍵盤錄入數據和從網上爬取數據。 二 用鼠標鍵盤錄入數據 1.錄入數據的規范 橫著錄入數據&#xff08;橫著一條條錄入數據&#xff09;。 2.使用快捷鍵進行數據錄入 tab 鍵和 enter 鍵。 tab 鍵&#xff1a;向右移動一個單元格。 tab 鍵…

C++類與對象-3.23筆記

今天學習了類的概述和寫類的基本框架 在嗶哩嗶哩學習的這個老師的C面向對象高級語言程序設計教程&#xff08;118集全&#xff09;講的很不錯&#xff08;真的&#xff01;&#xff01;&#xff01;&#xff09;&#xff0c;C語言也是在這個老師的帶領下學習的 #include<io…