利用 Nginx 反向代理解決跨域問題
上篇 JSONP 的文章裡提到過利用 Nginx 也可以解決跨域問題。趁著自己以前沒有接觸過 Nginx,熟悉了一下,順帶寫了一個非常非常簡單的 demo 實驗下。
正向代理和反向代理
提到代理,肯定要說一下這兩個的區別。
舉個正向代理的例子:我打球累了走不動了,找看球的小朋友幫我去旁邊的商店買瓶水。商店老闆是不知道到底是誰需要喝水的,隱藏了客戶端。當然,小朋友可以告訴老闆就是那個打球像蔡徐坤的人要喝水。還有,VPN 就是正向代理。
反向代理的例子:我打球累了,找看球的小朋友要瓶水喝(當然我肯定會給錢的:D)。我不需要知道小朋友的水是從旁邊的商店還是兩公里外的超市買的。隱藏了服務端。還有,我們連好了 VPN 訪問谷歌的時候,瀏覽的那些頁面,我們是不會知道具體是哪臺伺服器的資源。
具體步驟
服務介面
既然請求,肯定需要先寫一個服務介面,我們用 node 起一個服務:
// index。js
const
http
=
require
(
‘http’
);
const
fs
=
require
(
‘fs’
);
const
url
=
require
(
‘url’
);
const
server
=
http
。
createServer
(
function
(
req
,
res
)
{
if
(
req
。
url
===
‘/favicon。ico’
)
{
return
;
}
const
parseUrl
=
url
。
parse
(
req
。
url
,
true
);
console
。
log
(
‘parseUrl’
,
parseUrl
。
pathname
)
if
(
parseUrl
。
pathname
===
‘/api/getList’
)
{
const
list
=
{
‘a’
:
1
,
‘b’
:
2
}
res
。
writeHead
(
200
,
{
‘content-Type’
:
‘text/html;charset=UTF-8’
})
res
。
end
(
JSON
。
stringify
(
list
))
}
else
{
res
。
write
(
`
port: 666
`
)
res
。
end
()
}
});
server
。
listen
(
666
,
function
()
{
console
。
log
(
‘server is starting on port 666’
);
});
我們來訪問一下,可以拿到資料了。
測試頁面
然後,我們寫一個簡單的 ajax 請求頁面。你可以本地用
http-server
啟動訪問下,可以發現請求跨域了:
<
html
>
<
head
>
<
title
><
/title>
<
/head>
<
body
>
<
button
onclick
=
“sendAjax()”
>
sendAjax
<
/button>
<
script
type
=
“text/javascript”
>
var
sendAjax
=
()
=>
{
var
xhr
=
new
XMLHttpRequest
();
xhr
。
open
(
‘GET’
,
‘http://localhost:666/api/getList’
,
true
);
xhr
。
send
();
xhr
。
onreadystatechange
=
function
(
e
)
{
if
(
xhr
。
readyState
==
4
&&
xhr
。
status
==
200
)
{
console
。
log
(
xhr
。
responseText
);
}
};
}
<
/script>
<
/body>
<
/html>
安裝 Nginx
這個時候,你可以透過設定響應頭來允許跨域。或者用 Nginx 來解決這個問題了。首先肯定需要安裝 Nginx。這個按照對應的平臺安裝就行了。
brew update
brew install nginx
nginx
nginx -s reload // 重啟
配置
然後我們配置一下代理,這個意思就是我們請求中有 api 這樣的就會代理到 http://127。0。0。1:666,所以我們只要訪問
http://
localhost:9999/api/getL
ist
這個不跨域的介面,然後就會由伺服器反向代理到 http://localhost:666/api/getList。
listen 9999;
server_name localhost;
#charset koi8-r;
#access_log logs/host。access。log main;
location / {
root html;
index index。html index。htm;
}
location /api/ {
proxy_pass http://127。0。0。1:666;
}
配置好之後我們需要重啟一下 Nginx 服務。注意一點,重啟時可能會報這麼一個錯誤:
nginx: [error] open() “/usr/local/var/run/nginx。pid” failed (2: No such file or directory)
這是
sudo nginx -s stop
這個命令會刪除 pid 檔案,可以執行
sudo nginx
重新新增這個檔案。
測試結果
這個時候,我們不用絕對地址了,我們把ajax請求裡面的介面換成相對地址:
// xhr。open(‘GET’, ‘http://localhost:666/api/getList’, true);
xhr。open(‘GET’, ‘/api/getList’, true);
美滋滋,這就不跨域了呢。
當然,還可以更加真實一點,我們隨便用一個域名測試一下。Nginx 重新配置下:
listen
80
;
server_name
yumingtest
;
#
charset
koi8
-
r
;
#
access_log
logs
/
host
。
access
。
log
main
;
location
/
{
root
html
;
index
index
。
html
index
。
htm
;
}
location
/
api
/
{
proxy_pass
http
:
//127。0。0。1:666;
}
然後在 hosts 檔案裡面新增這條:
127。0。0。1 yumingtest。com
,重啟下 Nginx。
這下是不是更加真實了。關於hosts 檔案的作用,就是我們輸入域名不是要需要經過DNS解析IP嘛,這個裡面就存了一些。首先自動從 Hosts 檔案中尋找對應的 IP 地址,一旦找到,系統會立即開啟對應網頁,如果沒有找到, 則系統再會將網址提交 DNS 域名解析伺服器進行 IP 地址的解析。
還有一個問題,關於 HTTP 502 狀態碼,我是把介面服務停了,於是就報 502了。
也不一定是網上說的什麼
連線超時 我們向伺服器傳送請求 由於伺服器當前連結太多,導致伺服器方面無法給於正常的響應,產生此類報錯
那樣。
(完)
2019。11。30 補充
上面 Hosts 檔案那裡說錯了,輸入域名後並不是先自動從 Hosts 檔案中尋找對應的 IP 地址。而是瀏覽器先從瀏覽器的dns快取中找,找不到再去 hosts檔案中找 :)
下一篇:基金小白應該在哪裡系統入門?