下面我以簡(jiǎn)單的兩臺(tái)node服務(wù)器來(lái)說(shuō)明如何使用nginx進(jìn)行前端跨域訪問(wèn)。
- node1服務(wù)器 在localhost:8083上啟動(dòng)
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);
同域下的前端代碼只需調(diào)用
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);
}
}
}
這里有一點(diǎn)需要關(guān)注的是,前后端代碼處在同一個(gè)域下,xhr.open() url路徑寫(xiě)成下面這樣也是可以的浩螺,它會(huì)默認(rèn)請(qǐng)求到http://localhost:8083/web/users
xhr.open('GET', '/web/users');
下面我們將node1服務(wù)器中的web/users接口刪除:
const app = express();
app.listen(process.env.PORT || 8083);
前端此時(shí)自然無(wú)法訪問(wèn)后臺(tái)的web/users了疹启,將報(bào)一個(gè)404錯(cuò)誤岖免。
下面增加一個(gè)node2服務(wù)器溉浙,在localhost:8085上啟動(dòng)投放,同時(shí)我們將原先在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實(shí)現(xiàn)了這個(gè)接口宏赘,我們嘗試在原先8083端口下的ajax調(diào)用它試試:
xhr.open('GET', 'http://localhost:8085/web/users');
如我們所料绒北,瀏覽器阻止了此次行為,并拋出一個(gè)跨域錯(cuò)誤察署。
難道就無(wú)法訪問(wèn)那個(gè)接口了嗎闷游?其實(shí)服務(wù)器之間和服務(wù)器之間是可以相互調(diào)用的,阻止跨域訪問(wèn)只是在瀏覽器端做的限制而已。
下面我通過(guò)兩種方式來(lái)實(shí)現(xiàn)如何訪問(wèn)到8085上的web/users接口脐往。
1 . node直接作為代理訪問(wèn)
原理就是交由8083后端去訪問(wèn)8085端口接口休吠,訪問(wèn)完成交給前端
8083node后端實(shí)現(xiàn)代碼:
npm install request --save // 需要安裝一個(gè)http request模塊
const app = express()
const request = require('request')
// 訪問(wèn)此接口時(shí)通過(guò)request模塊去訪問(wèn)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方式訪問(wèn)
就是通過(guò)script 的src业簿,向服務(wù)器請(qǐng)求數(shù)據(jù)瘤礁,且這不受同源策略限制;然后服務(wù)器將相應(yīng)的數(shù)據(jù)放入指定的函數(shù)回調(diào)名中梅尤,返回給前端柜思。說(shuō)的有點(diǎn)繞,下面通過(guò)實(shí)例講解:
8083前端請(qǐng)求8085巷燥,這里已經(jīng)不再是ajax請(qǐng)求了赡盘,而是直接加載8085上資源。
<script>
function getUsers(data) {
alert(data)
}
</script>
<script src="http://localhost:8085/jsonp?callback=getUsers"></script>
上述代碼第一個(gè)script標(biāo)簽定義了一個(gè)函數(shù)getUsers 但是并沒(méi)有執(zhí)行缰揪,只是定義了而已陨享,要想有執(zhí)行能力,需要
getUsers(data)
所以我們要讓第二個(gè)標(biāo)簽script src="http://localhost:8085/jsonp?callback=getUsers" 返回getUsers(data)內(nèi)容即可钝腺,這樣第一個(gè)標(biāo)簽內(nèi)定義的函數(shù)就可以執(zhí)行了霉咨。返回接口內(nèi)容只需要放到函數(shù)參數(shù)里即可
后臺(tái)8085實(shí)現(xiàn):
const app = express();
const querystring=require('querystring')
const url=require('url')
// 處理前端jsonp請(qǐng)求
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)
})
前端返回
是不是有點(diǎn)黑魔法的味道!但是缺點(diǎn)也是明顯的拍屑,首先通過(guò)此方式有一定安全性的途戒,通過(guò)callback后加一些亂七八糟的東西可能會(huì)有xss攻擊,最主要的是jsonp不支持post方法僵驰。
3 .nginx反向代理器
此方式即類似于第一種node代理方式喷斋,也是通過(guò)服務(wù)器和服務(wù)器之間通信,只是不需要8083下后臺(tái)服務(wù)器自己去訪問(wèn)8085蒜茴,而是專門交給nginx,為什么星爪?姑且認(rèn)為nginx更加專業(yè)吧!
nginx配置
server {
listen 8007; # nginx啟動(dòng)端口,需要訪問(wèn)這個(gè)端口才能夠代理
server_name localhost:8083; # 需要代理的服務(wù)器
location / { # 如果你訪問(wèn)127.0.0.1/8002/的話nginx去請(qǐng)求
proxy_pass http://localhost:8083;
}
location /web { #訪問(wèn)/web/aa時(shí)會(huì)映射成http://localhost:8085/web/aa;
proxy_pass http://localhost:8085;
}
}
8083請(qǐng)求路徑
xhr.open('GET', '/web/users');
3 CORS
CORS全稱是跨域資源共享 是一個(gè)W3C標(biāo)準(zhǔn)粉私,它規(guī)定瀏覽器允許發(fā)送ajax到不同域下的服務(wù)器來(lái)獲取數(shù)據(jù)顽腾,從而克服了原來(lái)限制,使用CORS需要前后端都支持,現(xiàn)代瀏覽器基本上都支持诺核。具體CORS的知識(shí)可以參考阮一峰博客 http://www.ruanyifeng.com/blog/2016/04/cors.html抄肖。node實(shí)現(xiàn)只需要增加代碼
app.use('*',function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*'); //這個(gè)表示任意域名都可以訪問(wèn),這樣寫(xiě)不能攜帶cookie了窖杀。
//res.header('Access-Control-Allow-Origin', 'http://www.baidu.com'); //這樣寫(xiě)漓摩,只有www.baidu.com 可以訪問(wèn)。
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');//設(shè)置方法
if (req.method == 'OPTIONS') {
res.send(200);
}
else {
next();
}
});
或者使用現(xiàn)成的CORS模塊
npm install cors
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://www.baidu.com',
optionsSuccessStatus: 200
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: '只有百度可以訪問(wèn)'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
如有不正確入客,請(qǐng)指正_