webpack-dev-server原理解析及跨域解決方法
webpack proxy ,就是 webpack 提供的解決跨域的方案。其基本行為是接受客戶端發(fā)送的請求后轉(zhuǎn)發(fā)給其他的服務(wù)器,目的是為了解決在開發(fā)模式下的跨域問題。
原理
webpack中的proxy 工作原理是利用了 http-proxy-middleware
這個http 代理中間件,實現(xiàn)將請求轉(zhuǎn)發(fā)給其他的服務(wù)器。
如下:在開發(fā)階段,本地地址是 Http://loaclhost:3000
, 該瀏覽器發(fā)送一個前綴帶有 /api 標(biāo)識的向服務(wù)器請求數(shù)據(jù),但是這個服務(wù)器只是將這個請求轉(zhuǎn)發(fā)給另一臺服務(wù)器:
const express = require('express'); const proxy = require('http-proxy-middleware'); const app = express(); app.use('/api', proxy({target: 'http://www.test.org', changeOrigin: true})); app.listen(3000); // http://localhost:3000/api/foo/bar -> http://www.test.org/api/foo/bar
在開發(fā)階段,webpack-dev-server 會自動啟動一個本地開發(fā)服務(wù)器,所以我們的應(yīng)用在開發(fā)階段是獨立運(yùn)行在 localhost 的一個端口上的,而后端服務(wù)器又是運(yùn)行在另一個地址上.。
所以在開發(fā)階段中,由于瀏覽器的同源策略,當(dāng)本地瀏覽器訪問后端服務(wù)器的時候就會出現(xiàn)跨域請求資源的問題。
通過設(shè)置 webpack proxy 實現(xiàn)代理請求后,相當(dāng)于瀏覽器和服務(wù)器之間添加了一個代理服務(wù)器。
當(dāng)本地發(fā)送請求的時候,中間服務(wù)器會接受這個情求,并將這個請求轉(zhuǎn)發(fā)給目標(biāo)服務(wù)器(也就是后端服務(wù)器),目標(biāo)服務(wù)器返回數(shù)據(jù)后,中間服務(wù)器又會將數(shù)據(jù)返回給瀏覽器,當(dāng)中間服務(wù)器將數(shù)據(jù)返回給服務(wù)器的時候,它們兩者是同源的,并不會存在跨域的問題。
服務(wù)器和服務(wù)器之間是不會存在跨域資源的問題的。
webpack-dev-server
webpack 提供代理服務(wù)器的工具是webpack-dev-server
,但只適用于開發(fā)階段,線上要實現(xiàn)代理一般通過 nginx 來配置。
webpack 中的服務(wù)器工具 webpack-dev-server,實質(zhì)上是啟動了一個 express 服務(wù)器。
proxy 代理是利用 http-proxy-middleware
這個http代理中間件實現(xiàn)將請求轉(zhuǎn)發(fā)給其他服務(wù)器。
(vite 是用的 http-proxy,其實 http-proxy-middleware 也是基于 http-proxy 的)
背后其實都是使用 node 來啟動 server 服務(wù)器,這也是為什么我們常說這種代理只能在開發(fā)階段使用,因為 build 生產(chǎn)包時我們并不會打包一個 node 服務(wù)器進(jìn)去,線上要實現(xiàn)代理一般直接通過 nginx 來配置。
可以在webpack 配置對象屬性中通過 devServer 屬性來配置:
// ./webpack.config.js const path = require('path') module.exports = { // ... devServer: { contentBase: path.join(__dirname, 'dist'), compress: true, port: 9000, proxy: { '/api': { target: 'https://api.github.com' } } // ... } }
webpack-dev-server常用的配置項
Proxy代理
它的目的是設(shè)置代理來解決跨域訪問的問題。舉例:
我們的一個api請求地址(也就是服務(wù)器地址)是 http://localhost:8888
,
但是本地啟動服務(wù)器的域名是 http://localhost:8000
,
這個時候發(fā)送網(wǎng)絡(luò)請求就會出現(xiàn)跨域的問題(端口不同)。
所以將請求先發(fā)送到一個代理服務(wù)器,代理服務(wù)器和API服務(wù)器沒有跨域的問題,就可以解決我們的跨域問題了。
module.exports = { //... devServer: { proxy: { '/api': {// 以 /api 開頭的請求,會轉(zhuǎn)發(fā)到下面的 target 配置 target: 'http://localhost:8888',// 目標(biāo)服務(wù)器 pathRewrite: { "^/api": "", // 重寫路徑為空,即請求路徑中沒有/api字符串 "^/api": "/abcd" // 重寫路徑為abcd,即將請求路徑中的/api字符串替換成/abcd }, secure: false,// https接口,需要配置這個參數(shù) changeOrigin: true,// 將請求頭中的host 配置為 target }, }, host: '0.0.0.0', //用于指定devDerve使用的host,如果你希望服務(wù)器外部可以訪問,設(shè)定如 host: '0.0.0.0' https: true, // 默認(rèn)情況下dev-server使用http協(xié)議,通過配置可以支持https, // 注意:默認(rèn)使用自簽名證書,也可以配置自己的證書 // https: { // ca: './path/to/server.pem', // pfx: './path/to/server.pfx', // key: './path/to/server.key', // cert: './path/to/server.crt', // passphrase: 'webpack-dev-server', // requestCert: true, // }, // 開啟熱模塊替換 hot: true, }, };
- target:表示的是代理到的目標(biāo)地址(也就是要訪問的服務(wù)器地址),比如 /api會被代理到 http://localhost:8888/api
- pathRewrite:默認(rèn)情況下,我們的 /api 也會被寫入到URL中,即:http://localhost:8888/api, 如果希望刪除,可以使用pathRewrite,比如:
- 配置成 "^/api": "",那么/api/user => http://localhost:8888/user,地址中沒有/api,因為重新路徑是空的;
- 配置成"^/api": "/abcd" ,那么/api/user => http://localhost:8888/abcd/user,即將請求路徑中的/api字符串替換成/abcd
- secure: 默認(rèn)情況下,不接受在 HTTPS 上運(yùn)行且證書無效的后端服務(wù)器。 https接口,需要配置這個參數(shù)為false;
- changeOrigin:它表示是否更新代理后請求的headers中host地址,一般設(shè)置為true
proxy
配置中 changeOrigin: true
,// 將請求頭中的host 配置為 target。
那為什么要更改請求頭中的host呢?
因為一臺服務(wù)器上可以部署多個項目,當(dāng)我們發(fā)送請求時,DNS 會將域名解析為 IP 地址,此時,也就確定了我們目標(biāo)服務(wù)器,那如何確定我們要訪問的是哪個項目呢?這就需要用到 host 字段了。
請求頭中Host用來指定請求的 域名/ip地址和端口號,通常用于指定服務(wù)器的地址,端口號可以省略,省略時默認(rèn)為80端口。
此時我們將host指定為a.com就會訪問到淘寶服務(wù)了。
所以如果一臺服務(wù)器上部署多個項目時,我們需要更改請求頭中的host,來指定我們要訪問的項目。
一臺服務(wù)器只有一個項目時,我們可以不用更改請求頭中的host,因為DNS解析后,就確定了我們要訪問的項目。
但為了以后用起來方便,就統(tǒng)一將這個配置項changeOrigin設(shè)置為true。
host
devServer.host
配置項?于配置 DevServer 服務(wù)監(jiān)聽的地址,默認(rèn)使? 8080 端?。 如果 8080 端? 已經(jīng)被其它程序占有就使? 8081,如果 8081 還是被占?就使? 8082,以此類推
例如:
你想要局域?中的其它設(shè)備訪問你本地的服務(wù),可以在啟動 DevServer 時帶上 --host 0.0.0.0
,
也可以在webpack
配置項devServer.host
中設(shè)置0.0.0.0
host 的默認(rèn)值是 127.0.0.1
即只有本地可以訪問 DevServer 的 HTTP 服務(wù)。
localhost 和 0.0.0.0 的區(qū)別:
localhost:本質(zhì)上是一個域名,通常情況下會被解析成127.0.0.1。127.0.0.1:回環(huán)地址(Loop Back Address),表達(dá)的意思其實是我們主機(jī)自己發(fā)出去的包,直接被自己接收。
正常的數(shù)據(jù)庫包經(jīng)過 應(yīng)用層 - 傳輸層 - 網(wǎng)絡(luò)層 - 數(shù)據(jù)鏈路層 - 物理層 ,而回環(huán)地址,是在網(wǎng)絡(luò)層直接就被獲取到了,是不會經(jīng)過數(shù)據(jù)鏈路層和物理層的。
比如:
我們監(jiān)聽 127.0.0.1時,在同一個網(wǎng)段下的主機(jī)中,通過ip地址是不能訪問的。
0.0.0.0:監(jiān)聽IPV4上所有的地址,再根據(jù)端口找到不同的應(yīng)用程序,比如我們監(jiān)聽 0.0.0.0時,在同一個網(wǎng)段下的主機(jī)中,通過ip地址是可以訪問的
port、open、compress
devServer.port
設(shè)置監(jiān)聽的端口,默認(rèn)情況下是8080,不能設(shè)置為null,可以設(shè)置自動為auto
module.exports = { //... devServer: { port: 8080, }, };
devServer.open
告訴 dev-server 在服務(wù)器已經(jīng)啟動后打開瀏覽器。設(shè)置其為 true 以打開你的默認(rèn)瀏覽器。
module.exports = { //... devServer: { open: true, //在瀏覽器中打開指定頁面:open: ['/my-page'] //提供要使用的瀏覽器名稱,而不是默認(rèn)名稱 // open: { // app: { // name: 'google-chrome', // }, // }, }, };
devServer.compress
告訴 dev-server 在服務(wù)器端啟用 gzip 壓縮,用于減少服務(wù)器向前端傳輸?shù)臄?shù)據(jù)量,提高瀏覽的速度。
module.exports = { //... devServer: { compress: true, }, };
到此這篇關(guān)于webpack-dev-server原理解析及其中跨域解決方法的文章就介紹到這了,更多相關(guān)webpack-dev-server原理解析及其中跨域解決方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解webpack 入門總結(jié)和實踐(按需異步加載,css單獨打包,生成多個入口文件)
本篇文章主要介紹了webpack 入門總結(jié)和實踐(按需異步加載,css單獨打包,生成多個入口文件) ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06js面向?qū)ο蠓庋b級聯(lián)下拉菜單列表的實現(xiàn)步驟
這篇文章主要介紹了js面向?qū)ο蠓庋b級聯(lián)下拉菜單列表的實現(xiàn)步驟,幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下2021-02-02