整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          弱電接地的真實情況是這樣的,別聽不靠譜的電工瞎掰

          個留言剛看到:

          之前給大家分享過一個文章《只要是屏蔽網線,都應該做接地,否則屏蔽線就會失去應有的意義》實際上就是說如何給屏蔽線接地的。

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

          當時用了地線連接線,

          弱電箱里面的接線板打開后可以看到三個接線柱。

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

          另一端擰到設備的地線端子上。

          這時候,就有很多大聰明得說“弱電的接線地線不能接強電地線”

          這件事其實就像回復里面的電工所說的話一樣——瞎掰!

          咱們看一個網絡交換機的拆解圖片:

          注意一下左上角電源線的接線方式,你會發現:

          地線進入交換機后被第一時間用一根螺絲擰在了交換機的外殼上。

          同時我們再看核心的的電路板部分:

          我們會發現這臺交換機在電路板上利用金屬螺絲直接連接了電路板裸露在外的銅薄上。

          這個銅薄就和地線相連了,同時,電路板和地線連接的電路最終也會連接到RJ45接口上的接地簧片上

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

          在iN之前給大家指出的案例里面,只不過是吧那根地線從外面連接在了交換機的外殼上,而華為的交換機則是將地線從交換機的內部連接在了外殼上。本質上是沒有區別的。

          所以——電工說的“弱電不能接強電地”就有點太想當然了。

          那么問題來了,家里的弱電如何接地?

          當然是按照iN的方式來接了。為啥iN的交換機沒有得這樣接地呢?

          因為這款CSS610交換機是這樣供電的,交換機只能在電源端口取得直流電供給。并沒有被引入地線。所以這根地線咱們要手動的加一下。

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

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

          這種插頭大家應該都見過,基本上臺式機、電飯鍋什么的都會使用到,內置電源的交換機大部分也是使用這種插頭。

          使用這種線的結果就是——第一時間地線被從內部接入到了外殼上。

          當然了,你如果既不想在直流供電的小交換機上接一個小尾巴,又不想安裝一個相對比較大的內置電源的交換機,那么還有一個選擇就是用機架。

          沒錯,就是機架,如果你選用機架,并用螺絲將所有設備都固定在機架上,那么只要你的機架里面有一個設備是帶有電源接地的,那么所有的設備實際上就都接地了,這里有一個要點——你要用不帶漆膜的螺絲緊錮設備。

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

          如果這些都不愿意做,非得在不接地的情況下接通網絡,那么最好的處理方式就是——別用屏蔽電纜。

          擎反指紋瀏覽器是一種旨在減少或隱藏用戶瀏覽器指紋識別的技術和工具。下面將通過文字和視頻的方式詳細介紹反指紋瀏覽器的相關內容。

          反指紋瀏覽器的原理和技術

          反指紋瀏覽器的目標是減少用戶瀏覽器指紋的唯一性,從而減少用戶的跟蹤風險。為了實現這一目標,反指紋瀏覽器使用了許多技術和工具,包括:

          1. 用戶代理隨機化:用戶代理是指瀏覽器向服務器發送的包含瀏覽器信息的請求頭部,可以通過修改這個請求頭部來減少用戶的指紋唯一性。反指紋瀏覽器可以使用一些工具來隨機化用戶代理信息,使得每次請求時都發送不同的瀏覽器信息。
          2. 字體隨機化:字體是用戶指紋的一個重要組成部分,因為用戶的計算機上安裝的字體不同,可以用來區分不同的用戶。反指紋瀏覽器可以使用一些技術來隨機化字體信息,使得每次訪問時使用不同的字體。
          3. JavaScript 屏蔽:JavaScript 可以被用來獲取用戶的瀏覽器信息,因此屏蔽 JavaScript 可以減少用戶的指紋唯一性。反指紋瀏覽器可以使用一些工具來屏蔽 JavaScript。
          4. Cookie 隱身模式:Cookie 是網站用來存儲用戶信息的一種技術,可以用來跟蹤用戶的行為。反指紋瀏覽器可以使用一些技術來在瀏覽網站時使用隱身模式,從而避免 Cookie 被存儲在用戶的計算機上。
          5. 代理服務器:代理服務器可以用來隱藏用戶的 IP 地址,從而減少用戶的指紋唯一性。反指紋瀏覽器可以使用一些代理服務器來隱藏用戶的 IP 地址。

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

          反指紋瀏覽器的應用場景

          反指紋瀏覽器可以被用于多種應用場景,包括:

          1. 隱私保護:反指紋瀏覽器可以被用來保護用戶的隱私,避免用戶被跟蹤和監視。
          2. 安全測試:反指紋瀏覽器可以被用來測試網站

          o B 業務的生命周期與迭代通常會持續多年,隨著產品的迭代與演進,以接口調用為核心的前后端關系會變得非常復雜。在多年迭代后,接口的任何一處修改都可能給產品帶來難以預計的問題。在這種情況下,構建更穩健的前端應用,保證前端在長期迭代下的穩健與可拓展性就變得非常重要。本文將重點介紹如何利用接口防腐策略避免或減少接口變更對前端的影響。

          一 困境與難題

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

          此時前端組件與接口之間的依賴關系如下圖所示。

          當接口返回結構調整時MemoryFree 組件對接口的調用方式需要調整。同樣的,MemoryUsage 與 MemoryUsagePercent 也要進行修改才能工作。

          真實的 To B 業務面臨的接口可能會有數百個,組件與接口的集成邏輯也遠比以上的例子要復雜。

          經過數年甚至更長時間的迭代后,接口會逐步產生多個版本,出于對界面穩定性及用戶使用習慣的考量,前端往往會同時依賴接口的多個版本來構建界面。當部分接口需要調整下線或發生變更時,前端需要重新理解業務邏輯,并做出大量代碼邏輯調整才能保證界面穩定運行。

          常見的對前端造成影響的接口變更包括但不限于:

          • 返回字段調整
          • 調用方式改變
          • 多版本共存使用

          當前端面對的是平臺型業務時,此類問題會變得更為棘手。平臺型產品會對一種或多種底層引擎進行封裝,例如機器學習平臺可能會基于 TensorFlow、Pytorch 等機器學習引擎搭建,實時計算平臺可能基于 Flink、Spark 等計算引擎搭建。

          雖然平臺會對引擎的大部分接口進行上層封裝,但不可避免的仍然會有部分底層接口會直接被透傳到前端,在這個時候,前端不僅要應對平臺的接口變更,還會面臨著開源引擎接口的變更帶來的挑戰。

          前端在面臨的困境是由獨特的前后端關系決定的。與其他領域不同,在 To B 業務中,前端通常以下游客戶的身份接受后端供應商的供給,有些情況下會成為后端的跟隨者。

          在客戶/供應商關系中,前端處于下游,而后端團隊處于上游,接口內容與上線時間通常由后端團隊來決定。

          在跟隨者關系中,上游的后端團隊不會去根據前端團隊的需求進行任何調整,前端只能去順應上游后端的模型。這種情況通常發生在前端無法對上游后端團隊施加影響的時刻,例如前端需要基于開源項目的接口設計界面,或者是后端團隊的模型已經非常成熟且難以修改時。

          《架構整潔之道》的作者描述過這樣一個嵌入式架構設計的難題,與上文我們描述的困境十分類似。

          軟件應當是一種使用周期很長的東西,而固件會隨著硬件的演進而淘汰過時,但事實上的情況是,雖然軟件本身不會隨著時間推移而磨損,但硬件及其固件卻會隨時間推移而過時,隨即也需要對軟件做相應的改動。

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

          二 防腐層設計

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

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

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

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

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

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

          RxJS 是 ReactiveX 項目的 JavaScript 實現,而 ReactiveX 最早是 LINQ 的一個擴展,由微軟的架構師 Erik Meijer 領導的團隊開發。該項目目標是提供一致的編程接口,幫助開發者更方便的處理異步數據流。目前 RxJS 在開發中經常被作為響應式編程開發工具使用,但是在構建防腐層的場景中,RxJS 代表的 Observable 方案同樣可以發揮巨大作用。

          我們選擇 RxJS 主要基于以下幾點考慮:

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

          當在引入 RxJS 將所有類型的接口轉換為 Observable 對象后,前端的視圖組件將僅依賴 Observable,并與接口實現的細節解耦,同時,Observable 可以與 Promise 相互轉換,在視圖層獲得的是單純的 Promise,可以與任意數據層方案和框架搭配使用。

          除了轉換為 Promise 之外,開發者也可以與 RxJS 在渲染層的解決方案,例如 rxjs-hooks 混用,獲得更好的開發體驗。

          三 防腐層實現

          參照上文的防腐層設計,我們在開頭的儀表盤項目中實現以 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 的實現代碼如下,此時該組件將不再依賴具體的接口,而直接依賴防腐層的實現。

          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 返回字段調整

          返回字段變更時,防腐層可以有效攔截接口對組件的影響,當 /api/v2/quota/free 與 /api/v2/quota/usage 的返回數據變更為以下結構時

          {
            requestId: string;
            data: number;
          }

          我們只需要調整防腐層的兩行代碼,注意此時我們的上層封裝的 getMemoryUsagePercent 基于 Observable 構建所以不需要進行任何改動。

          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 化的防腐層中,會存在高階 Observable 與 低階 Observable 兩種設計,在上文的例子中,Free Observable 和 Usage Observable 為低階封裝,而 Percent Observable 利用 Free 和 Usage 的 Observable 進行了高階封裝,當低階封裝改動時,由于 Observable 本身的特性,高階封裝經常是不需要進行任何改動的,這也是防腐層給我們帶來的額外好處。

          2 調用方式改變

          當調用方式發生改變時,防腐層同樣可以發揮作用。/api/v3/memory 直接返回了 free 與 usage 的數據,接口格式如下。

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

          防腐層代碼只需要進行如下更新,就可以保障組件層代碼無需修改。

          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 多版本共存使用

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

          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))
            ));
          }

          通過 race 操作符,當 v2 與 v3 任何一個版本的接口可用時,防腐層都可以正常工作,在組件層無需再關注接口受環境的影響。

          四 額外應用

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

          1 概念映射

          接口語義與前端需要數據的語義有時并不能完全對應,當在組件層直接調用接口時,所有開發者都需要對接口與界面的語義映射足夠了解。有了防腐層后,防腐層提供的調用方法包含了數據的真實語義,減少了開發者的二次理解成本。

          2 格式適配

          在很多情況下,接口返回的數據結構與格式與前端需要的數據格式并不符合,通過在防腐層增加數據轉換邏輯,可以降低接口數據對業務代碼的入侵。在以上的案例里,我們封裝了 getMemoryUsagePercent 的數據返回,使得組件層可以直接使用百分比數據,而不需要再次進行轉換。

          3 接口緩存

          對于多種業務依賴同一接口的情況,我們可以通過防腐層增加緩存邏輯,從而有效降低接口的調用壓力。

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

          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 穩定性兜底

          當接口穩定性較差時,通常的做法是在組件層對 response error 的情況進行處理,這種兜底邏輯通常比較復雜,組件層的維護成本會很高。我們可以通過防腐層對穩定性進行兜底,當接口出錯時可以返回兜底業務數據,由于兜底數據統一維護在防腐層,后續的測試與修改也會更加方便。在上文中的多版本共存的防腐層中,增加以下代碼,此時即使 v2 和 v3 接口都無法返回數據,前端仍然可以保持可用。

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

          5 聯調與測試

          接口和前端可能會存在并行開發的狀態,此時,前端的開發并沒有真實的后端接口可用。與傳統的搭建 mock api 的方式相比,在防腐層直接對數據進行 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))
            );
          }

          在防腐層對數據進行 mock 也可以用于對頁面的測試,例如 mock 大量數據對頁面性能影響。

          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);
          }

          五 總結

          在本文中我們介紹了以下內容:

          1. 前端面對接口頻繁變動時的困境及原因如何
          2. 防腐層的設計思想與技術選型
          3. 使用 Observable 實現防腐層的代碼示例
          4. 防腐層的額外作用

          請讀者注意,只在特定的場景下引入前端防腐層才是合理的,即前端處于跟隨者或供應商/客戶關系中,且面臨大量接口無法保障穩定和兼容。如果在防腐層可以在后端 Gateway 構建,或者接口數量較少時,引入防腐層帶來的額外成本會大于其帶來的好處。

          RxJS 在防腐層構建場景下提供的更多的是 Observable 化的能力,如果讀者不需要復雜的 operators 轉換工具,也可以自行構建 Observable 構建方案,事實上只需要 100 行的代碼就可以實現 https://stackblitz.com/edit/mini-rxjs。

          改造后的前端架構將不再直接依賴接口實現,不會入侵現有前端數據層設計,還可以承擔概念映射、格式適配、接口緩存、穩定性兜底以及協助聯調測試等工作。文中所有的示例代碼都可以在倉庫 https://github.com/vthinkxie/rxjs-acl 獲得。

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

          本文為阿里云原創內容,未經允許不得轉載。


          主站蜘蛛池模板: 日韩高清国产一区在线| 中文字幕乱码亚洲精品一区| 亚洲成a人一区二区三区| 中文字幕人妻第一区| 伊人色综合视频一区二区三区| 2020天堂中文字幕一区在线观| 亚洲国产精品一区二区成人片国内| 插我一区二区在线观看| 日韩一本之道一区中文字幕| 国精品无码一区二区三区在线| 亚洲一区二区三区AV无码| 国产内射在线激情一区| 久久久久人妻精品一区蜜桃| 亚洲国产精品一区二区久久| 日本一区二区在线播放| 学生妹亚洲一区二区| 免费高清av一区二区三区| 国产日韩精品一区二区在线观看| 国产人妖在线观看一区二区| jazzjazz国产精品一区二区| 伊人激情AV一区二区三区| 无码人妻精品一区二区三18禁| 日韩精品视频一区二区三区 | 视频在线观看一区| 日韩少妇无码一区二区三区| 中文字幕一区二区三区免费视频| 国产在线精品一区二区在线观看| 91在线精品亚洲一区二区| 无码日韩精品一区二区免费| 国产一区精品视频| 中文字幕aⅴ人妻一区二区| 久久无码人妻一区二区三区午夜| 亚洲av日韩综合一区久热| 国产一区二区三区福利| 农村人乱弄一区二区| 亚洲国产系列一区二区三区| 精品不卡一区中文字幕| 久久亚洲一区二区| 日韩aⅴ人妻无码一区二区| 精品aⅴ一区二区三区| 亚洲中文字幕一区精品自拍 |