摘要:今天這篇文章,我們會(huì)介紹幾種常見(jiàn)的方法和其中存在的問(wèn)題,并提出如何基于請(qǐng)求攔截,快速解決跨域和代理問(wèn)題的方案。因?yàn)闆](méi)有修改該請(qǐng)求,只是延遲發(fā)送,這樣就保持了原請(qǐng)求與業(yè)務(wù)服務(wù)器之間的所有鑒權(quán)等相關(guān)信息,由此解決了跨域訪問(wèn)無(wú)法攜帶的問(wèn)題。
近幾年,隨著 Web 開(kāi)發(fā)逐漸成熟,前后端分離的架構(gòu)設(shè)計(jì)越來(lái)越被眾多開(kāi)發(fā)者認(rèn)可,使得前端和后端可以專注各自的職能,降低溝通成本,提高開(kāi)發(fā)效率。
在前后端分離的開(kāi)發(fā)模式下,前端和后端工程師得以并行工作。當(dāng)遇到前端界面展示需要的數(shù)據(jù),而后端對(duì)應(yīng)的接口還沒(méi)有完成開(kāi)發(fā)的情況時(shí),需要一個(gè)數(shù)據(jù)源來(lái)保證前端工作的順利進(jìn)行。
今天這篇文章,我們會(huì)介紹幾種常見(jiàn)的方法和其中存在的問(wèn)題,并提出如何基于HTTP 請(qǐng)求攔截,快速解決跨域和代理 mock 問(wèn)題的方案。
常見(jiàn)方法及問(wèn)題 請(qǐng)求 mock 服務(wù)器最常規(guī)的做法是維護(hù)一個(gè)提供靜態(tài)數(shù)據(jù)的 mock 服務(wù)器(它提供的數(shù)據(jù)稱為 mock 數(shù)據(jù)),前端請(qǐng)求 mock 服務(wù)器獲取數(shù)據(jù)即可,但這種靜態(tài)數(shù)據(jù)維護(hù)不便。
請(qǐng)求 AMP更好的做法是有一個(gè)根據(jù)接口定義來(lái)自動(dòng)生成數(shù)據(jù)的 mock 服務(wù)器,我們稱為AMP(接口管理平臺(tái),API Manage Platform),前端請(qǐng)求該服務(wù)器獲取數(shù)據(jù)。
在這種場(chǎng)景下,如果有些接口已經(jīng)完成開(kāi)發(fā),前端需要手動(dòng)修改代碼去設(shè)置不同接口的請(qǐng)求地址。當(dāng)接口數(shù)量較多時(shí),這種方法會(huì)變得非常低效。因此, AMP 一般也會(huì)同時(shí)提供代理功能,也就是指前端仍請(qǐng)求 AMP,AMP 會(huì)根據(jù)接口完成情況來(lái)決定返回 mock 數(shù)據(jù),還是將請(qǐng)求再次代理到真實(shí)的業(yè)務(wù)服務(wù)器獲取數(shù)據(jù)后返回。
但是這種方案的問(wèn)題在于當(dāng)涉及到需要角色權(quán)限驗(yàn)證的接口時(shí),登錄輸入用戶信息后在瀏覽器中會(huì)緩存 cookie,當(dāng)訪問(wèn)與登錄時(shí)同域名的接口時(shí),瀏覽器會(huì)自動(dòng)攜帶 cookie,由服務(wù)器解析 cookie 并鑒權(quán)后獲取對(duì)應(yīng)權(quán)限的接口數(shù)據(jù)。前端一般是在本地啟動(dòng)服務(wù)器進(jìn)行開(kāi)發(fā),當(dāng)業(yè)務(wù)服務(wù)器的接口完成開(kāi)發(fā),這時(shí)再采用請(qǐng)求 AMP 的方法切換接口數(shù)據(jù),就會(huì)出現(xiàn)跨域的情況。
由于瀏覽器的安全機(jī)制決定跨域訪問(wèn)時(shí)無(wú)法攜帶 cookie,并且無(wú)法通過(guò)代碼讀取 cookie,因此通過(guò)代碼傳遞 cookie 跨域不可行,而現(xiàn)有的解決方案也不完美:
如果在 AMP 額外增加模擬登陸的功能,會(huì)因?yàn)樗薪涌诘臋?quán)限固定不變,無(wú)法適配一個(gè)接口對(duì)不同角色有不同權(quán)限而返回相應(yīng)的數(shù)據(jù);而且一旦鑒權(quán)的接口功能變更、失效等情況發(fā)生,都需要重寫(xiě)修改 AMP 的代理功能,代價(jià)較大。
如果利用瀏覽器插件保存登陸信息、提供代理,則需要兼容不同瀏覽器,成本太高。
針對(duì)上述技術(shù)問(wèn)題,本文提出了一種可跨瀏覽器,并在前端實(shí)現(xiàn)的不侵入業(yè)務(wù)代碼的代理方法。
基于 HTTP 請(qǐng)求攔截 實(shí)現(xiàn)前端接口代理基于 HTTP 請(qǐng)求攔截實(shí)現(xiàn)前端接口的方式,從更底層的角度實(shí)現(xiàn)了接口開(kāi)發(fā)完成前后的 mock 數(shù)據(jù),及業(yè)務(wù)服務(wù)器真實(shí)數(shù)據(jù)之間的切換,并且解決了現(xiàn)有技術(shù)中由 HTTP 請(qǐng)求通過(guò) AMP 代理到業(yè)務(wù)服務(wù)器產(chǎn)生跨域無(wú)法攜帶權(quán)限信息,導(dǎo)致無(wú)法按照角色權(quán)限返回請(qǐng)求數(shù)據(jù)的技術(shù)問(wèn)題。
主要?jiǎng)?chuàng)新點(diǎn)在更底層基于 XMLHttpRequest 和 Fetch API 實(shí)現(xiàn)攔截代理,不需要考慮主流瀏覽器類型,和 JavaScript 依賴的工具庫(kù);
在前端實(shí)現(xiàn)代理,保留了登陸信息,無(wú)需額外處理鑒權(quán)問(wèn)題;
提供一種可以快速實(shí)現(xiàn)且可插拔的使用方式。
總的來(lái)說(shuō),這個(gè)方案提供了一種可快速實(shí)現(xiàn),運(yùn)行在前端瀏覽器中,且不依賴瀏覽器類型的請(qǐng)求代理方法。
設(shè)計(jì)思路Web 前端開(kāi)發(fā)一般使用 JavaScript 語(yǔ)言,瀏覽器環(huán)境的 HTTP 請(qǐng)求都是基于 Fetch API 或 XMLHttpRequest API 來(lái)實(shí)現(xiàn)的(基于前者的請(qǐng)求記做 xhr,后者記做 fetch),主流的 Javascript 開(kāi)源工具庫(kù)如 Axios、Request 也是這樣。所以,我們的方案就是要通過(guò)在底層攔截 xhr 或 fetch,根據(jù)一定的判斷邏輯來(lái)實(shí)現(xiàn)前端代理功能。
實(shí)現(xiàn)方式首先,重新封裝瀏覽器環(huán)境中原生的 XMLHttpRequest API 和 Fetch API。基本思路是將這兩個(gè)原生的 API 保存起來(lái),添加到各自重新封裝的同名 API 中(記作新 API),為新 API 寫(xiě)入與原生 API 中同名的方法和屬性,在攜帶請(qǐng)求參數(shù)的同名方法(比如下文中的 open 和 send)里加入攔截請(qǐng)求和代理的邏輯 ApiProxy,對(duì)外開(kāi)放一個(gè)可配置該攔截邏輯的接口,用于配置針對(duì)不同的 HTTP 請(qǐng)求格式所請(qǐng)求數(shù)據(jù)的攔截和代理邏輯。
ApiProxy 在這個(gè)過(guò)程中的主要作用和工作流程可以歸納為:
注冊(cè)攔截器。接收并攔截 HTTP 請(qǐng)求,解析該請(qǐng)求中的參數(shù),這里的參數(shù)是指能在 AMP 中唯一標(biāo)識(shí)該接口的參數(shù),比如域名+請(qǐng)求方法(如 GET、POST 等)+路徑(如 https://service.com/user 中的/user)。
根據(jù)該參數(shù)生成發(fā)送 AMP 的請(qǐng)求。AMP 實(shí)時(shí)維護(hù)了 mock 服務(wù)器上存儲(chǔ)的接口以及業(yè)務(wù)服務(wù)器上存儲(chǔ)的真實(shí)接口的相關(guān)信息,包括接口的定義、域名、屬性、開(kāi)發(fā)狀態(tài)等。
AMP 根據(jù)請(qǐng)求查詢接口定義數(shù)據(jù),如果接口存在且狀態(tài)是開(kāi)發(fā)中,則返回根據(jù)接口定義生成的 mock 數(shù)據(jù),否則返回特定響應(yīng)標(biāo)志,如圖 1 中的「{code:』200302』}」。
Apiproxy 收到 AMP 的響應(yīng)后判斷是否有特殊標(biāo)志,沒(méi)有直接返回 mock 數(shù)據(jù)到原請(qǐng)求,有則表示后端接口開(kāi)發(fā)完成,繼續(xù)發(fā)送原 HTTP 請(qǐng)求到后端服務(wù)器請(qǐng)求后端服務(wù)器存儲(chǔ)的真實(shí)數(shù)據(jù),相當(dāng)于沒(méi)有對(duì)原請(qǐng)求做任何處理。
和傳統(tǒng)的將 HTTP 請(qǐng)求發(fā)送給 AMP 不同的是 ,AMP 根據(jù)接口狀態(tài)判斷是根據(jù)請(qǐng)求直接返回 mock 數(shù)據(jù),還是開(kāi)啟代理將 HTTP 請(qǐng)求再發(fā)送給業(yè)務(wù)服務(wù)器(此時(shí)跨域訪問(wèn)會(huì)丟失原始 HTTP 請(qǐng)求中瀏覽器攜帶的 cookie),不直接將 HTTP 請(qǐng)求發(fā)送給 AMP,而是對(duì)請(qǐng)求正式發(fā)出之前進(jìn)行攔截,并解析其中的參數(shù)發(fā)送給 AMP,由 AMP 反饋接口狀態(tài),若開(kāi)發(fā)完成則將 HTTP 請(qǐng)求正式發(fā)送給業(yè)務(wù)服務(wù)器。因?yàn)闆](méi)有修改該請(qǐng)求,只是延遲發(fā)送,這樣就保持了原請(qǐng)求與業(yè)務(wù)服務(wù)器之間的所有鑒權(quán)等相關(guān)信息,由此解決了跨域訪問(wèn)無(wú)法攜帶 cookie 的問(wèn)題。
不同請(qǐng)求方式下 ApiProxy 的實(shí)現(xiàn)由于不同請(qǐng)求方式的底層設(shè)計(jì)不同,我們相應(yīng)的具體封裝手段也不同。
對(duì)于 XMLHttpRequest 請(qǐng)求,在其 open 方法中解析請(qǐng)求,訪問(wèn) AMP 根據(jù)響應(yīng)結(jié)果判斷是否需要繼續(xù)發(fā)送原請(qǐng)求到后臺(tái)服務(wù)器,一個(gè) xhr 只有在其 send 方法被調(diào)用時(shí)才會(huì)真正的發(fā)起 HTTP 請(qǐng)求,而在 open 方法中無(wú)法獲取到 send 方法傳遞的數(shù)據(jù),所以攔截發(fā)生在 send 方法中。首先多帶帶存儲(chǔ) send 方法中發(fā)送請(qǐng)求時(shí)的參數(shù),然后直接返回,確保先不調(diào)用真正的 XMLHttpRequest 的 send 方法,將多帶帶存儲(chǔ)的參數(shù)生成對(duì) AMP 的請(qǐng)求,執(zhí)行上述 AMP 中的判斷。
實(shí)例
1、定義與原生 XMLHttpRequest API 同名的接口,稱為新的 XHR 接口;
2、重命名原生 XMLHttpRequest API 并添加到新的 XHR 接口;
3、在新的 XHR 接口中定義與原生 XMLHttpRequest API 同名的屬性和方法;
4、在同名的 open 方法中解析 HTTP 請(qǐng)求,得到用來(lái)在 AMP 查詢接口狀態(tài)的參數(shù)(比如域名+請(qǐng)求方法+路徑);
5、攔截將要發(fā)送的原請(qǐng)求,在同名的 send 方法中暫存原請(qǐng)求要發(fā)送的數(shù)據(jù),暫停原請(qǐng)求的發(fā)送;
6、用 4 中的參數(shù)請(qǐng)求 AMP,查詢接口狀態(tài),如果接口不存在或是已完成狀態(tài),則返回特殊標(biāo)志,ApiProxy 取出 5 中暫存的數(shù)據(jù),傳遞給原請(qǐng)求,并繼續(xù)原請(qǐng)求的發(fā)送;否則,AMP 返回 mock 數(shù)據(jù),ApiProxy 直接將該數(shù)據(jù)返回給原請(qǐng)求。
Fetch API對(duì)于 Fetch API 而言,因?yàn)樗腔?Promise 實(shí)現(xiàn)的,攔截比較容易,只需要在 Fetch API 外層封裝一個(gè) Promise 入口,在其發(fā)起 fetch 請(qǐng)求前,先暫停原請(qǐng)求,解析數(shù)據(jù)請(qǐng)求 AMP,并等待響應(yīng),判斷響應(yīng)是否有特殊響應(yīng)碼,如果有則繼續(xù)原請(qǐng)求,否則跳過(guò)原請(qǐng)求,直接返回 mock 數(shù)據(jù)。
啟動(dòng)前端代理功能在前端實(shí)際開(kāi)發(fā)中,可以借助打包工具,比如 webpack,自定義一個(gè)可配置的插件,開(kāi)啟后在開(kāi)發(fā)環(huán)境中自動(dòng)將代理攔截代碼插入到主頁(yè)面里,從而啟動(dòng)前端代理功能。
小結(jié)本文提出的前端代理方法通過(guò)將代理職責(zé)下沉到前端,減少了 mock 服務(wù)器(或者接口管理平臺(tái))請(qǐng)求真實(shí)業(yè)務(wù)服務(wù)器步驟,同時(shí)將角色權(quán)限保持在前端請(qǐng)求中,進(jìn)一步減少了代理所需要承擔(dān)的工作量,從底層攔截 HTTP 請(qǐng)求的方法,繞過(guò)了利用瀏覽器插件做代理帶來(lái)的瀏覽器兼容的問(wèn)題。最后提供的利用打包工具(如 webpack)封裝這種代理方法,實(shí)現(xiàn)快速插拔的前端代理。
本文作者奴止,馬蜂窩社區(qū)研發(fā)團(tuán)隊(duì)前端開(kāi)發(fā)工程師,主要負(fù)責(zé)社區(qū)管理后臺(tái),接口管理平臺(tái)開(kāi)發(fā)等工作。
關(guān)注馬蜂窩技術(shù),找到更多你需要的內(nèi)容
附:參考資料關(guān)于跨域:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
關(guān)于XMLHTTPRequest:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
關(guān)于Fetch:
[https://developer.mozilla.org...](https://developer.mozilla.org...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109158.html
摘要:當(dāng)然需要的工具不只有這些,其他的一些可選工具還有文件壓縮壓縮時(shí)用到的文件重命名檢查一般編輯器自帶校驗(yàn)提示工具等等,具體根據(jù)項(xiàng)目需要安裝。 gulp 前端自動(dòng)化構(gòu)建工具 需要配置nodejs環(huán)境, 利用npm安裝全局gulp,安裝后可以輸入gulp指令。 npm install gulp -g 創(chuàng)建項(xiàng)目目錄、初始化npm包、gulp npm init gulp init 下載gul...
摘要:背景隨著互聯(lián)網(wǎng)應(yīng)用工程規(guī)模的日益復(fù)雜化和精細(xì)化,我們?cè)陂_(kāi)發(fā)一個(gè)標(biāo)準(zhǔn)應(yīng)用的早已開(kāi)始告別單干模式,為了提升開(kāi)發(fā)效率,前后端分離的需求越來(lái)越被重視,前端負(fù)責(zé)展現(xiàn)交互邏輯,后端負(fù)責(zé)業(yè)務(wù)數(shù)據(jù)接口,基本上也成為了我們?nèi)粘m?xiàng)目分工中的標(biāo)配,但是前后端分離 背景 隨著互聯(lián)網(wǎng)應(yīng)用工程規(guī)模的日益復(fù)雜化和精細(xì)化,我們?cè)陂_(kāi)發(fā)一個(gè)標(biāo)準(zhǔn)web應(yīng)用的早已開(kāi)始告別單干模式,為了提升開(kāi)發(fā)效率,前后端分離的需求越來(lái)越被重...
摘要:最后確定的方案最終決定的方案是使用一個(gè)代理服務(wù)器,也就是,來(lái)幫助我們解決環(huán)境問(wèn)題。團(tuán)隊(duì)規(guī)則同步支持遠(yuǎn)程規(guī)則,目的是讓團(tuán)隊(duì)成員間共用同一份轉(zhuǎn)發(fā)規(guī)則,降低溝通成本。 一、ZanProxy 是什么 一言以蔽之,ZanProxy 是一個(gè)基于 Node.js 的代理服務(wù)器。它專注于幫助前端開(kāi)發(fā)提高開(kāi)發(fā)效率。 showImg(https://segmentfault.com/img/remote/...
摘要:前端基本功常見(jiàn)概念一點(diǎn)這里前端基本功常見(jiàn)概念二點(diǎn)這里前端基本功常見(jiàn)概念三點(diǎn)這里什么是原型鏈當(dāng)一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法時(shí)候就會(huì)產(chǎn)生一個(gè)原型鏈。函數(shù)式編程是聲明式而不是命令式,并且應(yīng)用程序狀態(tài)通過(guò)純函數(shù)流轉(zhuǎn)。 前端基本功-常見(jiàn)概念(一) 點(diǎn)這里前端基本功-常見(jiàn)概念(二) 點(diǎn)這里前端基本功-常見(jiàn)概念(三) 點(diǎn)這里 1.什么是原型鏈 當(dāng)一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方...
摘要:本文適用的場(chǎng)景在對(duì)移動(dòng)端的純移動(dòng)端功能或者前端頁(yè)面的純前端功能進(jìn)行測(cè)試時(shí),服務(wù)端接口返回的數(shù)據(jù)不滿足要求,或者制造測(cè)試數(shù)據(jù)比較復(fù)雜,需要使用方法來(lái)快速構(gòu)造數(shù)據(jù)。進(jìn)入官網(wǎng)后,首先創(chuàng)建一個(gè)項(xiàng)目,一個(gè)項(xiàng)目包含若干個(gè)接口,我們最終模擬的是接口。 本文適用的場(chǎng)景:在對(duì)移動(dòng)端APP的純移動(dòng)端功能或者前端H5頁(yè)面的純前端功能進(jìn)行測(cè)試時(shí),服務(wù)端接口返回的數(shù)據(jù)不滿足要求,或者制造測(cè)試數(shù)據(jù)比較復(fù)雜,需要使...
閱讀 796·2021-08-23 09:46
閱讀 945·2019-08-30 15:44
閱讀 2603·2019-08-30 13:53
閱讀 3050·2019-08-29 12:48
閱讀 3872·2019-08-26 13:46
閱讀 1807·2019-08-26 13:36
閱讀 3520·2019-08-26 11:46
閱讀 1419·2019-08-26 10:48