在先後端分離的開發中,前端的靜態資源存於本機上,經過 localhost 訪問,若是直接調用服務端 api 則會由於跨域的問題不能正常訪問。解決跨域問題能夠經過 JSONP 或者讓服務端設置 Access-Control-Allow-Origin
解除限制。可是並非全部接口均可以這麼搞的,因此通常須要前端本身配置代理來解決跨域問題。javascript
最近接手了一個項目,代理配置過程頗有意思,記錄下來。簡單描述下場景:projectA
是一個普通的頁面,但裏面部分區域和部分彈層是經過 iframe 的形式引用的 projectB
,並且後端接口限制出於安全考慮 只接受來自指定域名 (*.server.com
) 的請求,對於來自 localhost 或者 IP 的請求會被直接重定向至 server 域的登錄接口(server.com/login
)。須要同時啓動 projectA
(localhost:8087)和 projectB
(localhost:8085)兩個項目。前端
前端配置代理最經常使用的就是利用webpack的devServer.proxy了。java
我首先嚐試的是在 projectA
的 devServer 中這樣配置:webpack
devServer: {
proxy: {
'/api': { // 須要直接代理到線上環境的接口
target: 'http://ad.server.com',
changeOrigin: true,
headers: {
// 後端要校驗請求源,那改下 host 或者 origin 不就美滋滋了?
Host: 'ad.server.com',
Origin: 'ad.server.com'
},
},
'/apitest': { // 須要與後端聯調的接口
target: '10.8.0.1:9909',// 後端本地開發環境
},
'/iframe': {
target: 'http://localhost:8085',
}
// 另外還有 iframe 裏的 api 調用指向線上環境
}
}
複製代碼
然而,後端接口殘酷地給跳轉到登錄接口去了 😭。猜測一下可能後端的接口是經過 cookie 來判斷當前登錄域的,從 localhost 過去的請求不帶 cookie。後來嘗試發如今 proxy的headers裏再增長 cookie 便可破跳轉,可是請求過去返回結果仍是在報錯,後端表示仍然是認證失敗。nginx
既然從 localhost 訪問不行那隻好就從 server.com 這個域來訪問了。簡單的作法就是利用瀏覽器插件 SwitchyOmega
配置代理。即 http://ad.server.com/*
的全部請求所有指向 localhost8087, http://ad.server.com/iframe/*
的請求所有指向 localhost8085, 而後將 api 的部分拎出來直接代理回線上。git
坑爹的是有的靜態資源也不須要被代理到本地,例如 http://ad.server.com/static/*
本地可能根本就沒有,得從新指回到線上。這時候 iframe 裏的 projectB 又開始做妖了,裏面的靜態資源存於好幾個目錄,得挨着挨着配置,最後出來的完整配置就變得無比長。github
SwitchyOmega
既能夠對全局進行代理設置,也能夠對單獨域進行設置(點開 SwitchyOmega
看到下面那個漏斗即是)。這就致使了個人噩夢:期間我在作其餘項目的時候進行一些小流量測試也是在用這個 SwitchyOmega
代理,也會涉及到對 server.com
域的修改,幾番折騰後已經分不清到底當前是在全局代理仍是對單獨域代理了(並且實際項目中不止 server.com
這一個域),每日疑惑即是:「如今到底把哪一個域代理到哪去了?」web
爲了不這種困惑最後只能左手一個 Chrome,右手一個 Canary(Chrome 的開發版),兩個不一樣瀏覽器分別獨立的 SwitchyOmega
配置。後端
後來感受用 SwitchyOmega
這種上網工具來作開發不太專業,並且切換瀏覽器來代理的作法也實在不方便,就改用 Charels
。開啓代理後利用其 Map Remote
功能,能夠配置具體哪些請求代理到哪一個地方去。由於其界面是圖形化的,功能也比較強大,把 SwitchyOmega
裏的配置抄一份過來即可用了。比 SwitchyOmega
相比,不用再把本就應該代理到線上的靜態資源再寫一遍,因此配置會少一些。api
最後讓我放棄 Charles 的緣由是:實在太卡了 😭。同時配置了多個 url 代理的狀況下,電腦風扇轉得飛起,請求一個被代理了的 url 半天回不告終果。並且 SwitchyOmega
和 Charles
都不能批量複製修改,得一個一個在圖形界面改,有的時候就很麻煩(好比將線上環境切到後端的開發環境)。
想更靈活地複製修改配置,固然最理想的就是一個可編輯的配置文件了。Nginx
正好能夠很是方便的修改配置文件,並且本地啓一個 Nginx
進程不會像 Charels
那麼耗資源。最後配置出來的 Nginx
大概長這個樣子:
http:{
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream localhost8083 {
server 127.0.0.1:8083;
keepalive 2000;
}
upstream localhost8087 {
server 127.0.0.1:8087;
keepalive 2000;
}
upstream rd {
server 10.8.0.1:9909;
keepalive 2000;
}
upstream server {
server ad.server.com;
keepalive 2000;
}
server {
listen 80;
# api接口用於和後端開發聯調
location ^~ /api/{
proxy_pass http://rd;
proxy_set_header Host $host:$server_port;
}
# 代理 projectA 的頁面
location ~ /(path1|path2|path3)/ {
proxy_pass http://localhost8087;
proxy_set_header Host $host:$server_port;
}
# 代理 projectA 的靜態資源
location ^~ /projectA_static/ {
proxy_pass http://localhost8087;
proxy_set_header Host $host:$server_port;
}
# 代理 projectA 的 hot-update
location ~ \.hot-update.js$ {
proxy_pass http://localhost8087;
proxy_set_header Host $host:$server_port;
}
# 代理 projectB 的 iframe 頁面
location ~ /(path_iframe1|path_iframe2|path_iframe3) {
proxy_pass http://localhost8085;
proxy_set_header Host $host:$server_port;
}
# 代理 projectB 的靜態資源
location ^~ /projectB_static/ {
proxy_pass http://localhost8085;
proxy_set_header Host $host:$server_port;
}
# 剩下的請求正常走 server.com 線上環境
location / {
proxy_pass http://server;
proxy_set_header Host server;
}
}
複製代碼
利用 Nginx
靈活的規則,能夠合併一些類似的代理規則,不用像配置 Charles
那樣得一個一個本身粘貼了。另外還有個好處就是能夠靈活管理本身的代理環境, 若是從此再有像這種代理比較麻煩的項目,能夠分別拆成兩個 nginx.conf
文件,使用時指定用哪一個 conf 文件便可。若是用 Charles
管理的話,全部代理都一個配置列表裏面,代理多了以後會很是難以維護。
不過本機用 Nginx
代理通常得配合改 hosts 文件,在 hosts 文件裏將 test.server.com
(本身瞎編的一個域,這裏知足 *.server.com
就能經過後端的校驗) 指向 localhost便可。啓動 Nginx
指定監聽 80 端口,這樣訪問 test.server.com
的時候(實際上訪問的就是 localhost:80
) 就會被 Nginx
給代理了。配置好了以後,訪問 ad.server.com/
就是線上環境,改爲 test.server.com/
就是本機環境了,無痛切換,很是舒服。
以上幾種辦法都在必定場景下能實現代理的需求。後來發現社區有專門的輪子 xswitch、zan-proxy。不過做爲前端開發,多熟悉下 Charels
和 Nginx
也是個不錯的選擇。