抽絲剝繭:詳述一次DevServer Proxy配置無(wú)效問(wèn)題的細(xì)致排查過(guò)程

事情的起因是這樣的珊泳,在一個(gè)已上線的項(xiàng)目中富纸,其中一個(gè)包含登錄和獲取菜單的接口因響應(yīng)時(shí)間較長(zhǎng),后端讓我嘗試未經(jīng)服務(wù)轉(zhuǎn)發(fā)的另一域名下的新接口旨椒,舊接口允許跨域請(qǐng)求晓褪,但新接口不允許本地訪問(wèn)(只允許發(fā)布測(cè)試/生產(chǎn)的域名訪問(wèn))。

問(wèn)題

那么問(wèn)題來(lái)了综慎,本地環(huán)境該如何成功訪問(wèn)到新的接口并驗(yàn)證業(yè)務(wù)功能是否生效呢涣仿?


1_跨域.png

嘗試過(guò)程

我首先就想到了直接在 webpack 項(xiàng)目中配置 devServer,并且修改接口地址(為了安全隱私示惊,隱去公司實(shí)際域名好港,使用 xxxxx 來(lái)替代。)

devServer: {
  proxy: {
    '/': {
      target: 'https://xxxxx.cn',
      pathRewrite: {
        '/proxyApi': '',
      },
      changeOrigin: true,
    },
  },
} 

但返回的接口提示【登錄態(tài)無(wú)效】米罚,這下起碼不跨域了钧汹!本來(lái)以為已經(jīng)代理成功,只需要找到后端看看報(bào)錯(cuò)即可


2.png

但后端反饋這個(gè)報(bào)錯(cuò)是因?yàn)檎?qǐng)求頭沒(méi)有攜帶指定參數(shù)录择,他也查不到該請(qǐng)求的詳細(xì)信息拔莱。這時(shí)候我又開(kāi)始有疑問(wèn)了,明明查看請(qǐng)求頭是有的呀隘竭。


3.png

疑問(wèn)

在 chrome 瀏覽器上看到的請(qǐng)求地址并不是后端提供的真實(shí)接口請(qǐng)求地址塘秦,而是加了我代理的字段。在響應(yīng)體上我也沒(méi)有找到 location 等字段反饋到真實(shí)的請(qǐng)求接口动看。

此時(shí)的我懷疑尊剔,代理是真的生效了嗎,我請(qǐng)求的接口是真實(shí)的后端接口嗎菱皆?開(kāi)始驗(yàn)證 devServer 的 proxy 是否執(zhí)行须误。在 proxy 處配置請(qǐng)求前后輸出的函數(shù),結(jié)果發(fā)現(xiàn) onProxyReq 和 onProxyRes 都沒(méi)有執(zhí)行仇轻。

proxy: {
  '/proxyApi': {
    target: 'https://xxxxx.cn',
    pathRewrite: {
      '/proxyApi': '',
    },
    changeOrigin: true,
    onProxyReq(proxyReq, req, res) {
      console.log('>>>請(qǐng)求', req);
    },
    onProxyRes(proxyRes, req, res) {
      // 響應(yīng)的鉤子函數(shù)
      console.log('>>>響應(yīng)', res);
    },
  },
},

所以此時(shí)猜測(cè)是不是整個(gè) devServer 都沒(méi)有生效京痢,但如何證明它沒(méi)有生效呢?

證實(shí)

目前代理后端域名不受我們控制拯田,我無(wú)從知曉它是否發(fā)送到后端服務(wù)器上历造,所以我打算自己用 nodejs 開(kāi)啟一個(gè)服務(wù),開(kāi)啟服務(wù)的方式很簡(jiǎn)單,使用核心模塊 https 幾行代碼搞定吭产。

const http = require("http");

const server = http.createServer((req, res) => {
  console.log(">>req", req.url, req.rawHeaders );
  res.end("hello");
});

server.listen("3002", () => {
  console.log("3002端口啟動(dòng)了");
});

通過(guò) node 啟動(dòng)服務(wù)后侣监,首先驗(yàn)證是否可攔截請(qǐng)求,直接通過(guò)瀏覽器窗口 輸入


4.png

哎~ 服務(wù)啟動(dòng)了臣淤,頁(yè)面也得到的響應(yīng)橄霉,服務(wù)器能獲取到剛剛 get 請(qǐng)求的數(shù)據(jù)


5.png

此時(shí)將項(xiàng)目中 proxy 的配置改為 3002 端口的服務(wù),再次執(zhí)行業(yè)務(wù)邏輯代碼發(fā)送請(qǐng)求邑蒋,發(fā)現(xiàn)此時(shí)3002端口啟動(dòng)的服務(wù)控制臺(tái)空空如也姓蜂!也就是說(shuō),它根本沒(méi)有攔截到該請(qǐng)求医吊。

proxy: {
  '/proxyApi': {
    target: 'http://localhost:3002',
},

猜想是否因?yàn)轫?xiàng)目里的接口請(qǐng)求工具導(dǎo)致無(wú)法攔截钱慢,于是直接在頁(yè)面上使用 fetch 發(fā)送請(qǐng)求,此時(shí)發(fā)現(xiàn) 3002 端口的服務(wù)仍然沒(méi)有接收到請(qǐng)求卿堂。

fetch('https://xxxxx.cn/proxyApi/yyyyy/operateTargetNew')

