前端跨域问题解决方案汇总
下面我以簡(jiǎn)單的兩臺(tái)node服務(wù)器來(lái)說(shuō)明如何使用nginx進(jìn)行前端跨域訪問(wèn)。
同域下的前端代碼只需調(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);}} } 復(fù)制代碼這里有一點(diǎn)需要關(guān)注的是,前后端代碼處在同一個(gè)域下,xhr.open() url路徑寫(xiě)成下面這樣也是可以的,它會(huì)默認(rèn)請(qǐng)求到http://localhost:8083/web/users
xhr.open('GET', '/web/users'); 復(fù)制代碼下面我們將node1服務(wù)器中的web/users接口刪除:
const app = express(); app.listen(process.env.PORT || 8083); 復(fù)制代碼前端此時(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); 復(fù)制代碼由于8085實(shí)現(xiàn)了這個(gè)接口,我們嘗試在原先8083端口下的ajax調(diào)用它試試:
xhr.open('GET', 'http://localhost:8085/web/users'); 復(fù)制代碼如我們所料,瀏覽器阻止了此次行為,并拋出一個(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)代碼:
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> 復(fù)制代碼上述代碼第一個(gè)script標(biāo)簽定義了一個(gè)函數(shù)getUsers 但是并沒(méi)有執(zhí)行,只是定義了而已,要想有執(zhí)行能力,需要
getUsers(data) 復(fù)制代碼所以我們要讓第二個(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):
前端返回
是不是有點(diǎn)黑魔法的味道!但是缺點(diǎn)也是明顯的,首先通過(guò)此方式有一定安全性的,通過(guò)callback后加一些亂七八糟的東西可能會(huì)有xss攻擊,最主要的是jsonp不支持post方法。
3 .nginx反向代理器
此方式即類似于第一種node代理方式,也是通過(guò)服務(wù)器和服務(wù)器之間通信,只是不需要8083下后臺(tái)服務(wù)器自己去訪問(wèn)8085,而是專門(mén)交給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;}} 復(fù)制代碼8083請(qǐng)求路徑
xhr.open('GET', '/web/users'); 復(fù)制代碼3 CORS
CORS全稱是跨域資源共享 是一個(gè)W3C標(biāo)準(zhǔn),它規(guī)定瀏覽器允許發(fā)送ajax到不同域下的服務(wù)器來(lái)獲取數(shù)據(jù),從而克服了原來(lái)限制,使用CORS需要前后端都支持,現(xiàn)代瀏覽器基本上都支持。具體CORS的知識(shí)可以參考阮一峰博客 www.ruanyifeng.com/blog/2016/0…
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();} }); 復(fù)制代碼或者使用現(xiàn)成的CORS模塊
npm install cors 復(fù)制代碼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') }) 復(fù)制代碼如有不正確,請(qǐng)指正^_^
總結(jié)
以上是生活随笔為你收集整理的前端跨域问题解决方案汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 像数据科学家一样思考:12步指南(上)
- 下一篇: 2017年html5行业报告,云适配发布