一、跨域分類
跨域分為開發跨域(開發環境跨域)和線上跨域(生產環境跨域):
- 開發環境跨域:開發階段前后端工作站不同,所以ip地址不同,請求數據必然出現跨域問題;
- 生產環境跨域:一個網站關聯多台服務器產生的跨域問題,構成一個完整的生產服務器集群,生產服務器集群之間的通信通過地址的方式通信,就算在局域網中,端口地址也是不一樣的。
二、解決
2.1 線上跨域
線上跨域的常規解決方案:
- 后端代碼上增加一個跨域請求響應頭:Access-Control-Allow-Origin
例如:php中的header(Access-Control-Allow-Origin:*) ;PS:其中,*表示所有請求地址都可允許跨域響應
- 也可以采用 前后端配置處理 的方式:采用jsonp模式,前端完成jsonp請求發送
2.2 開發跨域
即:在開發過程中存在的跨域問題,這種現象一般出現在 前后端分離的項目中:前后端分離導致開發聯調過程中不在同一服務器或端口下,引發的跨域。
開發階段引發的跨域可能在項目上線時消失,即當前端代碼打包到后端同一服務器上,此時地址相同端口相同,相當於所有的接口都是在同一服務器內部進行請求調用操作,因此便不會產生跨域。但是呢,沒有開發哪兒來的上線,因此還是免不了開發過程中的跨域。
解決方式:前端構建代理服務器來完成跨域。即:在本地創建一個虛擬服務器,發送請求數據,同時接收請求的數據
過程:
- 在vue.config.js配置文件中,通過devServer.proxy選項配置代理:
devServer:{ port: 8080, proxy: { // key:描述項目中哪些請求需要被代理服務器代理,以路徑前綴方式描述key,定義被攔截請求的前綴 "/api": { target: "http://127.0.0.1:8080", // 定義被攔截的請求需要訪問的真實服務器 pathRewrite: { // 通過前綴替換進行地址的重寫和定義:去掉/api(因為/api默認會拼接上去) "^/api": "" // 替換掉以/api開頭的,這里用空字符串替換,直接去掉 } } } }
原理:當遇到“/api”時,會進入內部函數,將target變量的真實后台地址拼接到“/api”的前面,此時 請求路徑變成了:“http://127.0.0.1:8080/api",然后由於pathRewrite方法中將 “/api”替換成了空,也就是說直接去掉,因此路徑變成了 ““http://127.0.0.1:8080”,這就完成了代理,通過“/api”這個橋梁將后台地址成功地引入。
注:
vue.config.js文件只是做前端代理解決跨域問題時所用到的配置文件,當前端打包到服務器上時,該文件會被忽略,因此前端對於 api接口路徑的定義一定要跟后端所提供的保持一致,不能隨意增減上下文,即使你可能通過 配置代理 獲取了正確的請求路徑,因為打包到服務器后代理便失效了。
三、實例
1、當前需請求的后端接口路徑:
192.168.88.88:8091/host/getHostsInfo
2、配置文件
devServer:{ port: 8080, //代表本地服務器啟動后的虛擬端口 proxy: { "^/host": { // ^/host 表示匹配查詢以host開頭的路徑, /host有可能查詢到路徑中包含host的,不一定作為開頭 target: "http://192.168.88.88:8091", // 定義被攔截的請求需要訪問的真實服務器 pathRewrite: { // 通過前綴替換進行地址的重寫和定義:去掉/host(因為/host默認會拼接上去) "^/host": "/host" // 替換掉以/host開頭的,這里只是為了展示pathRewrite的用法,不需替換可以直接去掉這段。 } } } }
3、創建axios的時候,baseUrl配置:
const ajax = axios.create({ baseURL:"", timeout: 6000,//請求超時時間 })
創建請求:
export function getData() { //get return request({ url: '/host/getHostsInfo', method: 'GET' }) }
此時,baseUrl拼上請求地址,得到:/host/getHostsInfo,在代理proxy函數中,遇到 /host,則代理到target下的真實服務器路徑,將target的真實服務器地址加到 /host 前面,因此得到:http://192.168.88.88:8091/host/getHostsInfo ,也就是真實需請求的后端真實服務器接口路徑地址。
而如果在pathRewrite中對路徑進行了重寫,將 /host 替換成 "" 空字符串,即去掉它,此時代表后端接口請求路徑:http://192.168.88.88:8091/getHostsInfo。當然,本實例中這樣的代理是調不通的~
四、當項目需請求不同的后端地址時候,可配置多個代理。
原理一樣,直接上代碼:
proxy:{ "/api": { target: "http://192.168.88.88:8091", // ws: true, // 是否啟用websockets changeOrigin: true pathRewrite: { "^/api": "" } }, "/user": { target: "http://192.168.99.99:8091", // ws: true, changeOrigin: true pathRewrite: { "^/user": "" } }, },
baseUrl配置:
const ajax = axios.create({ baseURL:"/", //注意:這里我baseUrl寫的是 / ,因此在請求接口里的url沒有以 / 開頭了,寫法隨意,原理就是一個拼接過程。 timeout: 6000,//請求超時時間 })
請求接口:
export function getData() { //get return request({ url: 'api/host/getHostsInfo', method: 'GET' }) } export function getData1() { //get return request({ url: 'user/host/getHostsInfo', method: 'GET' }) }
此時,上面兩種方式最終請求的真實服務器接口路徑 是 兩台服務器下的同一接口路徑:
http://192.168.88.88:8091/host/getHostsInfo
http://192.168.99.99:8091/host/getHostsInfo