前言
大家好,我是老馬。很高興遇到你。
我們為 java 開發者實現了 java 版本的 nginx
https://github.com/houbb/nginx4j
如果你想知道 servlet 如何處理的,可以參考我的另一個專案:
手寫從零實現簡易版 tomcat minicat
手寫 nginx 系列
如果你對 nginx 原理感興趣,可以閱讀:
從零手寫實現 nginx-01-為什麼不能有 java 版本的 nginx?
從零手寫實現 nginx-02-nginx 的核心能力
從零手寫實現 nginx-03-nginx 基於 Netty 實現
從零手寫實現 nginx-04-基於 netty http 出入參最佳化處理
從零手寫實現 nginx-05-MIME型別(Multipurpose Internet Mail Extensions,多用途網際網路郵件擴充套件型別)
從零手寫實現 nginx-06-資料夾自動索引
從零手寫實現 nginx-07-大檔案下載
從零手寫實現 nginx-08-範圍查詢
從零手寫實現 nginx-09-檔案壓縮
從零手寫實現 nginx-10-sendfile 零複製
從零手寫實現 nginx-11-file+range 合併
從零手寫實現 nginx-12-keep-alive 連線複用
從零手寫實現 nginx-13-nginx.conf 配置檔案介紹
從零手寫實現 nginx-14-nginx.conf 和 hocon 格式有關係嗎?
從零手寫實現 nginx-15-nginx.conf 如何透過 java 解析處理?
從零手寫實現 nginx-16-nginx 支援配置多個 server
從零手寫實現 nginx-17-nginx 預設配置最佳化
從零手寫實現 nginx-18-nginx 請求頭+響應頭操作
從零手寫實現 nginx-19-nginx cors
從零手寫實現 nginx-20-nginx 佔位符 placeholder
從零手寫實現 nginx-21-nginx modules 模組資訊概覽
從零手寫實現 nginx-22-nginx modules 分模組載入最佳化
從零手寫實現 nginx-23-nginx cookie 的操作處理
從零手寫實現 nginx-24-nginx IF 指令
HTTP CORS 是什麼?
HTTP CORS(Cross-Origin Resource Sharing,跨源資源共享)是一種安全機制,它允許一個網頁(執行在瀏覽器中的網頁)去請求另一個不同源(域名、協議或埠不同)的資源。
想象一下,網際網路上的每個網站都有自己的“家”,並且通常只能訪問自己家裡的東西。
但是,有時候一個網站需要訪問另一個網站的資料或資源,比如圖片、影片或API。如果沒有CORS,這種訪問是不被允許的,因為瀏覽器出於安全考慮會阻止這種跨源請求。
CORS機制允許網站“告訴”瀏覽器,它信任哪些外部網站,並允許它們訪問自己的資源。
這樣,當一個網站請求另一個網站資源時,瀏覽器會檢查這個請求是否被允許。如果允許,瀏覽器就會允許這次請求,否則會阻止。
簡單來說,CORS就像是一個“通行證”,它讓不同的網站之間可以安全地共享資源。
為什麼需要 HTTP CORS?
HTTP CORS(跨源資源共享)之所以需要,主要是為了保護使用者和網站資料的安全,同時也提供了一種機制來允許安全地跨網站訪問資源。
為什麼需要CORS:
想象一下,你有一個自己的圖書館(網站A),而你的朋友有一個不同的圖書館(網站B)。通常,你只能借閱你自己圖書館裡的書籍,不能直接去朋友圖書館借書。這是因為每個圖書館都有自己的規則和隱私政策,它們不希望其他人隨意訪問自己的書籍。
但是,有時候你需要借閱朋友圖書館裡的一本書,這時候就需要一種機制來確保這個過程是安全的。CORS就相當於是一張“借書證”,它允許你的朋友圖書館知道你想要借書,並且決定是否允許你借閱。
如果沒有CORS這樣的機制,任何圖書館的人都可以隨意去其他圖書館借書,這可能會導致一些問題:
-
隱私問題:圖書館的書籍可能包含敏感資訊,不應該被未經授權的人訪問。
-
安全問題:如果有人惡意訪問圖書館,可能會造成書籍損壞或資訊洩露。
-
管理問題:圖書館需要能夠控制誰可以借閱書籍,以及借閱的條件。
透過CORS,網站可以明確哪些外部網站是可信的,並且可以設定規則來控制它們如何訪問資源。
這樣,既保護了網站的資源不被濫用,又允許了安全的跨網站互動,比如社交媒體登入、API呼叫等。
簡而言之,CORS是網路安全和資源共享之間的一個平衡點。
開發過程中遇到了 CORS 限制,如何解決?
遇到CORS(跨源資源共享)限制時,通常有以下幾種解決方法,分別針對後端、前端和瀏覽器:
後端解決方法
-
設定Access-Control-Allow-Origin響應頭:
在伺服器響應中新增Access-Control-Allow-Origin
頭,指定允許訪問的源。例如,如果你想允許所有源訪問你的資源,可以設定為*
(不推薦,因為不安全):Access-Control-Allow-Origin: *
或者指定具體的源:
Access-Control-Allow-Origin: https://www.example.com
-
處理預檢請求(Preflight Request):
對於某些型別的請求,瀏覽器會先傳送一個預檢請求(OPTIONS請求),詢問伺服器是否允許實際的請求。伺服器需要正確響應這個OPTIONS請求,並在響應中包含必要的CORS頭資訊。 -
設定其他CORS相關的響應頭:
Access-Control-Allow-Methods
:指定允許的HTTP方法,如GET, POST等。Access-Control-Allow-Headers
:指定允許的自定義請求頭。Access-Control-Allow-Credentials
:如果需要攜帶憑證(如cookies),則需要設定為true
。Access-Control-Max-Age
:指定預檢請求的快取時間。
前端解決方法
-
使用代理伺服器:
在開發過程中,可以透過設定一個代理伺服器來繞過CORS限制。
例如,使用Webpack的devServer.proxy配置或Node.js的http-proxy-middleware。
-
使用CORS代理服務:
對於一些簡單的請求,可以使用公共的CORS代理服務,如https://cors-anywhere.herokuapp.com/
。 -
同源策略:
確保前端應用和後端服務部署在同一源(相同的協議、域名和埠)。
Chrome 瀏覽器解決方法
老馬推薦直接修改啟動引數:
修改啟動引數
你可以使用 --disable-web-security
引數來啟動 Chrome,這樣可以禁用瀏覽器的同源策略和 CORS 安全特性,從而允許跨域請求。
例如,可以在命令列中使用以下引數來啟動 Chrome:
chrome.exe --user-data-dir="D://Chrome dev session" --disable-web-security
此外,還可以透過設定 --args
引數來實現類似的效果,如搜尋結果[3]所示:
--args --disable-web-security --user-data-dir=D:\HaoroomsChromeUserData
或者在 macOS 上使用以下命令:
open -n /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir=/Users/Eric/MyChromeDevUserData/
請注意,這些方法僅適用於開發環境,不推薦在生產環境中使用,因為這會降低瀏覽器的安全性。
此外,如果遇到跨域 cookies 問題,還可以透過訪問 chrome://flags
並禁用 SameSite by default cookies
和 Cookies without SameSite must be secure
選項來解決[3]。
其他方式:
-
使用Chrome擴充套件:
安裝一些允許CORS的Chrome擴充套件,如Allow CORS: Access-Control-Allow-Origin
。 -
開發者工具中的CORS禁用:
在Chrome的開發者工具中,可以臨時禁用CORS限制。
但是,這種方法只適用於開發和測試,不應用於生產環境。
- 開啟Chrome的開發者工具。
- 點選“Network”(網路)標籤。
- 在右側的“Request Blocking”(請求攔截)部分,勾選“Disable cache”(禁用快取)和“Disable CORS”(禁用CORS)。
注意
- 安全考慮:在生產環境中,不建議使用萬用字元
*
來設定Access-Control-Allow-Origin
,因為這可能會帶來安全風險。 - 預檢請求:對於需要傳送額外頭資訊(如自定義頭)或使用非簡單方法(如PUT、DELETE等)的請求,伺服器必須正確處理OPTIONS預檢請求。
- 憑證支援:如果需要跨域請求時攜帶cookies或認證資訊,確保伺服器設定了
Access-Control-Allow-Credentials: true
,並且前端請求時需要使用withCredentials: true
。
透過上述方法,可以解決開發過程中遇到的CORS限制問題。
nginx 是如何支援 CORS 設定的?
Nginx 是一個流行的 Web 伺服器和反向代理伺服器,它可以透過配置檔案來支援 CORS 設定。
以下是如何在 Nginx 配置檔案中設定 CORS 的一些示例。
基本 CORS 設定
如果你想允許所有來源的跨域請求,可以在 Nginx 配置檔案中新增以下行:
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000;
}
允許特定來源的 CORS 設定
如果只想允許特定的域名進行跨域請求,可以將 *
替換為具體的域名:
location / {
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000;
}
處理預檢請求
對於需要預檢的請求(如帶有自定義頭或使用非簡單HTTP方法的請求),Nginx 需要正確響應 OPTIONS 請求:
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'DAV' 1;
return 204;
}
應用到特定路徑
你可以將 CORS 設定應用到特定的路徑或位置塊:
location /api/ {
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000;
}
注意事項
- 確保 CORS 相關的
add_header
指令在 Nginx 配置檔案的適當位置,通常是在server
或location
塊中。 - 根據你的應用需求,可能需要調整
Access-Control-Allow-Methods
和Access-Control-Allow-Headers
的值。 - 如果你的應用需要處理預檢請求,確保正確配置
OPTIONS
請求的處理。 - 重啟 Nginx 服務以使配置更改生效。
透過這些配置,Nginx 可以支援跨源資源共享,從而允許前端應用從不同的源安全地請求後端服務。
小結
本節我們實現了 cors,這個對於瀏覽器安全和日常開發幫助比較大。
我們給出了常見的解決方案,不過實際生產注意使用安全。
下一節,我們考慮實現一下 cors 的支援。
我是老馬,期待與你的下次重逢。
開源地址
為了便於大家學習,已經將 nginx 開源
https://github.com/houbb/nginx4j