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

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

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

          對(duì)微前端的11個(gè)錯(cuò)誤認(rèn)識(shí)

          對(duì)微前端的11個(gè)錯(cuò)誤認(rèn)識(shí)

          文最初發(fā)布于 Bits and Pieces 博客,經(jīng)原作者授權(quán)由 InfoQ 中文站翻譯并分享。

          微前端是一個(gè)可以追溯到多年前的新趨勢(shì)。隨著新方法的出現(xiàn)以及各種挑戰(zhàn)被克服,它們正在慢慢地進(jìn)入主流。但遺憾的是,許多非常明顯的認(rèn)識(shí)誤區(qū),讓許多人很難理解微前端到底是什么。

          簡(jiǎn)而言之,微前端就是將微服務(wù)的一些好處引入前端。除此之外,我們不應(yīng)該忘記,微服務(wù)也不是什么“銀彈”。

          提示:要在微前端或任何其他項(xiàng)目之間共享 React/Angular/Vue 組件,可以使用像 Bit 這樣的工具。它允許你從任何代碼庫中“harvest”組件,并將它們共享到 bit.dev 的一個(gè)集合中。它讓團(tuán)隊(duì)可以在任何存儲(chǔ)庫中使用你的組件。使用它可以優(yōu)化協(xié)作、加速開發(fā)和保持 UI 一致性。

          示例:在 bit.dev 中查找共享 React 組件

          認(rèn)識(shí)誤區(qū)

          我想列一下在過去幾個(gè)月中,我最常聽到的關(guān)于微前端的誤解。先從從一個(gè)明顯的例子開始。

          微前端需要 JavaScript

          目前,許多微前端解決方案都是 JavaScript 框架。這怎么可能錯(cuò)呢?JavaScript 不再是可選的。每個(gè)人都想要高度交互的體驗(yàn),而 JS 在提供這些體驗(yàn)中發(fā)揮著至關(guān)重要的作用。

          除了加載速度快、可訪問 Web 應(yīng)用的優(yōu)點(diǎn)外,還有其他因素應(yīng)該考慮。因此,許多 JavaScript 框架都提供了 isomorphic 渲染能力。最終,這讓它們不僅能夠在客戶端進(jìn)行拼接(stitch),還能在服務(wù)器上準(zhǔn)備好一切。如果有性能要求(如第一次有意義渲染的初始時(shí)間),這個(gè)選項(xiàng)聽起來很不錯(cuò)。

          請(qǐng)記住,isomorphic 渲染有其自身的挑戰(zhàn)。

          然而,即使一個(gè) JavaScript 解決方案沒有提供 isomorphic 呈現(xiàn),這也沒什么問題。如果不想在構(gòu)建微前端時(shí)使用 JavaScript,我們當(dāng)然可以這樣做。有許多模式,其中很多根本不需要 JavaScript。

          考慮一種“比較舊的”模式:使用<frameset>。我聽見你笑了?好吧,有一些現(xiàn)如今人們?cè)噲D做的分割,它以前就支持了(下文有更詳細(xì)的討論)。一個(gè)頁面(可能由另一個(gè)服務(wù)渲染)負(fù)責(zé)菜單,而另一個(gè)頁面負(fù)責(zé)標(biāo)題。

          復(fù)制代碼

          <frameset cols="25%,*,25%">  <frame src="menu.html">  <frame src="content.html">  <frame src="sidebar.html"></frameset>

          如今,我們使用更靈活(且仍然受到活躍支持)的<iframe>元素。它們提供了一些很好的特性——最重要的是使得不同的微前端相互隔離,但仍然可以通過postMessage進(jìn)行通信。

          微前端只在客戶端有效

          在 JavaScript 認(rèn)識(shí)誤區(qū)之后,這是下一個(gè)層次。當(dāng)然,在客戶端有多種技術(shù)可以實(shí)現(xiàn)微前端,實(shí)際上,我們甚至不需要<iframe>或任何類似的技術(shù)。

          微前端可以像服務(wù)器端“includes”一樣簡(jiǎn)單。有了諸如 Edge Side Includes 之類的高級(jí)技術(shù),這將變得更加強(qiáng)大。如果我們排除了在微前端功能中實(shí)現(xiàn)的微前端場(chǎng)景,那么即使是簡(jiǎn)單的鏈接也可以很好的工作。最終,微前端解決方案也能像小而獨(dú)立的服務(wù)器端渲染器一樣簡(jiǎn)單。每個(gè)渲染器可能只有一個(gè)頁面那么小。

          下圖展示了在反向代理中發(fā)生的更高級(jí)的拼接:

          通過反向代理實(shí)現(xiàn)服務(wù)器端拼接

          當(dāng)然,可能 JavaScript 有許多優(yōu)點(diǎn),但它仍然高度依賴于你試圖通過微前端解決的問題。根據(jù)你的需要,服務(wù)器端解決方案可能仍然是最好的(或者至少是更好的)選擇。

          你應(yīng)該使用多個(gè)框架

          在幾乎每一個(gè)關(guān)于微前端的教程中,不同的部分不僅由不同的團(tuán)隊(duì)開發(fā),而且使用了不同的技術(shù)。這是假的。

          適當(dāng)?shù)奈⑶岸朔椒赡苁褂貌煌募夹g(shù),但是,這不應(yīng)該是目標(biāo)。我們做微服務(wù)也不只是為了在后端拼湊技術(shù)。如果我們使用多種技術(shù),那只是因?yàn)槲覀儷@得了一個(gè)特定的好處。

          我們的目標(biāo)應(yīng)該始終是某種統(tǒng)一性。最好的方法是考慮一個(gè)新項(xiàng)目:我們會(huì)怎么做?如果答案是“使用單一框架”,那么我們就走上正軌了。

          長(zhǎng)遠(yuǎn)來看,有很多原因可以解釋為什么應(yīng)用程序中會(huì)出現(xiàn)多個(gè)框架??赡苁沁z留的,可能為了方便,也可能是一個(gè)概念驗(yàn)證。無論是什么原因:能夠處理這種場(chǎng)景還是不錯(cuò)的,但它絕不應(yīng)該是開始就希望達(dá)到的狀態(tài)。

          不管你的微前端框架多高效——使用多個(gè)框架總是要付出不可忽視的代價(jià)。不僅初始渲染會(huì)花費(fèi)更長(zhǎng)的時(shí)間,而且內(nèi)存消耗也會(huì)朝著錯(cuò)誤的方向發(fā)展。不能使用方便模型(例如,針對(duì)某個(gè)框架的模式庫)。需要更多的重復(fù)。最終,程序的 Bug 數(shù)量、不一致行為和可感知的響應(yīng)性都會(huì)受到影響。

          按技術(shù)組件劃分

          一般來說,這沒有多大意義。我還沒見過微服務(wù)后端的數(shù)據(jù)處理在一個(gè)服務(wù)中而 API 在另一個(gè)服務(wù)中。通常,服務(wù)由多個(gè)層組成。雖然某些技術(shù)內(nèi)容(如日志記錄)肯定會(huì)引入到公共服務(wù)中,但有時(shí)也會(huì)使用諸如 Sidecar 之類的技術(shù)。此外,還需要通用服務(wù)編程技術(shù)。

          對(duì)于微前端,情況也是如此。為什么一個(gè)微前端只能做菜單?每個(gè)微前端都有相應(yīng)的菜單嗎?拆分應(yīng)該根據(jù)業(yè)務(wù)需求來做,而不是技術(shù)決策。如果你讀過一些關(guān)于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的書,你就會(huì)知道它是關(guān)于定義這些領(lǐng)域的——而這個(gè)定義與任何技術(shù)要求無關(guān)。

          考慮以下劃分:

          按布局分解成微前端

          這些都是技術(shù)組件,和微前端無關(guān)。在一個(gè)真實(shí)的微前端應(yīng)用程序中,屏幕可能看起來是這樣的。

          按領(lǐng)域分解成微前端

          的確,這里的拼接要復(fù)雜得多,但這是一個(gè)可靠的微前端應(yīng)用程序應(yīng)該為你提供的!

          不應(yīng)該共享任何東西

          不。你應(yīng)該共享那些值得共享的東西。你絕對(duì)不應(yīng)該共享所有東西(見下一條)。但要做到始終如一,你至少需要共享一套原則。至于是通過共享庫、共享 URL,或者只是在構(gòu)建或設(shè)計(jì)應(yīng)用程序時(shí)使用的文檔,那就不重要了。

          對(duì)于微服務(wù),“無共享”架構(gòu)如下圖所示:

          微服務(wù)的“無共享”架構(gòu)

          在瀏覽器中,這將導(dǎo)致使用<iframe>,因?yàn)槟壳皼]有其他方法可以防止資源泄漏。使用影子 DOM,則 CSS 可能會(huì)被隔離,但腳本層面仍然能訪問所有內(nèi)容。

          即使想遵循無共享的架構(gòu),我們也會(huì)遇到麻煩。

          當(dāng)然,共享的程度越深(例如,使用一個(gè)通過應(yīng)用 shell 追加到 DOM 的共享庫),就越會(huì)出問題。另一方面,共享程度越淺(例如,只是一個(gè)指定基本設(shè)計(jì)元素的文檔),就會(huì)出現(xiàn)更多的不一致性。

          應(yīng)該共享一切

          絕對(duì)不是。如果這樣想,那么單體更有意義。就性能而言,這可能已經(jīng)是一個(gè)問題了。什么可以延遲加載?我們能去掉一些東西嗎?但真正的問題是依賴管理。什么都不能更新,因?yàn)樗赡軙?huì)破壞某個(gè)東西。

          共享部件的好處是一致性保證。

          現(xiàn)在,如果我們共享所有的東西,我們就是用復(fù)雜性來換一致性。這種一致性是不可維護(hù)的,因?yàn)閺?fù)雜性會(huì)在每個(gè)角落引入 Bug。

          問題的根源在于“依賴地獄”。下圖很好地說明了這一點(diǎn)。

          簡(jiǎn)而言之,如果一切都相互依賴,那么我們就會(huì)有依賴問題。僅僅更新一個(gè)方框就會(huì)影響整個(gè)系統(tǒng)。一致嗎?確實(shí)。簡(jiǎn)單的?絕不。

          微前端只是 Web 端的

          為什么只是 Web?誠(chéng)然,到目前為止,我們接觸到的主要是 Web,但其概念和想法可以應(yīng)用于任何類型的應(yīng)用程序(移動(dòng)應(yīng)用、客戶端應(yīng)用……甚至是 CLI 工具)。在我看來,微前端只是“插件架構(gòu)”的一個(gè)花哨叫法。不過,插件接口如何設(shè)計(jì),以及運(yùn)行使用插件的應(yīng)用程序需要具備什么條件,這就是另外一回事了。

          下圖顯示了一個(gè)非常通用的插件架構(gòu),來自 Omar Elgabry :

          通用插件架構(gòu)

          該架構(gòu)并沒有在哪里運(yùn)行的概念。它既可以在手機(jī)上運(yùn)行,也能在 Windows 上運(yùn)行,甚至還能在服務(wù)器上運(yùn)行。

          微前端需要大型團(tuán)隊(duì)

          為什么?如果解決方案超級(jí)復(fù)雜,那么我肯定會(huì)找一個(gè)簡(jiǎn)單的。有些問題需要復(fù)雜的解決方案,但好的解決方案通常是簡(jiǎn)單的。

          根據(jù)場(chǎng)景的不同,它甚至可能不需要一個(gè)分布式團(tuán)隊(duì)。擁有分布式團(tuán)隊(duì)是采用微前端的首要原因之一,但這不是唯一原因。另一個(gè)很好的理由是特性的粒度。

          如果從業(yè)務(wù)的角度來看微前端,那么你就會(huì)發(fā)現(xiàn),擁有啟用和關(guān)閉特定特性的能力是很有意義的。針對(duì)不同的市場(chǎng),使用不同的微前端。回到一個(gè)簡(jiǎn)單的權(quán)限模式,這是有意義的。不需要編寫代碼來根據(jù)特定條件打開或關(guān)閉某些東西。所有這些都留給公共層,可以根據(jù)(可能是動(dòng)態(tài)的)條件激活或停用。

          這樣,不能(或不應(yīng)該)使用的代碼也不會(huì)被交付。雖然這不應(yīng)該是一個(gè)保護(hù)層,但它肯定是一個(gè)便捷(和性能)層。用戶不會(huì)感到困惑,因?yàn)樗麄兛吹降氖撬麄兡茏龅?。他們看不到?jīng)]有交付的功能,所以沒有字節(jié)浪費(fèi)在不可用的代碼上。

          微前端無法調(diào)試

          對(duì)于任何類型的實(shí)現(xiàn)(或供討論的底層架構(gòu)),開發(fā)經(jīng)驗(yàn)都可能遭到削弱。應(yīng)對(duì)這種情況的唯一方法是開發(fā)人員優(yōu)先。實(shí)現(xiàn)中的第一原則應(yīng)該是:使調(diào)試和開發(fā)成為可能。采用標(biāo)準(zhǔn)的工具。

          有些微前端框架根本不接受這一點(diǎn)。有些需要在線連接、專用環(huán)境、多重服務(wù)……這不應(yīng)該是標(biāo)準(zhǔn),也絕不是常態(tài)。

          微服務(wù)需要微前端(或反過來)

          解耦的模塊化后端可能為解耦前端打下了一個(gè)很好的基礎(chǔ),但通常情況下,情況并非如此。后端單體,前端模塊化,也是完全可行的,例如,為簡(jiǎn)化個(gè)性化可能就要結(jié)合授權(quán)、權(quán)限和市場(chǎng)。

          實(shí)際上,同樣,微服務(wù)后端并不能證明適合將類似的模式應(yīng)用于前端。許多微服務(wù)后端都是由單用途的應(yīng)用程序操作的,它們的功能沒有增加,只是外觀發(fā)生了改變。

          微前端需要單存儲(chǔ)庫

          我已經(jīng)讀到過好幾次,要?jiǎng)?chuàng)建一個(gè)微前端解決方案,就需要利用單存儲(chǔ)庫,最好使用像 Lerna 這樣的工具。我不認(rèn)可這一點(diǎn)。當(dāng)然,單存儲(chǔ)庫有一些優(yōu)點(diǎn),但也有明顯的缺點(diǎn)。

          雖然有一些微前端框架需要聯(lián)合 CI/CD 構(gòu)建,但大多數(shù)都不需要。聯(lián)合 CI/CD 構(gòu)建通常會(huì)導(dǎo)致單存儲(chǔ)庫,因?yàn)槠湓O(shè)置要簡(jiǎn)單得多。但對(duì)我來說,這是單體重新打包。如果你在單存儲(chǔ)庫上進(jìn)行聯(lián)合構(gòu)建,那么你就失去了讓微前端富有吸引力的兩個(gè)非常重要的優(yōu)點(diǎn):

          1. 獨(dú)立部署
          2. 獨(dú)立開發(fā)

          不管怎樣,如果你看到微前端解決方案需要單存儲(chǔ)庫:那樣做就行。一個(gè)精心設(shè)計(jì)的單體系統(tǒng)可能會(huì)更好,它不會(huì)有分布式系統(tǒng)的所有問題。

          結(jié)論

          微前端技術(shù)并不適合所有人。我不認(rèn)為微前端是未來的發(fā)展趨勢(shì),但我也相信它們?cè)谖磥頃?huì)發(fā)揮重要作用。


          關(guān)注我并轉(zhuǎn)發(fā)此篇文章,私信我“領(lǐng)取資料”,即可免費(fèi)獲得InfoQ價(jià)值4999元迷你書,點(diǎn)擊文末「了解更多」,即可移步InfoQ官網(wǎng),獲取最新資訊~

          一文章中整合了spring cloud 用Sentinel來實(shí)現(xiàn)降級(jí)熔斷,并用Nacos來作為配置存儲(chǔ)。需要看的朋友可以查看我的主頁,或者直接點(diǎn)擊:面對(duì)大流量如何優(yōu)雅熔斷降級(jí)Sentinel實(shí)踐 。在上文我們實(shí)現(xiàn)了Sentine控制臺(tái)將配置推送到應(yīng)用服務(wù),但是還沒有實(shí)現(xiàn)Sentine控制臺(tái)將配置實(shí)時(shí)推拉到Nacos,本文將通過修改官方的源碼來實(shí)現(xiàn)此步驟。

          上篇文章中的推拉數(shù)據(jù)如下:


          Sentinel控制臺(tái)并沒有與遠(yuǎn)程配置中心Nacos相連接。本文將實(shí)現(xiàn)連接到配置中心。


          一、下載官方源碼

          可以下載最新的版本的:

          https://github.com/alibaba/Sentinel

          ,也可以下載穩(wěn)定版本的地方下載源碼:

          https://github.com/alibaba/Sentinel/releases

          二、修改pom.xml中的sentinel-datasource-nacos的依賴,將<scope>test</scope>注釋掉,這樣才能在主程序中使用

          具體如下:

                 <!-- for Nacos rule publisher sample -->
                  <dependency>
                      <groupId>com.alibaba.csp</groupId>
                      <artifactId>sentinel-datasource-nacos</artifactId>
          <!--            使用Sentinel Dashboard動(dòng)態(tài)推拉數(shù)據(jù)同步到Nacos 注掉test-->
          <!--            <scope>test</scope>-->
                  </dependency>


          三、修改sidebar.html的dashboard.flowV1為dashboard.flow

          找到resources/app/scripts/directives/sidebar/sidebar.html中的這段代碼

          把原來:

          <li ui-sref-active="active">
            <a ui-sref="dashboard.flowV1({app: entry.app})">
              <i class="glyphicon glyphicon-filter"></i>  流控規(guī)則
            </a>
          </li>

          修改為:

          <li ui-sref-active="active">
            <a ui-sref="dashboard.flow({app: entry.app})">
              <i class="glyphicon glyphicon-filter"></i>  流控規(guī)則
            </a>
          </li>

          如下:

          四、修改flow_v2.html里的dashboard.flowV1為dashboard.flow

          原來:

          <a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})">
            回到單機(jī)頁面
          </a>

          修改為:

          <a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flow({app: app})">
            回到單機(jī)頁面
          </a>

          修改效果如下:

          五、修改identity.js文件的 FlowServiceV1 為FlowServiceV2

          如下圖:

          六、開始修改dashboard的java源碼,讀取為通過Nacos

          包的結(jié)構(gòu)圖如下:

          1、添加FlowRuleNacosProvider

          import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
          import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
          import com.alibaba.csp.sentinel.datasource.Converter;
          import com.alibaba.csp.sentinel.util.StringUtil;
          import com.alibaba.nacos.api.config.ConfigService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.stereotype.Component;
          
          import java.util.ArrayList;
          import java.util.List;
          
          /**
           * @author Eric Zhao,yaokj
           * @since 1.4.0
           */
          @Component("flowRuleNacosProvider")
          public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
          
              @Autowired
              private NacosConfigProperties nacosConfigProperties;
          
              @Autowired
              private ConfigService configService;
              @Autowired
              private Converter<String, List<FlowRuleEntity>> converter;
          
              @Override
              public List<FlowRuleEntity> getRules(String appName) throws Exception {
                  String dataidPostfix=NacosConfigUtil.FLOW_DATA_ID_POSTFIX;
                  if(StringUtil.isNotBlank(nacosConfigProperties.getDataidPostfix())){
                      dataidPostfix=nacosConfigProperties.getDataidPostfix();
                  }
          
                  String rules=configService.getConfig(appName + dataidPostfix, nacosConfigProperties.getGroupId(), 3000);
                  if (StringUtil.isEmpty(rules)) {
                      return new ArrayList<>();
                  }
                  return converter.convert(rules);
          
              }
          }

          2、添加FlowRuleNacosPublisher

          
          import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
          import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
          import com.alibaba.csp.sentinel.datasource.Converter;
          import com.alibaba.csp.sentinel.util.AssertUtil;
          import com.alibaba.csp.sentinel.util.StringUtil;
          import com.alibaba.nacos.api.config.ConfigService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.stereotype.Component;
          
          import java.util.List;
          
          /**
           * @author Eric Zhao,yaokj
           * @since 1.4.0
           */
          @Component("flowRuleNacosPublisher")
          public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
          
              @Autowired
              private NacosConfigProperties nacosConfigProperties;
          
              @Autowired
              private ConfigService configService;
              @Autowired
              private Converter<List<FlowRuleEntity>, String> converter;
          
              @Override
              public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
                  AssertUtil.notEmpty(app, "app name cannot be empty");
                  if (rules==null) {
                      return;
                  }
          
                  String dataidPostfix=NacosConfigUtil.FLOW_DATA_ID_POSTFIX;
                  if(StringUtil.isNotBlank(nacosConfigProperties.getDataidPostfix())){
                      dataidPostfix=nacosConfigProperties.getDataidPostfix();
                  }
          
                  configService.publishConfig(app + dataidPostfix, nacosConfigProperties.getGroupId(), converter.convert(rules));
              }
          }
          

          3、添加NacosConfig

          
          import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
          import com.alibaba.csp.sentinel.datasource.Converter;
          import com.alibaba.fastjson.JSON;
          import com.alibaba.nacos.api.PropertyKeyConst;
          import com.alibaba.nacos.api.config.ConfigFactory;
          import com.alibaba.nacos.api.config.ConfigService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          
          import java.util.List;
          import java.util.Properties;
          
          /**
           * @author Eric Zhao,yaokj
           * @since 1.4.0
           */
          @Configuration
          public class NacosConfig {
              @Autowired
              private NacosConfigProperties nacosConfigProperties;
          
              @Bean
              public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
                  return JSON::toJSONString;
              }
          
              @Bean
              public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
                  return s -> JSON.parseArray(s, FlowRuleEntity.class);
              }
          
              @Bean
              public ConfigService nacosConfigService() throws Exception {
                  Properties properties=new Properties();
                  properties.put(PropertyKeyConst.SERVER_ADDR, nacosConfigProperties.getServerAddr());
                  properties.put(PropertyKeyConst.NAMESPACE, nacosConfigProperties.getNamespace());
                  return ConfigFactory.createConfigService(properties);
                  
              }
          }

          4、添加NacosConfigProperties

          
          import org.springframework.boot.context.properties.ConfigurationProperties;
          import org.springframework.stereotype.Component;
          
          /**
           * yaokj
           */
          @Component
          @ConfigurationProperties(prefix="nacos.server")
          public class NacosConfigProperties {
          
              private String ip;
          
              private String port;
          
              private String namespace;
          
              private String groupId;
          
              private String dataidPostfix;
          
              public String getIp() {
                  return ip;
              }
          
              public void setIp(String ip) {
                  this.ip=ip;
              }
          
              public String getPort() {
                  return port;
              }
          
              public void setPort(String port) {
                  this.port=port;
              }
          
              public String getNamespace() {
                  return namespace;
              }
          
              public void setNamespace(String namespace) {
                  this.namespace=namespace;
              }
          
              public String getGroupId() {
                  return groupId;
              }
          
              public void setGroupId(String groupId) {
                  this.groupId=groupId;
              }
          
              public String getDataidPostfix() {
                  return dataidPostfix;
              }
          
              public void setDataidPostfix(String dataidPostfix) {
                  this.dataidPostfix=dataidPostfix;
              }
          
              public String getServerAddr() {
                  return this.getIp()+":"+this.getPort();
              }
          
              @Override
              public String toString() {
                  return "NacosConfigProperties{" +
                          "ip='" + ip + '\'' +
                          ", port='" + port + '\'' +
                          ", namespace='" + namespace + '\'' +
                          ", groupId='" + groupId + '\'' +
                          ", dataidPostfix='" + dataidPostfix + '\'' +
                          '}';
              }
          }
          

          5、添加NacosConfigUtil

          
          /**
           * @author yaokj
           * @since 1.4.0
           */
          public final class NacosConfigUtil {
          
              public static final String GROUP_ID="SENTINEL_GROUP";
              
              public static final String FLOW_DATA_ID_POSTFIX="-flow-rules";
              public static final String PARAM_FLOW_DATA_ID_POSTFIX="-param-rules";
              public static final String CLUSTER_MAP_DATA_ID_POSTFIX="-cluster-map";
          
              /**
               * cc for `cluster-client`
               */
              public static final String CLIENT_CONFIG_DATA_ID_POSTFIX="-cc-config";
              /**
               * cs for `cluster-server`
               */
              public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX="-cs-transport-config";
              public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX="-cs-flow-config";
              public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX="-cs-namespace-set";
          
              private NacosConfigUtil() {}
          }
          

          6、在application.properties添加Nacos配置

          #nacos
          nacos.server.ip=nacos-web.test.xx.net
          nacos.server.port=80
          nacos.server.namespace=sentinel-config
          nacos.server.group-id=SENTINEL_GROUP
          nacos.server.dataid-postfix=-flow-rules

          如下:


          七、然后修改FlowControllerV2中的默認(rèn)DynamicRuleProvider和DynamicRulePublisher

          將FlowControllerV2類的:

          @Autowired
          @Qualifier("flowRuleDefaultProvider")
          private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
          @Autowired
          @Qualifier("flowRuleDefaultPublisher")
          private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

          修改為:

          @Autowired
          @Qualifier("flowRuleNacosProvider")
          private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
          @Autowired
          @Qualifier("flowRuleNacosPublisher")
          private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;


          八、演示

          通過上面的步驟已經(jīng)修改完成源碼了。

          1、在客戶端服務(wù)應(yīng)用zizai-wxwork-api的配置為如下

          spring:
            cloud:
              sentinel:
                transport:
                  dashboard: localhost:8080
                datasource:
                  ds:
                    nacos:
                      server-addr: nacos-web.test.xx.net:80
                      dataId: ${spring.application.name}-flow-rules
                      groupId: SENTINEL_GROUP
                      namespace: sentinel-config
                      data-type: json
                      rule-type: flow
              nacos:
                discovery:
                  server-addr: nacos-web.test.xx.net:80
                  namespace: c8d3b947-7c0b-4cc6-9958-xx

          2、Nacos的配置為如下

          3、在Sentinel控制臺(tái)上配置便可以同步過去


          4、打開Nacos查看,可看到同步成功



          實(shí)現(xiàn)了限流。


          喜歡的朋友評(píng)論、點(diǎn)贊、轉(zhuǎn)發(fā)、收藏本文。有疑問的在評(píng)論區(qū)留言。謝謝!

          可能會(huì)認(rèn)為釣魚網(wǎng)站很難檢測(cè)和跟蹤,但實(shí)際上,許多釣魚網(wǎng)站都包含唯一標(biāo)識(shí)它們的HTML片段。

          你可能會(huì)認(rèn)為釣魚網(wǎng)站很難檢測(cè)和跟蹤,但實(shí)際上,許多釣魚網(wǎng)站都包含唯一標(biāo)識(shí)它們的HTML片段。本文就以英國(guó)皇家郵政(Royal Mail)釣魚網(wǎng)站為例來進(jìn)行說明,它們都包含字符串css_4WjozGK8ccMNs2W9MfwvMVZNPzpmiyysOUq4_0NulQo。

          這些長(zhǎng)而隨機(jī)的字符串是追蹤釣魚網(wǎng)站的絕佳指標(biāo),幾乎可以肯定,任何含有css_4WjozGK8ccMNs2W9MfwvMVZNPzpmiyysOUq4_0NulQo的網(wǎng)頁都是皇家郵政釣魚工具的實(shí)例。

          但是,像這樣的獨(dú)特字符串最終如何成為檢測(cè)網(wǎng)絡(luò)釣魚工具標(biāo)識(shí)的呢?

          不幸的是,我們并不是RFC 3514的模仿者,在RFC 3514中,如果所有的IP數(shù)據(jù)包是惡意的,那么它們都包含一個(gè)標(biāo)志信號(hào)。不,這些識(shí)別字符串完全是由釣魚工具開發(fā)者無意中包含的。

          →【網(wǎng)絡(luò)安全更多技術(shù)學(xué)習(xí)資料包】←

          釣魚工具是如何誕生的?

          釣魚網(wǎng)站試圖盡可能接近他們真正的目標(biāo)網(wǎng)站,然而,大多數(shù)釣魚者并不具備復(fù)制公司網(wǎng)站的技能。相反,他們采用了快捷方式,只是假冒了原始網(wǎng)站的HTML并對(duì)其進(jìn)行了一些小的調(diào)整。

          假冒目標(biāo)網(wǎng)站并將其變成釣魚工具的過程大致如下:

          1.使用諸如HTTrack之類的工具復(fù)制目標(biāo)網(wǎng)站,甚至只需在網(wǎng)絡(luò)瀏覽器中點(diǎn)擊文件→保存即可。

          2.調(diào)整HTML以添加一個(gè)請(qǐng)求受害者個(gè)人信息的表單。

          3.將其與PHP后端粘合在一起,以保存收集到的數(shù)據(jù)。

          然后,可以將該工具包輕松部署到便宜的托管服務(wù)提供商上,并準(zhǔn)備收集受害者的詳細(xì)信息。

          4.通過復(fù)制整個(gè)網(wǎng)頁,釣魚者幾乎不需要什么技巧或精力即可獲得一個(gè)超級(jí)逼真的釣魚頁面。但是,這種假冒模式意味著他們的釣魚頁面充滿了他們實(shí)際上并不需要的東西。

          特別是,原始網(wǎng)站中的任何特殊字符串都有可能意外地出現(xiàn)在最終的釣魚工具中。這對(duì)我們來說很好,因?yàn)閷ふ姨厥庾址且环N非常容易和可靠的方法來檢測(cè)釣魚網(wǎng)站。

          所謂的特殊字符串就是一個(gè)足夠長(zhǎng)或復(fù)雜的字符串,該字符串在整個(gè)互聯(lián)網(wǎng)上都是獨(dú)一無二的,這可能是因?yàn)樗请S機(jī)字符(如64a9e3b8)或只是因?yàn)樗銐蜷L(zhǎng)。

          那么,問題來了:為什么在最初的網(wǎng)站中會(huì)有這些字符串?事實(shí)證明,在現(xiàn)代開發(fā)實(shí)踐中,網(wǎng)站到處都是這些足夠長(zhǎng)或復(fù)雜的字符串。

          網(wǎng)頁中長(zhǎng)或復(fù)雜的字符串是怎么來的?

          現(xiàn)代網(wǎng)站很少是100%靜態(tài)的內(nèi)容,當(dāng)前的開發(fā)實(shí)踐和網(wǎng)絡(luò)安全特性意味著,有多種方法可以使冗長(zhǎng)的隨機(jī)字符串最終出現(xiàn)在網(wǎng)站中。以下是我所見過的各種來源的概述:

          1.文件名中的哈希

          現(xiàn)代網(wǎng)站通常使用諸如Webpack或Parcel之類的“捆綁包”進(jìn)行處理,這些捆綁包將所有JavaScript和CSS組合成一組文件。例如,網(wǎng)站的sidebar.css和footer.css可能合并為一個(gè)styles.css文件。

          為了確保瀏覽器獲得這些文件的正確版本,捆綁程序通常在文件名中包含一個(gè)哈希。昨天你的網(wǎng)頁可能使用的是styles.64a9e3b8.css,但是在更新你的樣式表之后,它現(xiàn)在使用的是styles.a4b3a5ee.css。這個(gè)文件名的改變迫使瀏覽器獲取新的文件,而不是依賴于它的緩存。

          但這些足夠長(zhǎng)或復(fù)雜的文件名正是最近皇家郵政(Royal Mail)的釣魚工具被發(fā)現(xiàn)的原因。

          當(dāng)釣魚者假冒真正的皇家郵政網(wǎng)站時(shí),HTML看起來是這樣的:

          不幸的是,不管他們用什么技術(shù)來假冒網(wǎng)站,文件名都沒有改變。因此,通過urlscan.io查找大量使用CSS文件的釣魚網(wǎng)站是很容易的:

          2. 版本控制參考

          網(wǎng)絡(luò)釣魚者針對(duì)的任何網(wǎng)站很可能都是由一個(gè)團(tuán)隊(duì)開發(fā)的,他們很可能會(huì)使用git等版本控制系統(tǒng)(VCS)進(jìn)行協(xié)作。

          一個(gè)合理的常見的選擇是在網(wǎng)站的每一個(gè)構(gòu)建中嵌入一個(gè)來自VCS的參考,這有助于完成諸如將漏洞報(bào)告與當(dāng)時(shí)正在運(yùn)行的代碼版本相關(guān)聯(lián)之類的任務(wù)。

          例如,Monzo網(wǎng)站使用一個(gè)小的JavaScript代碼片段嵌入了git commit哈希:

          VCS參考資料對(duì)于安防人員來說非常有用,因?yàn)樗鼈兒苋菀自诎姹究刂葡到y(tǒng)中找到。如果你發(fā)現(xiàn)一個(gè)釣魚網(wǎng)站無意中包含了VCS參考,你就可以直接查找該網(wǎng)站的編寫時(shí)間(也就是該網(wǎng)站被假冒的時(shí)間)。

          3.SaaS的API密鑰

          網(wǎng)站經(jīng)常使用各種第三方服務(wù),如對(duì)講機(jī)或reCAPTCHA。為了使用這些服務(wù),網(wǎng)站通常需要包含相關(guān)的JavaScript庫以及一個(gè)API密鑰。

          例如,Tide使用reCAPTCHA,并將這段代碼作為其集成的一部分:

          因?yàn)閞eCAPTCHA “sitekey” 對(duì)每個(gè)網(wǎng)站來說都是唯一的,因此任何包含字符串6Lclb0UaAAAAAJJVHqW2L8FXFAgpIlLZF3SPAo3w且不在tide.co上的頁面都很可能是假冒的網(wǎng)站。

          雖然SaaS API密鑰是非常獨(dú)特的,并且具有很好的指示作用,但它們變化非常少,因此無法區(qū)分從同一網(wǎng)站假冒出來的不同釣魚工具。一個(gè)網(wǎng)站可能會(huì)使用相同的API密鑰達(dá)數(shù)年之久,因此在那時(shí)創(chuàng)建的所有工具包都將包含相同的密鑰。出于同樣的原因,API密鑰對(duì)于識(shí)別何時(shí)創(chuàng)建網(wǎng)絡(luò)釣魚工具包也沒有任何幫助。

          4. 跨站請(qǐng)求偽造(CSRF)令牌

          事實(shí)證明,許多網(wǎng)絡(luò)安全最佳實(shí)踐也使網(wǎng)絡(luò)釣魚成為重要的指標(biāo)。其中最常見的可能是“跨網(wǎng)站請(qǐng)求偽造”(CSRF)令牌。

          簡(jiǎn)單地說,CSRF是一個(gè)漏洞,惡意網(wǎng)站可以借此誘騙用戶在目標(biāo)網(wǎng)站上執(zhí)行經(jīng)過身份驗(yàn)證的操作。例如,此HTML創(chuàng)建了一個(gè)按鈕,點(diǎn)擊該按鈕可將POST請(qǐng)求發(fā)送到https://example.com/api/delete-my-account":

          如果example.com不能防御CSRF,它將處理此請(qǐng)求并刪除毫無戒心的用戶帳戶。

          防御CSRF的最常見方法是使用所謂的CSRF令牌,這是一個(gè)嵌入在每個(gè)網(wǎng)頁中的隨機(jī)值,服務(wù)器希望將其與敏感請(qǐng)求一起發(fā)送回去。例如,example.com的“刪除我的賬戶”按鈕應(yīng)該是這樣的:

          服務(wù)器將拒絕任何不包含預(yù)期隨機(jī)值的請(qǐng)求。

          CSRF令牌非常適合檢測(cè)釣魚網(wǎng)站,因?yàn)閺脑O(shè)計(jì)上看,它們是獨(dú)一無二的。

          5. 內(nèi)容安全策略隨機(jī)數(shù)

          內(nèi)容安全策略(CSP)是一種較新的安全手段,可幫助防御跨網(wǎng)站腳本(XSS)攻擊。它允許開發(fā)人員指定策略,比如只允許特定域的< script >標(biāo)記,或更有趣的是,對(duì)于我們的用例,僅允許包含指定“nonce”的< script >標(biāo)記。

          要使用基于隨機(jī)數(shù)的CSP,網(wǎng)站需要包含以下政策:

          并且使用具有匹配隨機(jī)值的腳本標(biāo)簽:

          這有助于防止XSS攻擊,因?yàn)閻阂庾⑷氲腏avaScript不會(huì)具有匹配的現(xiàn)時(shí)值,因此瀏覽器將拒絕運(yùn)行它。

          就像CSRF令牌一樣,CSP隨機(jī)數(shù)也構(gòu)成了完美的網(wǎng)絡(luò)釣魚工具包檢測(cè)器:它們的設(shè)計(jì)不可篡改,因此通常會(huì)為每個(gè)請(qǐng)求隨機(jī)生成長(zhǎng)且復(fù)雜的字符串。

          6. 的資源完整性哈希

          現(xiàn)代瀏覽器中可用的另一個(gè)安全功能是子資源完整性(SRI),通過允許你指定期望內(nèi)容的哈希值,可以保護(hù)你免受惡意修改的JavaScript / CSS的侵害。當(dāng)瀏覽器加載受SRI保護(hù)的JavaScript / CSS文件時(shí),它將對(duì)內(nèi)容進(jìn)行哈希處理并將其與HTML中的預(yù)期哈希進(jìn)行比較。如果不匹配,則會(huì)引發(fā)漏洞。

          例如,以下是研究人員的博客如介紹的如何將子資源完整性用于其CSS:

          這個(gè)SRI哈希值是根據(jù)研究者網(wǎng)站上所有CSS計(jì)算得出的,結(jié)果,盡管研究者使用的是公共博客模板,但極不可能有另一個(gè)網(wǎng)站具有相同的哈希值,他們必須使用完全相同的模板版本,并且必須包含所有相同的插件。

          對(duì)于自定義網(wǎng)站比研究者更多的公司,實(shí)際上可以確保沒有其他網(wǎng)站擁有完全相同的CSS。

          如何使用這些長(zhǎng)且復(fù)雜的字符串來防御網(wǎng)絡(luò)釣魚

          下次當(dāng)你分析網(wǎng)絡(luò)釣魚網(wǎng)站時(shí),請(qǐng)注意其中一些有用的長(zhǎng)且復(fù)雜的字符串。

          文件名中的哈??赡苁悄阌龅降淖畛R姷氖吕?,這些也是最有用的,因?yàn)槟憧梢栽趗rlscan.io上搜索文件名以查找同一工具包的其他實(shí)例。


          主站蜘蛛池模板: 人妻激情偷乱视频一区二区三区 | 日本一区二区三区精品国产 | 免费一区二区无码东京热| 国产在线一区二区综合免费视频| 一区二区三区AV高清免费波多| 色婷婷亚洲一区二区三区| 日本无卡码一区二区三区| 丝袜美腿一区二区三区| 一区二区三区日本电影| 无码人妻精品一区二区三区久久 | 无码人妻一区二区三区兔费| 四虎成人精品一区二区免费网站| 欧洲精品一区二区三区在线观看| 亚洲视频一区二区| 免费无码VA一区二区三区| 日韩a无吗一区二区三区| 国产一区在线视频| 国产精品成人国产乱一区| 亚洲av午夜福利精品一区人妖| 日本一区二区三区免费高清| www.亚洲一区| 国产人妖在线观看一区二区| 久久综合一区二区无码| 亚洲精品无码一区二区| 99精品国产一区二区三区| 3d动漫精品成人一区二区三| 99在线精品一区二区三区| 国产精品电影一区二区三区| 末成年女AV片一区二区| 色婷婷一区二区三区四区成人网| 蜜桃视频一区二区三区| 国产精品99精品一区二区三区| 无码日韩精品一区二区免费暖暖 | 国产自产在线视频一区| 国产日韩精品一区二区在线观看| 精品无码人妻一区二区三区品| 国产精品一区二区久久不卡| 精品无码成人片一区二区| 亚洲一区二区三区在线观看蜜桃| 中文无码精品一区二区三区| 日本一区二区三区免费高清在线|