
上篇 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/getList 這個不跨域的接口,然後就會由伺服器反向代理到 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檔案中找 :)