Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 男女下面进入的视频,国内精品一区二区2021在线,99re在线播放视频

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          弱電接地的真實(shí)情況是這樣的,別聽(tīng)不靠譜的電工瞎掰

          個(gè)留言剛看到:

          之前給大家分享過(guò)一個(gè)文章《只要是屏蔽網(wǎng)線,都應(yīng)該做接地,否則屏蔽線就會(huì)失去應(yīng)有的意義》實(shí)際上就是說(shuō)如何給屏蔽線接地的。

          iN的做法很簡(jiǎn)單——直接從接線板上引出一根地線,再懟到交換機(jī)上面的接地端子上:

          當(dāng)時(shí)用了地線連接線,

          弱電箱里面的接線板打開(kāi)后可以看到三個(gè)接線柱。

          地線連接線直接擰到接線板的地線接線柱上,

          另一端擰到設(shè)備的地線端子上。

          這時(shí)候,就有很多大聰明得說(shuō)“弱電的接線地線不能接強(qiáng)電地線”

          這件事其實(shí)就像回復(fù)里面的電工所說(shuō)的話一樣——瞎掰!

          咱們看一個(gè)網(wǎng)絡(luò)交換機(jī)的拆解圖片:

          注意一下左上角電源線的接線方式,你會(huì)發(fā)現(xiàn):

          地線進(jìn)入交換機(jī)后被第一時(shí)間用一根螺絲擰在了交換機(jī)的外殼上。

          同時(shí)我們?cè)倏春诵牡牡碾娐钒宀糠郑?/p>

          我們會(huì)發(fā)現(xiàn)這臺(tái)交換機(jī)在電路板上利用金屬螺絲直接連接了電路板裸露在外的銅薄上。

          這個(gè)銅薄就和地線相連了,同時(shí),電路板和地線連接的電路最終也會(huì)連接到RJ45接口上的接地簧片上

          網(wǎng)線如果有屏蔽層并且使用屏蔽接頭的話,屏蔽接頭就會(huì)和這根簧片接觸,從而也是連接在了電源線上那根地線上。

          在iN之前給大家指出的案例里面,只不過(guò)是吧那根地線從外面連接在了交換機(jī)的外殼上,而華為的交換機(jī)則是將地線從交換機(jī)的內(nèi)部連接在了外殼上。本質(zhì)上是沒(méi)有區(qū)別的。

          所以——電工說(shuō)的“弱電不能接強(qiáng)電地”就有點(diǎn)太想當(dāng)然了。

          那么問(wèn)題來(lái)了,家里的弱電如何接地?

          當(dāng)然是按照iN的方式來(lái)接了。為啥iN的交換機(jī)沒(méi)有得這樣接地呢?

          因?yàn)檫@款CSS610交換機(jī)是這樣供電的,交換機(jī)只能在電源端口取得直流電供給。并沒(méi)有被引入地線。所以這根地線咱們要手動(dòng)的加一下。

          能不能不這樣加根外殼上的小尾巴呢?

          那么就選擇帶有地線的交換機(jī)就好了,通常大一點(diǎn)的小交換機(jī)都支持220V帶地線的梅花插頭或者C13插頭的接入。

          這種插頭大家應(yīng)該都見(jiàn)過(guò),基本上臺(tái)式機(jī)、電飯鍋什么的都會(huì)使用到,內(nèi)置電源的交換機(jī)大部分也是使用這種插頭。

          使用這種線的結(jié)果就是——第一時(shí)間地線被從內(nèi)部接入到了外殼上。

          當(dāng)然了,你如果既不想在直流供電的小交換機(jī)上接一個(gè)小尾巴,又不想安裝一個(gè)相對(duì)比較大的內(nèi)置電源的交換機(jī),那么還有一個(gè)選擇就是用機(jī)架。

          沒(méi)錯(cuò),就是機(jī)架,如果你選用機(jī)架,并用螺絲將所有設(shè)備都固定在機(jī)架上,那么只要你的機(jī)架里面有一個(gè)設(shè)備是帶有電源接地的,那么所有的設(shè)備實(shí)際上就都接地了,這里有一個(gè)要點(diǎn)——你要用不帶漆膜的螺絲緊錮設(shè)備。

          像上面這樣,為了好看用磷化發(fā)黑效果的螺絲去緊固設(shè)備,而且大多數(shù)設(shè)備都放在托盤上,這是沒(méi)有接地效果的。特別不推薦在機(jī)架上這樣搞。

          如果這些都不愿意做,非得在不接地的情況下接通網(wǎng)絡(luò),那么最好的處理方式就是——?jiǎng)e用屏蔽電纜。

          擎反指紋瀏覽器是一種旨在減少或隱藏用戶瀏覽器指紋識(shí)別的技術(shù)和工具。下面將通過(guò)文字和視頻的方式詳細(xì)介紹反指紋瀏覽器的相關(guān)內(nèi)容。

          反指紋瀏覽器的原理和技術(shù)

          反指紋瀏覽器的目標(biāo)是減少用戶瀏覽器指紋的唯一性,從而減少用戶的跟蹤風(fēng)險(xiǎn)。為了實(shí)現(xiàn)這一目標(biāo),反指紋瀏覽器使用了許多技術(shù)和工具,包括:

          1. 用戶代理隨機(jī)化:用戶代理是指瀏覽器向服務(wù)器發(fā)送的包含瀏覽器信息的請(qǐng)求頭部,可以通過(guò)修改這個(gè)請(qǐng)求頭部來(lái)減少用戶的指紋唯一性。反指紋瀏覽器可以使用一些工具來(lái)隨機(jī)化用戶代理信息,使得每次請(qǐng)求時(shí)都發(fā)送不同的瀏覽器信息。
          2. 字體隨機(jī)化:字體是用戶指紋的一個(gè)重要組成部分,因?yàn)橛脩舻挠?jì)算機(jī)上安裝的字體不同,可以用來(lái)區(qū)分不同的用戶。反指紋瀏覽器可以使用一些技術(shù)來(lái)隨機(jī)化字體信息,使得每次訪問(wèn)時(shí)使用不同的字體。
          3. JavaScript 屏蔽:JavaScript 可以被用來(lái)獲取用戶的瀏覽器信息,因此屏蔽 JavaScript 可以減少用戶的指紋唯一性。反指紋瀏覽器可以使用一些工具來(lái)屏蔽 JavaScript。
          4. Cookie 隱身模式:Cookie 是網(wǎng)站用來(lái)存儲(chǔ)用戶信息的一種技術(shù),可以用來(lái)跟蹤用戶的行為。反指紋瀏覽器可以使用一些技術(shù)來(lái)在瀏覽網(wǎng)站時(shí)使用隱身模式,從而避免 Cookie 被存儲(chǔ)在用戶的計(jì)算機(jī)上。
          5. 代理服務(wù)器:代理服務(wù)器可以用來(lái)隱藏用戶的 IP 地址,從而減少用戶的指紋唯一性。反指紋瀏覽器可以使用一些代理服務(wù)器來(lái)隱藏用戶的 IP 地址。

          除了以上技術(shù)和工具之外,反指紋瀏覽器還可以使用一些其他的技術(shù)來(lái)減少用戶的指紋唯一性,比如使用虛擬機(jī)、使用 Tor 瀏覽器等等。

          反指紋瀏覽器的應(yīng)用場(chǎng)景

          反指紋瀏覽器可以被用于多種應(yīng)用場(chǎng)景,包括:

          1. 隱私保護(hù):反指紋瀏覽器可以被用來(lái)保護(hù)用戶的隱私,避免用戶被跟蹤和監(jiān)視。
          2. 安全測(cè)試:反指紋瀏覽器可以被用來(lái)測(cè)試網(wǎng)站

          o B 業(yè)務(wù)的生命周期與迭代通常會(huì)持續(xù)多年,隨著產(chǎn)品的迭代與演進(jìn),以接口調(diào)用為核心的前后端關(guān)系會(huì)變得非常復(fù)雜。在多年迭代后,接口的任何一處修改都可能給產(chǎn)品帶來(lái)難以預(yù)計(jì)的問(wèn)題。在這種情況下,構(gòu)建更穩(wěn)健的前端應(yīng)用,保證前端在長(zhǎng)期迭代下的穩(wěn)健與可拓展性就變得非常重要。本文將重點(diǎn)介紹如何利用接口防腐策略避免或減少接口變更對(duì)前端的影響。

          一 困境與難題

          為了更清晰解釋前端面臨的難題,我們以 To B 業(yè)務(wù)中常見(jiàn)的儀表盤頁(yè)面為例,該頁(yè)面包含了可用內(nèi)存、已使用內(nèi)存和已使用的內(nèi)存占比三部分信息展示。

          此時(shí)前端組件與接口之間的依賴關(guān)系如下圖所示。

          當(dāng)接口返回結(jié)構(gòu)調(diào)整時(shí)MemoryFree 組件對(duì)接口的調(diào)用方式需要調(diào)整。同樣的,MemoryUsage 與 MemoryUsagePercent 也要進(jìn)行修改才能工作。

          真實(shí)的 To B 業(yè)務(wù)面臨的接口可能會(huì)有數(shù)百個(gè),組件與接口的集成邏輯也遠(yuǎn)比以上的例子要復(fù)雜。

          經(jīng)過(guò)數(shù)年甚至更長(zhǎng)時(shí)間的迭代后,接口會(huì)逐步產(chǎn)生多個(gè)版本,出于對(duì)界面穩(wěn)定性及用戶使用習(xí)慣的考量,前端往往會(huì)同時(shí)依賴接口的多個(gè)版本來(lái)構(gòu)建界面。當(dāng)部分接口需要調(diào)整下線或發(fā)生變更時(shí),前端需要重新理解業(yè)務(wù)邏輯,并做出大量代碼邏輯調(diào)整才能保證界面穩(wěn)定運(yùn)行。

          常見(jiàn)的對(duì)前端造成影響的接口變更包括但不限于:

          • 返回字段調(diào)整
          • 調(diào)用方式改變
          • 多版本共存使用

          當(dāng)前端面對(duì)的是平臺(tái)型業(yè)務(wù)時(shí),此類問(wèn)題會(huì)變得更為棘手。平臺(tái)型產(chǎn)品會(huì)對(duì)一種或多種底層引擎進(jìn)行封裝,例如機(jī)器學(xué)習(xí)平臺(tái)可能會(huì)基于 TensorFlow、Pytorch 等機(jī)器學(xué)習(xí)引擎搭建,實(shí)時(shí)計(jì)算平臺(tái)可能基于 Flink、Spark 等計(jì)算引擎搭建。

          雖然平臺(tái)會(huì)對(duì)引擎的大部分接口進(jìn)行上層封裝,但不可避免的仍然會(huì)有部分底層接口會(huì)直接被透?jìng)鞯角岸耍谶@個(gè)時(shí)候,前端不僅要應(yīng)對(duì)平臺(tái)的接口變更,還會(huì)面臨著開(kāi)源引擎接口的變更帶來(lái)的挑戰(zhàn)。

          前端在面臨的困境是由獨(dú)特的前后端關(guān)系決定的。與其他領(lǐng)域不同,在 To B 業(yè)務(wù)中,前端通常以下游客戶的身份接受后端供應(yīng)商的供給,有些情況下會(huì)成為后端的跟隨者。

          在客戶/供應(yīng)商關(guān)系中,前端處于下游,而后端團(tuán)隊(duì)處于上游,接口內(nèi)容與上線時(shí)間通常由后端團(tuán)隊(duì)來(lái)決定。

          在跟隨者關(guān)系中,上游的后端團(tuán)隊(duì)不會(huì)去根據(jù)前端團(tuán)隊(duì)的需求進(jìn)行任何調(diào)整,前端只能去順應(yīng)上游后端的模型。這種情況通常發(fā)生在前端無(wú)法對(duì)上游后端團(tuán)隊(duì)施加影響的時(shí)刻,例如前端需要基于開(kāi)源項(xiàng)目的接口設(shè)計(jì)界面,或者是后端團(tuán)隊(duì)的模型已經(jīng)非常成熟且難以修改時(shí)。

          《架構(gòu)整潔之道》的作者描述過(guò)這樣一個(gè)嵌入式架構(gòu)設(shè)計(jì)的難題,與上文我們描述的困境十分類似。

          軟件應(yīng)當(dāng)是一種使用周期很長(zhǎng)的東西,而固件會(huì)隨著硬件的演進(jìn)而淘汰過(guò)時(shí),但事實(shí)上的情況是,雖然軟件本身不會(huì)隨著時(shí)間推移而磨損,但硬件及其固件卻會(huì)隨時(shí)間推移而過(guò)時(shí),隨即也需要對(duì)軟件做相應(yīng)的改動(dòng)。

          無(wú)論是客戶/供應(yīng)商關(guān)系,還是跟隨者關(guān)系,正如軟件無(wú)法決定硬件的發(fā)展與迭代一樣,前端也很難或者無(wú)法決定引擎與接口的設(shè)計(jì),雖然前端本身不會(huì)隨著時(shí)間的推移而變得不可用,但技術(shù)引擎及相關(guān)接口卻會(huì)隨著時(shí)間推移而過(guò)時(shí),前端代碼會(huì)跟隨技術(shù)引擎的迭代更換逐步腐爛,最終難逃被迫重寫的命運(yùn)。

          二 防腐層設(shè)計(jì)

          早在 Windows 誕生之前,工程師為了解決上文中硬件、固件與軟件的可維護(hù)性問(wèn)題,引入了 HAL(Hardware Abstraction Layer)的概念, HAL 為軟件提供服務(wù)并且屏蔽了硬件的實(shí)現(xiàn)細(xì)節(jié),使得軟件不必由于硬件或者固件的變更而頻繁修改。

          HAL 的設(shè)計(jì)思想在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD) 中又被稱為防腐層(Anticorruption Layer)。在 DDD 定義的多種上下文映射關(guān)系中,防腐層是最具有防御性的一種。它經(jīng)常被使用在下游團(tuán)隊(duì)需要阻止外部技術(shù)偏好或者領(lǐng)域模型入侵的情況,可以幫助很好地隔離上游模型與下游模型。

          我們可以在前端中引入防腐層的概念,降低或避免當(dāng)前后端的上下文映射接口變更對(duì)前端代碼造成的影響。

          在行業(yè)內(nèi)有很多種方式可以實(shí)現(xiàn)防腐層,無(wú)論是近幾年大火的 GraphQL 還是 BFF 都可以作為備選方案,但是技術(shù)選型同樣受限于業(yè)務(wù)場(chǎng)景。與 To C 業(yè)務(wù)完全不同,在 To B 業(yè)務(wù)中,前后端的關(guān)系通常為客戶/供應(yīng)商或者跟隨者/被跟隨者的關(guān)系。在這種關(guān)系下,寄希望于后端配合前端對(duì)接口進(jìn)行 GraphQL 改造已經(jīng)變得不太現(xiàn)實(shí),而 BFF 的構(gòu)建一般需要額外的部署資源及運(yùn)維成本。

          在上述情況下,在瀏覽器端構(gòu)建防腐層是更為可行的方案,但是在瀏覽器中構(gòu)建防腐層同樣面臨挑戰(zhàn)。

          無(wú)論是 React、Angular 還是 Vue 均有無(wú)數(shù)的數(shù)據(jù)層解決方案,從 Mobx、Redux、Vuex 等等,這些數(shù)據(jù)層方案對(duì)視圖層實(shí)際上都會(huì)有入侵,有沒(méi)有一種防腐層解決方案可以與視圖層徹底解耦呢?以 RxJS 為代表的 Observable 方案在這時(shí)可能是最好的選擇。

          RxJS 是 ReactiveX 項(xiàng)目的 JavaScript 實(shí)現(xiàn),而 ReactiveX 最早是 LINQ 的一個(gè)擴(kuò)展,由微軟的架構(gòu)師 Erik Meijer 領(lǐng)導(dǎo)的團(tuán)隊(duì)開(kāi)發(fā)。該項(xiàng)目目標(biāo)是提供一致的編程接口,幫助開(kāi)發(fā)者更方便的處理異步數(shù)據(jù)流。目前 RxJS 在開(kāi)發(fā)中經(jīng)常被作為響應(yīng)式編程開(kāi)發(fā)工具使用,但是在構(gòu)建防腐層的場(chǎng)景中,RxJS 代表的 Observable 方案同樣可以發(fā)揮巨大作用。

          我們選擇 RxJS 主要基于以下幾點(diǎn)考慮:

          • 統(tǒng)一不同數(shù)據(jù)源的能力:RxJS 可以將 websocket、http 請(qǐng)求、甚至用戶操作、頁(yè)面點(diǎn)擊等轉(zhuǎn)換為統(tǒng)一的 Observable 對(duì)象。
          • 統(tǒng)一不同類型數(shù)據(jù)的能力:RxJS 將異步數(shù)據(jù)和同步數(shù)據(jù)統(tǒng)一為 Observable 對(duì)象。
          • 豐富的數(shù)據(jù)加工能力:RxJS 提供了豐富的 Operator 操作符,可以對(duì) Observable 在訂閱前進(jìn)行預(yù)先加工。
          • 不入侵前端架構(gòu):RxJS 的 Observable 可以與 Promise 互相轉(zhuǎn)換,這意味著 RxJS 的所有概念可以被完整封裝在數(shù)據(jù)層,對(duì)視圖層可以只暴露 Promise。

          當(dāng)在引入 RxJS 將所有類型的接口轉(zhuǎn)換為 Observable 對(duì)象后,前端的視圖組件將僅依賴 Observable,并與接口實(shí)現(xiàn)的細(xì)節(jié)解耦,同時(shí),Observable 可以與 Promise 相互轉(zhuǎn)換,在視圖層獲得的是單純的 Promise,可以與任意數(shù)據(jù)層方案和框架搭配使用。

          除了轉(zhuǎn)換為 Promise 之外,開(kāi)發(fā)者也可以與 RxJS 在渲染層的解決方案,例如 rxjs-hooks 混用,獲得更好的開(kāi)發(fā)體驗(yàn)。

          三 防腐層實(shí)現(xiàn)

          參照上文的防腐層設(shè)計(jì),我們?cè)陂_(kāi)頭的儀表盤項(xiàng)目中實(shí)現(xiàn)以 RxJS Observable 為核心的防腐層代碼。

          其中防腐層的核心代碼如下

          export function getMemoryFreeObservable(): Observable<number> {
            return fromFetch("/api/v1/memory/free").pipe(mergeMap((res) => res.json()));
          }
          
          export function getMemoryUsageObservable(): Observable<number> {
            return fromFetch("/api/v1/memory/usage").pipe(mergeMap((res) => res.json()));
          }
          
          export function getMemoryUsagePercent(): Promise<number> {
            return lastValueFrom(forkJoin([getMemoryFreeObservable(), getMemoryUsageObservable()]).pipe(
              map(([usage, free]) => +((usage / (usage + free)) * 100).toFixed(2))
            ));
          }
          
          export function getMemoryFree(): Promise<number> {
            return lastValueFrom(getMemoryFreeObservable());
          }
          
          export function getMemoryUsage(): Promise<number> {
            return lastValueFrom(getMemoryUsageObservable());
          }

          MemoryUsagePercent 的實(shí)現(xiàn)代碼如下,此時(shí)該組件將不再依賴具體的接口,而直接依賴防腐層的實(shí)現(xiàn)。

          function MemoryUsagePercent() {
            const [usage, setUsage] = useState<number>(0);
            useEffect(() => {
              (async () => {
                const result = await getMemoryUsagePercent();
                setUsage(result);
              })();
            }, []);
            return <div>Usage: {usage} %</div>;
          }
          
          export default MemoryUsagePercent;

          1 返回字段調(diào)整

          返回字段變更時(shí),防腐層可以有效攔截接口對(duì)組件的影響,當(dāng) /api/v2/quota/free 與 /api/v2/quota/usage 的返回?cái)?shù)據(jù)變更為以下結(jié)構(gòu)時(shí)

          {
            requestId: string;
            data: number;
          }

          我們只需要調(diào)整防腐層的兩行代碼,注意此時(shí)我們的上層封裝的 getMemoryUsagePercent 基于 Observable 構(gòu)建所以不需要進(jìn)行任何改動(dòng)。

          export function getMemoryUsageObservable(): Observable<number> {
            return fromFetch("/api/v2/memory/free").pipe(
               mergeMap((res) => res.json()),
          +    map((data) => data.data)
            );
          }
          
          export function getMemoryUsageObservable(): Observable<number> {
            return fromFetch("/api/v2/memory/usage").pipe(
               mergeMap((res) => res.json()),
          +    map((data) => data.data)
            );
          }

          在 Observable 化的防腐層中,會(huì)存在高階 Observable 與 低階 Observable 兩種設(shè)計(jì),在上文的例子中,F(xiàn)ree Observable 和 Usage Observable 為低階封裝,而 Percent Observable 利用 Free 和 Usage 的 Observable 進(jìn)行了高階封裝,當(dāng)?shù)碗A封裝改動(dòng)時(shí),由于 Observable 本身的特性,高階封裝經(jīng)常是不需要進(jìn)行任何改動(dòng)的,這也是防腐層給我們帶來(lái)的額外好處。

          2 調(diào)用方式改變

          當(dāng)調(diào)用方式發(fā)生改變時(shí),防腐層同樣可以發(fā)揮作用。/api/v3/memory 直接返回了 free 與 usage 的數(shù)據(jù),接口格式如下。

          {
            requestId: string;
            data: {
              free: number;
              usage: number;
            }
          }

          防腐層代碼只需要進(jìn)行如下更新,就可以保障組件層代碼無(wú)需修改。

          export function getMemoryObservable(): Observable<{ free: number; usage: number }> {
            return fromFetch("/api/v3/memory").pipe(
              mergeMap((res) => res.json()),
              map((data) => data.data)
            );
          }
          
          export function getMemoryFreeObservable(): Observable<number> {
            return getMemoryObservable().pipe(map((data) => data.free));
          }
          
          export function getMemoryUsageObservable(): Observable<number> {
            return getMemoryObservable().pipe(map((data) => data.usage));
          }
          
          export function getMemoryUsagePercent(): Promise<number> {
            return lastValue(getMemoryObservable().pipe(
              map(({ usage, free }) => +((usage / (usage + free)) * 100).toFixed(2))
            ));
          }

          3 多版本共存使用

          當(dāng)前端代碼需要在多套環(huán)境下部署時(shí),部分環(huán)境下 v3 的接口可用,而部分環(huán)境下只有 v2 的接口部署,此時(shí)我們依然可以在防腐層屏蔽環(huán)境的差異。

          export function getMemoryLegacyObservable(): Observable<{ free: number; usage: number }> {
            const legacyUsage = fromFetch("/api/v2/memory/usage").pipe(
              mergeMap((res) => res.json())
            );
            const legacyFree = fromFetch("/api/v2/memory/free").pipe(
              mergeMap((res) => res.json())
            );
            return forkJoin([legacyUsage, legacyFree], (usage, free) => ({
              free: free.data.free,
              usage: usage.data.usage,
            }));
          }
          
          export function getMemoryObservable(): Observable<{ free: number; usage: number }> {
            const current = fromFetch("/api/v3/memory").pipe(
              mergeMap((res) => res.json()),
              map((data) => data.data)
            );
            return race(getMemoryLegacyObservable(), current);
          }
          
          export function getMemoryFreeObservable(): Observable<number> {
            return getMemoryObservable().pipe(map((data) => data.free));
          }
          
          export function getMemoryUsageObservable(): Observable<number> {
            return getMemoryObservable().pipe(map((data) => data.usage));
          }
          
          export function getMemoryUsagePercent(): Promise<number> {
            return lastValue(getMemory().pipe(
              map(({ usage, free }) => +((usage / (usage + free)) * 100).toFixed(2))
            ));
          }

          通過(guò) race 操作符,當(dāng) v2 與 v3 任何一個(gè)版本的接口可用時(shí),防腐層都可以正常工作,在組件層無(wú)需再關(guān)注接口受環(huán)境的影響。

          四 額外應(yīng)用

          防腐層不僅僅是多了一層對(duì)接口的封裝與隔離,它還能起到以下作用。

          1 概念映射

          接口語(yǔ)義與前端需要數(shù)據(jù)的語(yǔ)義有時(shí)并不能完全對(duì)應(yīng),當(dāng)在組件層直接調(diào)用接口時(shí),所有開(kāi)發(fā)者都需要對(duì)接口與界面的語(yǔ)義映射足夠了解。有了防腐層后,防腐層提供的調(diào)用方法包含了數(shù)據(jù)的真實(shí)語(yǔ)義,減少了開(kāi)發(fā)者的二次理解成本。

          2 格式適配

          在很多情況下,接口返回的數(shù)據(jù)結(jié)構(gòu)與格式與前端需要的數(shù)據(jù)格式并不符合,通過(guò)在防腐層增加數(shù)據(jù)轉(zhuǎn)換邏輯,可以降低接口數(shù)據(jù)對(duì)業(yè)務(wù)代碼的入侵。在以上的案例里,我們封裝了 getMemoryUsagePercent 的數(shù)據(jù)返回,使得組件層可以直接使用百分比數(shù)據(jù),而不需要再次進(jìn)行轉(zhuǎn)換。

          3 接口緩存

          對(duì)于多種業(yè)務(wù)依賴同一接口的情況,我們可以通過(guò)防腐層增加緩存邏輯,從而有效降低接口的調(diào)用壓力。

          與格式適配類似,將緩存邏輯封裝在防腐層可以避免組件層對(duì)數(shù)據(jù)的二次緩存,并可以對(duì)緩存數(shù)據(jù)集中管理,降低代碼的復(fù)雜度,一個(gè)簡(jiǎn)單的緩存示例如下。

          class CacheService {
            private cache: { [key: string]: any } = {};
            getData() {
              if (this.cache) {
                return of(this.cache);
              } else {
                return fromFetch("/api/v3/memory").pipe(
                  mergeMap((res) => res.json()),
                  map((data) => data.data),
                  tap((data) => {
                    this.cache = data;
                  })
                );
              }
            }
          }

          4 穩(wěn)定性兜底

          當(dāng)接口穩(wěn)定性較差時(shí),通常的做法是在組件層對(duì) response error 的情況進(jìn)行處理,這種兜底邏輯通常比較復(fù)雜,組件層的維護(hù)成本會(huì)很高。我們可以通過(guò)防腐層對(duì)穩(wěn)定性進(jìn)行兜底,當(dāng)接口出錯(cuò)時(shí)可以返回兜底業(yè)務(wù)數(shù)據(jù),由于兜底數(shù)據(jù)統(tǒng)一維護(hù)在防腐層,后續(xù)的測(cè)試與修改也會(huì)更加方便。在上文中的多版本共存的防腐層中,增加以下代碼,此時(shí)即使 v2 和 v3 接口都無(wú)法返回?cái)?shù)據(jù),前端仍然可以保持可用。

            return race(getMemoryLegacy(), current).pipe(
          +   catchError(() => of({ usage: '-', free: '-' }))
            );

          5 聯(lián)調(diào)與測(cè)試

          接口和前端可能會(huì)存在并行開(kāi)發(fā)的狀態(tài),此時(shí),前端的開(kāi)發(fā)并沒(méi)有真實(shí)的后端接口可用。與傳統(tǒng)的搭建 mock api 的方式相比,在防腐層直接對(duì)數(shù)據(jù)進(jìn)行 mock 是更方便的方案。

          export function getMemoryFree(): Observable<number> {
            return of(0.8);
          }
          
          export function getMemoryUsage(): Observable<number> {
            return of(1.2);
          }
          
          export function getMemoryUsagePercent(): Observable<number> {
            return forkJoin([getMemoryUsage(), getMemoryFree()]).pipe(
              map(([usage, free]) => +((usage / (usage + free)) * 100).toFixed(2))
            );
          }

          在防腐層對(duì)數(shù)據(jù)進(jìn)行 mock 也可以用于對(duì)頁(yè)面的測(cè)試,例如 mock 大量數(shù)據(jù)對(duì)頁(yè)面性能影響。

          export function getLargeList(): Observable<string[]> {
            const options = [];
            for (let i = 0; i < 100000; i++) {
              const value = `${i.toString(36)}${i}`;
              options.push(value);
            }
            return of(options);
          }

          五 總結(jié)

          在本文中我們介紹了以下內(nèi)容:

          1. 前端面對(duì)接口頻繁變動(dòng)時(shí)的困境及原因如何
          2. 防腐層的設(shè)計(jì)思想與技術(shù)選型
          3. 使用 Observable 實(shí)現(xiàn)防腐層的代碼示例
          4. 防腐層的額外作用

          請(qǐng)讀者注意,只在特定的場(chǎng)景下引入前端防腐層才是合理的,即前端處于跟隨者或供應(yīng)商/客戶關(guān)系中,且面臨大量接口無(wú)法保障穩(wěn)定和兼容。如果在防腐層可以在后端 Gateway 構(gòu)建,或者接口數(shù)量較少時(shí),引入防腐層帶來(lái)的額外成本會(huì)大于其帶來(lái)的好處。

          RxJS 在防腐層構(gòu)建場(chǎng)景下提供的更多的是 Observable 化的能力,如果讀者不需要復(fù)雜的 operators 轉(zhuǎn)換工具,也可以自行構(gòu)建 Observable 構(gòu)建方案,事實(shí)上只需要 100 行的代碼就可以實(shí)現(xiàn) https://stackblitz.com/edit/mini-rxjs。

          改造后的前端架構(gòu)將不再直接依賴接口實(shí)現(xiàn),不會(huì)入侵現(xiàn)有前端數(shù)據(jù)層設(shè)計(jì),還可以承擔(dān)概念映射、格式適配、接口緩存、穩(wěn)定性兜底以及協(xié)助聯(lián)調(diào)測(cè)試等工作。文中所有的示例代碼都可以在倉(cāng)庫(kù) https://github.com/vthinkxie/rxjs-acl 獲得。

          原文鏈接:https://developer.aliyun.com/article/872430?utm_content=g_1000331001

          本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。


          主站蜘蛛池模板: 国产天堂在线一区二区三区| 美女福利视频一区二区| 色一乱一伦一区一直爽| 国产精品丝袜一区二区三区| 无码毛片一区二区三区中文字幕| 国产AV午夜精品一区二区入口| 日韩有码一区二区| 日韩美一区二区三区| 亚洲sm另类一区二区三区| 99精品国产高清一区二区| 国产品无码一区二区三区在线蜜桃| 国产一区二区三区日韩精品| 99无码人妻一区二区三区免费| 无码人妻品一区二区三区精99| 在线精品亚洲一区二区小说| 真实国产乱子伦精品一区二区三区| 女人18毛片a级毛片一区二区| 亚洲一区二区三区影院| 精品人妻码一区二区三区| 亚洲一区二区影院| 亚洲蜜芽在线精品一区| 精品福利一区二区三区免费视频 | 亚洲高清一区二区三区电影| 亚洲AV无码一区二区三区DV| 中文字幕精品一区二区精品| 久久精品视频一区| 国产AV一区二区三区传媒| 色狠狠一区二区三区香蕉| 亚洲精品一区二区三区四区乱码| 亚洲日本久久一区二区va| 性色av闺蜜一区二区三区| 无码日韩人妻av一区免费| 国产亚洲综合一区二区三区| 一区二区视频免费观看| 久久精品国产一区二区三区日韩| 日韩精品无码一区二区三区| 亲子乱av一区区三区40岁| 免费人人潮人人爽一区二区 | 蜜桃传媒一区二区亚洲AV| 在线播放精品一区二区啪视频| 视频一区二区三区在线观看|