下面我以簡單的兩臺node伺服器來說明如何使用nginx進行前端跨域訪問。
- node1伺服器 在localhost:8083上啟動
const app = express();
app.get('/web/users',(req, res)=>{
res.json([{name:"張三",age:12},{name:"李四",age:14}]);
res.end()
})
app.listen(process.env.PORT || 8083);
複製程式碼
同域下的前端程式碼只需呼叫
function getUsers() {
var xhr=new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8083/web/users');
xhr.send(null);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}else {
alert(xhr.statusText);
}
}
}
複製程式碼
這裡有一點需要關注的是,前後端程式碼處在同一個域下,xhr.open() url路徑寫成下面這樣也是可以的,它會預設請求到http://localhost:8083/web/users
xhr.open('GET', '/web/users');
複製程式碼
下面我們將node1伺服器中的web/users介面刪除:
const app = express();
app.listen(process.env.PORT || 8083);
複製程式碼
前端此時自然無法訪問後臺的web/users了,將報一個404錯誤。
下面增加一個node2伺服器,在localhost:8085上啟動,同時我們將原先在8083上刪除的web/users介面搬遷到8085上:
const app = express();
app.get('/web/users',(req, res)=>{
res.json([{name:"張三",age:12},{name:"李四",age:14}]);
res.end()
})
app.listen(process.env.PORT || 8085);
複製程式碼
由於8085實現了這個介面,我們嘗試在原先8083埠下的ajax呼叫它試試:
xhr.open('GET', 'http://localhost:8085/web/users');
複製程式碼
如我們所料,瀏覽器阻止了此次行為,並丟擲一個跨域錯誤。
難道就無法訪問那個介面了嗎?其實伺服器之間和伺服器之間是可以相互呼叫的,阻止跨域訪問只是在瀏覽器端做的限制而已。
下面我通過兩種方式來實現如何訪問到8085上的web/users介面。
1 . node直接作為代理訪問
原理就是交由8083後端去訪問8085埠介面,訪問完成交給前端
8083node後端實現程式碼:
npm install request --save // 需要安裝一個http request模組
複製程式碼
const app = express()
const request = require('request')
// 訪問此介面時通過request模組去訪問8085 再返回給前端。
app.get('/web/users',(req, res)=>{
var url='http://localhost:8085'+req.url
console.log(url) // http://localhost:8085/web/users
req.pipe(request(url)).pipe(res);
})
複製程式碼
2. jsonp方式訪問
就是通過script 的src,向伺服器請求資料,且這不受同源策略限制;然後伺服器將相應的資料放入指定的函式回撥名中,返回給前端。說的有點繞,下面通過例項講解: 8083前端請求8085,這裡已經不再是ajax請求了,而是直接載入8085上資源。
<script>
function getUsers(data) {
alert(data)
}
</script>
<script src="http://localhost:8085/jsonp?callback=getUsers"></script>
複製程式碼
上述程式碼第一個script標籤定義了一個函式getUsers 但是並沒有執行,只是定義了而已,要想有執行能力,需要
getUsers(data)
複製程式碼
所以我們要讓第二個標籤script src="http://localhost:8085/jsonp?callback=getUsers" 返回getUsers(data)內容即可,這樣第一個標籤內定義的函式就可以執行了。返回介面內容只需要放到函式引數裡即可
後臺8085實現:
const app = express();
const querystring=require('querystring')
const url=require('url')
// 處理前端jsonp請求
app.get('/jsonp',(req,res)=>{
var qs = querystring.parse(req.url.split('?')[1]); //{callback:'getUsers'}
var users=JSON.stringify([{name:"張三",age:12},{name:"李四",age:14}]) // 注意需要傳成字串格式
var callback=`${qs.callback}(${users})`
res.end(callback)
})
複製程式碼
前端返回
是不是有點黑魔法的味道!但是缺點也是明顯的,首先通過此方式有一定安全性的,通過callback後加一些亂七八糟的東西可能會有xss攻擊,最主要的是jsonp不支援post方法。
3 .nginx反向代理器
此方式即類似於第一種node代理方式,也是通過伺服器和伺服器之間通訊,只是不需要8083下後臺伺服器自己去訪問8085,而是專門交給nginx,為什麼?姑且認為nginx更加專業吧! nginx配置
server {
listen 8007; # nginx啟動埠,需要訪問這個埠才能夠代理
server_name localhost:8083; # 需要代理的伺服器
location / { # 如果你訪問127.0.0.1/8002/的話nginx去請求
proxy_pass http://localhost:8083;
}
location /web { #訪問/web/aa時會對映成http://localhost:8085/web/aa;
proxy_pass http://localhost:8085;
}
}
複製程式碼
8083請求路徑
xhr.open('GET', '/web/users');
複製程式碼
未完待續...