一、項目背景簡介
如果你是在使用Vue在做前端項目,那么你肯定對Vue和Node的組合不陌生。無論是在實際的項目中還是我們自己做的Demo中,但凡涉及到API接口請求,都會接觸到 跨域 這一技術(shù)名詞。
這篇博客介紹的是如何在Vue + Node項目中解決跨域請求的問題,博客中會介紹兩種跨域的設(shè)置方案,即前端跨域設(shè)置和后端跨域設(shè)置。
什么是跨域以及跨域的相關(guān)解決方案,相信你多多少少都知道點,畢竟這是前端面試題目中常問到的。這里我就假設(shè)大家已經(jīng)知道什么是跨域了,如果你對跨域還不是很了解,可以在簡書或CSDN搜索跨域相關(guān)問題。
其他的不多說,直接開始吧!
二、前端設(shè)置跨域
首先我們先說一下如何在前端設(shè)置跨域,其實準確來說應(yīng)該是在前端設(shè)置 跨域代理 。在前端設(shè)置跨域的時候,我們是在Webpack中進行配置。需要說明的是: Vue-cli 2.x 版本和 Vue-cli 3.0 版本在Webpack的配置上有些不同,我們這里以 Vue-cli 3.0 為例進行介紹:
如果你之前做過Webpack的相關(guān)配置,那么在你項目的根目錄中肯定會有一個名為 vue.config.js 的文件,如果沒有,那就新建一個。注意該文件是在項目的根目錄中,也就是和 src文件夾 同級文件夾。

然后直接復(fù)制下面這些代碼到你的 vue.config.js 文件中,下面對這些代碼進行說明。
module.exports = {
// 配置跨域代理
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8081', // 你自己的api接口地址
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': '/api/',
}
}
}
}
};
上面的代碼等同于一下代碼:
module.exports = {
// 配置跨域代理
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8081/api', // 你自己的api接口地址
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': '',
}
}
}
}
};
在上述的配置中,我們可以看到兩種配置方式的些許不同,這說明跨域代理最終匹配到的api地址是由 target 和 pathRewrite 兩個屬性共同決定的。
我們在前端設(shè)置完成代理之后,就可以跨域請求了,比如下面使用 axios 進行請求的一個例子:
import axios from 'axios';
export default {
data() {
return {}
},
created() {
axios({
method: 'get',
url: "/api/goods"
}).then(data => {
console.log(data);
});
}
};
在我的項目中,前端的端口是 0802 ,后端的端口是 0801 , 我們可以看到上面我們請求的url是 /api/goods ,經(jīng)過前端跨域代理的處理之后,最終訪問的url是http://localhost:8081/api/goods,這樣的話,就解決了跨域的問題。
但是需要注意的是,如果這個時候你在開發(fā)者工具中查看自己請求的api地址的時候,看到的是http://localhost:8082/api/goods ,但是不要慌,這是沒錯的,因為跨域代理是在后臺對api地址進行重定向的。

三、后端設(shè)置跨域
如果你想問:在前端不進行設(shè)置跨域行不行,感覺好麻煩,我就是想簡簡單單的請求一個自己寫的api,有沒有其他的辦法。辦法是有的,也就是下面要說的在后端設(shè)置跨域請求。
比如我們在后端使用Node寫了一個api,在該api之前進行跨域設(shè)置,使得在所有域中都可以訪問api,代碼如下:
var express = require('express');
var app = express();
// api 返回的結(jié)果
const goods = {
name: "goods",
weight: 200
};
// 設(shè)置跨域
app.all("*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*"); //設(shè)置允許跨域的域名,*代表允許任意域名跨域
res.header("Access-Control-Allow-Headers", "content-type"); //允許的header類型
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS"); //跨域允許的請求方式
if (req.method.toLowerCase() == 'options')
res.send(200); //讓options嘗試請求快速結(jié)束
else
next();
});
app.get('/api/goods', (req, res) => {
res.json({
errno: 200,
data: goods
});
});
var server = app.listen(8081, () => {
var host = server.address().address;
var port = server.address().port;
console.log('Server is running at: http://%s:%s', host, port);
})
這樣一來,我們就可以在自己的項目中,請求這個api了,但是要注意的是,這個時候我們需要使用該api的 絕對路徑 ,比如下面的請求實例:
import axios from 'axios';
export default {
data() {
return {}
},
created() {
axios({
method: 'get',
url: "http://localhost:8081/api/goods"
}).then(data => {
console.log(data);
});
}
};
四、總結(jié)
通過上面的介紹,我們知道現(xiàn)在有兩種配置跨域的方法,那么你可能想問在項目中要使用哪一個呢?
我的建議是:兩個同時使用。前端使用跨域代理,能夠讓我們簡化我們的api請求路徑。
后端設(shè)置跨域,可以讓我們的api更加便捷,避免出現(xiàn)跨域請求的問題。同時你也可以在后端跨域的設(shè)置中,根據(jù)實際需求決定在哪些域中可以請求自己寫的api,這樣更加安全。