Nginx 配置跨域的實現(xiàn)及常見問題解決
1. 跨域
1.1 同源策略
同源策略(Same-Origin Policy)是瀏覽器的一種安全機制,它限制了不同源之間的資源共享。兩個 URL 被認為是同源的,必須滿足以下三個條件:
- 協(xié)議相同(如 http 或 https)
- 域名相同
- 端口相同
例如:
- 同源:
- http://example.com:8080 和 http://example.com:8080
- 跨域:
- http://example.com:8080 和 http://example.com:3000(端口不同)
- http://example.com 和 https://example.com(協(xié)議不同)
- http://example.com 和 http://api.example.com(域名不同)
1.2 跨域資源共享(CORS)
CORS 是一種機制,通過設置特定的 HTTP 響應頭,允許瀏覽器訪問跨域資源。CORS 頭主要包括:
- **Access-Control-Allow-Origin**:指定允許訪問的源。
- **Access-Control-Allow-Methods**:指定允許的 HTTP 方法(如 GET, POST)。
- **Access-Control-Allow-Headers**:指定允許的請求頭(如 Content-Type, Authorization)。
- **Access-Control-Allow-Credentials**:是否允許攜帶 Cookie 或其他憑證。
- **Access-Control-Max-Age**:預檢請求的緩存時間。
2. Nginx 配置跨域的場景
2.1 場景 1:簡單跨域請求
如果前端發(fā)送的是 簡單請求(如 GET 或 POST,且沒有自定義請求頭),Nginx 只需要在響應中添加跨域頭即可。
2.2 場景 2:復雜跨域請求
如果前端發(fā)送的是 復雜請求(如 POST 請求包含 Content-Type: application/json 或自定義頭 Authorization 等),瀏覽器會先發(fā)起 預檢請求(OPTIONS),詢問服務器是否允許跨域。
Nginx 必須正確處理 OPTIONS 請求,并返回所有必要的跨域頭。
3. Nginx 配置跨域的完整實現(xiàn)
3.1 基礎跨域配置
基礎的 Nginx 跨域配置示例:
server { listen 8081; server_name localhost; # 根目錄(H5 前端文件) root /usr/share/nginx/html/applet/dist/build/h5/; # 跨域配置 location /api/ { # 添加跨域頭 add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always; add_header 'Access-Control-Allow-Credentials' 'true' always; # 如果是預檢請求 (OPTIONS),直接返回成功 if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With'; add_header 'Access-Control-Max-Age' 1800; add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain'; return 204; } # 反向代理到后端服務 proxy_pass url; # 替換為后端服務地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
3.2 配置解析
- Access-Control-Allow-Origin:允許的跨域來源。如果后端需要支持多個來源,可以動態(tài)設置該值;或者使用 * 表示允許所有來源。
- Access-Control-Allow-Methods:聲明支持的 HTTP 方法。
- Access-Control-Allow-Headers:聲明允許的自定義請求頭。如果前端發(fā)送了 Authorization 或其他自定義頭,必須在這里明確聲明。
- Access-Control-Max-Age:指定預檢請求的緩存時間,單位為秒(如 1800 表示緩存 30 分鐘)。
- if ($request_method = 'OPTIONS'):單獨處理預檢請求,直接返回 204,避免請求被轉發(fā)到后端。
- 在 if 判斷中直接返回響應(如 return 204)的情況下,add_header** 需要在同一個 if 塊內聲明**,否則不會被應用到響應中。這里主要是nginx的響應流程和作用域特性。
3.3 動態(tài)配置跨域來源
3.3.1 常規(guī)配置
如果后端需要允許多個特定來源,可以通過 $http_origin 動態(tài)設置 Access-Control-Allow-Origin:
location /api/ { # 動態(tài)設置跨域來源 set $cors ""; if ($http_origin ~* (http://ip:port|http://example.com)) { set $cors $http_origin; } add_header 'Access-Control-Allow-Origin' $cors always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always; add_header 'Access-Control-Allow-Credentials' 'true' always; # 如果是預檢請求 (OPTIONS),直接返回成功 if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' $cors always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With'; add_header 'Access-Control-Max-Age' 1800; add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain'; return 204; } proxy_pass bakcendurl; }
3.3.2 進階配置
Nginx 提供了 map
指令,可用于根據請求條件動態(tài)設置變量。利用map
指令提前設置變量,避免 if 指令的復雜嵌套,更安全地實現(xiàn)動態(tài)跨域邏輯。
# 動態(tài)設置允許的跨域來源 map $http_origin $cors_origin { default ""; "~^https?://trusteddomain1\.com$" $http_origin; "~^https?://trusteddomain2\.com$" $http_origin; } # 動態(tài)設置緩存時間 map $http_origin $cors_max_age { default "0"; "~^https?://trusteddomain1\.com$" "86400"; # 1 天 "~^https?://trusteddomain2\.com$" "3600"; # 1 小時 } server { listen 8081; server_name localhost; location ~* ^/(url|url1|……) { add_header 'Access-Control-Allow-Origin' "$cors_origin" always; add_header 'Vary' 'Origin' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always; add_header 'Access-Control-Max-Age' "$cors_max_age" always; # 特殊處理 OPTIONS 預檢請求 if ($request_method = 'OPTIONS') { # 設置 CORS 響應頭 add_header 'Access-Control-Allow-Origin' "$cors_origin" always; add_header 'Vary' 'Origin' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always; add_header 'Access-Control-Max-Age' "$cors_max_age" always; add_header 'Content-Length' '0' always; add_header 'Content-Type' 'text/plain' always; return 204; } # 其他請求正常代理到后端服務 proxy_pass backendurl; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 1024m; proxy_buffer_size 1024k; proxy_buffers 16 1024k; proxy_busy_buffers_size 2048k; proxy_temp_file_write_size 2048k; } }
測試命令:
curl -X OPTIONS http://localhost:8081/api/test \ -H "Content-Type: application/json" \ -H "Origin: https://trusteddomain1.com" \ -H "Authorization: Bearer null" \ -I
結果:
改為第二個域名,輸出結果:
配置成功。
4. 驗證跨域配置是否生效
4.1 使用 curl 驗證
預檢請求
運行以下命令,檢查 OPTIONS 請求的響應頭是否包含正確的跨域頭:
curl -X OPTIONS http://localhost:8081/api/test-endpoint \ -H "Origin: yoururl" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: Content-Type, Authorization" -I
實際請求
運行以下命令,檢查實際請求的跨域頭:
curl -X POST http://localhost:8081/api/test-endpoint \ -H "Origin: yoururl" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{"key":"value"}' -I
將Origin的值替換即可。
5. 常見問題及解決方法
5.1 No 'Access-Control-Allow-Origin' header is present on the requested resource
- 原因:后端未返回 Access-Control-Allow-Origin。
- 解決:檢查 Nginx 或后端服務是否返回了正確的跨域頭。
5.2 Request header field <header_name> is not allowed by Access-Control-Allow-Headers
- 原因:前端發(fā)送了未被允許的自定義請求頭。
- 解決:在 Access-Control-Allow-Headers 中添加該頭(如 Authorization, channel 等)。
5.3 OPTIONS 請求返回 404 或 405
- 原因:Nginx 或后端未正確處理 OPTIONS 請求。
- 解決:在 Nginx 配置中使用 if ($request_method = 'OPTIONS') 單獨處理預檢請求。
6. 注意事項
(1) 不建議長期使用通配符 *
- 如果前端需要發(fā)送 Authorization 或 Cookie,不能使用通配符 *,需要指定具體的跨域來源:
add_header 'Access-Control-Allow-Origin' 'http://ip:port' always; add_header 'Access-Control-Allow-Credentials' 'true' always;
(2) 確保前端請求頭與后端配置匹配
- 如果前端發(fā)送了自定義頭(如 channel),后端的 Access-Control-Allow-Headers 必須包含這些頭。
(3) 確保后端不會覆蓋 Nginx 的跨域頭
- 如果后端服務也返回了跨域頭,可能會覆蓋 Nginx 的配置。可以通過 proxy_hide_header 移除后端返回的頭:
proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Access-Control-Allow-Methods; proxy_hide_header Access-Control-Allow-Headers;
7. 總結
- CORS 的核心在于配置正確的跨域頭(Access-Control-Allow-*)。
- Nginx 配置跨域的關鍵點:
- 處理預檢請求(OPTIONS)。
- 添加必要的跨域頭(Access-Control-Allow-Origin, Access-Control-Allow-Headers 等)。
- 確保跨域頭在所有響應中生效(使用 always 參數(shù))。
- 使用工具(如 curl 或瀏覽器開發(fā)者工具)驗證跨域配置是否正確。
到此這篇關于Nginx 配置跨域的實現(xiàn)及常見問題解決的文章就介紹到這了,更多相關Nginx 配置跨域內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
nginx 配置虛擬主機,實現(xiàn)在一個服務器可以訪問多個網站的方法
下面小編就為大家分享一篇nginx 配置虛擬主機,實現(xiàn)在一個服務器可以訪問多個網站的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12Linux\Nginx 環(huán)境下虛擬域名配置及測試驗證
這篇文章主要介紹了Linux\Nginx 虛擬域名配置及測試驗證的步驟詳解,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-11-11nginx connect() to unix:/var/run/php-fpm.sock failed (11: Re
這篇文章主要介紹了nginx connect() to unix:/var/run/php-fpm.sock failed (11: Resource temporarily unavailable),需要的朋友可以參考下2015-01-01