本來(lái)以為是不是 proxy 字符匹配的問(wèn)題束莫,因?yàn)?/proxyApi 標(biāo)識(shí)出現(xiàn)在整個(gè)url 中間,試圖修改為正則表達(dá)式 "*/proxyApi/"草描,也是無(wú)效的

proxy: {
  '**/proxyApi/*': {
},

再次嘗試

這時(shí)候我意識(shí)到一個(gè)問(wèn)題览绿,帶有域名的接口訪問(wèn)好像不行,那我直接去掉域名呢穗慕?

此時(shí)直接使用 fetch 請(qǐng)求不包含域名的接口地址

fetch('/proxyApi/yyyyy/operateTargetNew')

這個(gè)時(shí)候饿敲,終于看到了問(wèn)題即將解決的曙光!調(diào)用接口成功獲取到了 3002 端口返回的響應(yīng)


6.png

也能在本地的 3002 端口服務(wù)上獲取到請(qǐng)求的詳細(xì)信息逛绵。
7.png

撥開(kāi)云霧

查詢資料發(fā)現(xiàn)果然是接口地址的原因怀各。Webpack DevServer的proxy配置主要用于開(kāi)發(fā)環(huán)境中,針對(duì)的是由本地DevServer發(fā)出的API請(qǐng)求暑脆。

當(dāng)你在前端代碼中發(fā)送請(qǐng)求時(shí)渠啤,通常會(huì)使用相對(duì)路徑(如/api/xxx/yyy),這樣它們就會(huì)被發(fā)送到當(dāng)前頁(yè)面所在的主機(jī)和端口添吗,也就是Webpack DevServer。

這時(shí)份名,DevServer的proxy設(shè)置可以將請(qǐng)求轉(zhuǎn)發(fā)到配置的后端服務(wù)器碟联。

// webpack.config.js
module.exports = {
  // ...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://your-backend-server.com',
        changeOrigin: true,
      },
    },
  },
};

現(xiàn)在,如果你發(fā)送一個(gè)請(qǐng)求到/api/xxx/yyy僵腺,DevServer會(huì)將它代理到http://your-backend-server.com/api/xxx/yyy鲤孵。

然而,如果你在前端代碼中直接使用了完整的URL(即包含域名https://www.xxxx.com/api/xxx/yyy)辰如,就繞過(guò)了Webpack DevServer普监,請(qǐng)求直接發(fā)往該完整URL對(duì)應(yīng)的服務(wù)器。DevServer的proxy配置不會(huì)和這個(gè)請(qǐng)求交互,因此無(wú)法將它代理到你配置的目標(biāo)服務(wù)器凯正。

請(qǐng)求改造

于是再改回需要代理的接口毙玻,并對(duì)項(xiàng)目邏輯進(jìn)行一些改造,因?yàn)槟J(rèn)的網(wǎng)絡(luò)庫(kù)會(huì)拼接url廊散,這里做一個(gè)判斷桑滩,將需要代理的域名和代理的字符作為一組值保存起來(lái)。

如果匹配中需要代理的需求允睹,并用前綴來(lái)替換运准。

// 本地環(huán)境,需要將代理的接口剔除域名缭受,并拼接代理前綴
  if (process.env.NODE_ENV === 'development') {
    const proxyObj = {
      'https://xxxx.cn': '/proxyApi',
    };
    const proxyKeys = Object.keys(proxyObj);
    for (let i = 0; i < proxyKeys.length; i++) {
      const host = proxyKeys[i];
      if (option.url.includes(host)) {
        const prefix = proxyObj[host];
        option.url = option.url.replace(host, prefix);
      }
    }
  }

這樣就可以將接口請(qǐng)求拼接為 https://xxxx.con 域名的全部替換為指定前綴胁澳,這樣這部分的請(qǐng)求就都會(huì)走代理。

8.png

很慚愧米者,雖然早就知道 webpack 的 proxy 配置解決本地跨域問(wèn)題韭畸,但確實(shí)很少自己去配置,一般是后端解決掉跨域問(wèn)題或者項(xiàng)目里的自帶里處理方案塘雳,所以真正到自己配置的時(shí)候多少有點(diǎn)迷糊了陆盘。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市败明,隨后出現(xiàn)的幾起案子隘马,更是在濱河造成了極大的恐慌,老刑警劉巖妻顶,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酸员,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡讳嘱,警方通過(guò)查閱死者的電腦和手機(jī)幔嗦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沥潭,“玉大人邀泉,你說(shuō)我怎么就攤上這事《鄹耄” “怎么了汇恤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拔恰。 經(jīng)常有香客問(wèn)我因谎,道長(zhǎng),這世上最難降的妖魔是什么颜懊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任财岔,我火速辦了婚禮风皿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匠璧。我一直安慰自己桐款,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布患朱。 她就那樣靜靜地躺著鲁僚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裁厅。 梳的紋絲不亂的頭發(fā)上冰沙,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音执虹,去河邊找鬼拓挥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛袋励,可吹牛的內(nèi)容都是我干的侥啤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼茬故,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼盖灸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起磺芭,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赁炎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后钾腺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體徙垫,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年放棒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了姻报。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡间螟,死狀恐怖吴旋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厢破,我是刑警寧澤邮府,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站溉奕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏忍啤。R本人自食惡果不足惜加勤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一仙辟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鳄梅,春花似錦叠国、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至孙蒙,卻和暖如春项棠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挎峦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工香追, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坦胶。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓透典,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親顿苇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子峭咒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容