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

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

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

          HTML編碼規(guī)范

          版規(guī)則

          縮進(jìn)

          使用2個(gè)空格縮進(jìn)

          <ul>
            <li>Fantastic</li>
            <li>Great</li>
          </ul>
          .example {
            color: blue;
          }

          大小寫

          只允許使用小寫。

          所有的代碼都用小寫字母:適用于元素名,屬性,屬性值(除了文本和CDATA), 選擇器,特性,特性值(除了字符串)。

          <!-- 不推薦 -->
          <A HREF="/">Home</A>
          <!-- 推薦 -->
          <img src="google.png"
          alt="Google">

          行為空格

          建議刪除行尾白空格。

          <!-- 不推薦 -->
          <p>What?  </p>
          <!-- 推薦 -->
          <p>Yes please.</p>

          常規(guī)Meta規(guī)則

          編碼

          如果沒(méi)有特殊需求,一般采用utf-8編碼。如果是cms站點(diǎn),則遵守該站點(diǎn)的編碼規(guī)則。

          <!-- 網(wǎng)頁(yè)編碼 -->
          <meta charset="utf-8">

          注釋

          盡可能的去解釋你寫的代碼。說(shuō)明該代碼包括什么、目的是什么、能做什么、為什么使用它等。

          注釋是否需要詳盡,取決于項(xiàng)目的復(fù)雜程度。

          一般單行注釋:

          <!-- col -->

          模塊間注釋:

          <!-- news -->
          <div class="news">
            <h2>News</h2>
            <p>...</p>
          </div>
          <!--/ news -->

          循環(huán)注釋:

          <ul>
            <!-- loop: new list -->
            <li>new's title 1</li>
            <li>new's title 2</li>
            <li>new's title 3</li>
            <li>new's title 4</li>
            <li>new's title 5</li>
            <!-- /loop: new list -->
          </ul>

          cms輸出注釋:

          <!-- cms: news list -->
          <ul>
            <li>new's title 1</li>
            <li>new's title 2</li>
            <li>new's title 3</li>
            <li>new's title 4</li>
            <li>new's title 5</li>
          </ul>
          <!-- /cms: news list -->

          Tab選項(xiàng)卡內(nèi)容注釋:

          <!-- tab: news list -->
          <div class="tab"></div>
          <!-- /tab: news list -->

          常規(guī)HTML設(shè)計(jì)規(guī)則

          文檔類型

          使用html5文檔聲明,不再使用XHTML(application/xhtml+xml)。

          HTML5是目前所有HTML文檔類型中的首選:

          <!DOCTYPE html>

          HTML 的正確性

          編寫有效、正確的HTML代碼,否則很難達(dá)到性能上的提升。

          可以使用一些工具驗(yàn)證你的代碼,如 W3C HTML validator

          HTML 的語(yǔ)義性

          根據(jù)HTML各個(gè)元素的用途而去使用它們。

          <!-- 不推薦 -->
          <div class="col">
            <div class="title">
          news</div>
            <p>list1</p>
            <p>list2</p>
            <p>list3</p>
          </div>
          <!-- 推薦 -->
          <div class="col">
            <h2 class="title">
          news</h2>
            <p>list1</p>
            <p>list2</p>
            <p>list3</p>
          </div>

          部分標(biāo)簽說(shuō)明:

          • div 主要用于布局,分割頁(yè)面的結(jié)構(gòu);
          • ul/ol 主要用于無(wú)序/有序列表;
          • dl/dt/dd 當(dāng)頁(yè)面中出現(xiàn)第一行為類似標(biāo)題/簡(jiǎn)述,然后下面為詳細(xì)描述的內(nèi)容時(shí)應(yīng)該使用該標(biāo)簽;
          • span 沒(méi)有特殊的意義,可以用作排版的輔助,然后在css中定義span;
          • h1-h6 標(biāo)題, 根據(jù)重要性依次遞減;
          • h1 最重要的標(biāo)題;
          • label 使表單更有親和力而且能輔助表單排版;

          不推薦使用的標(biāo)簽:

          • font 文字的外觀,大小和顏色;
          • u 文本下劃線;
          • center 居中對(duì)齊;
          • s 刪除線;
          • strike 刪除線;
          • noframes 無(wú)視框時(shí)的內(nèi)容;
          • iframe 定義嵌入視圖;
          • isindex 不建議使用(可搜尋,使用input代替);
          • dir 目錄式列舉;
          • menu 菜單列表;
          • basefont 定義基本字體;
          • applet 定義java程序;
          • frame 定義個(gè)別視框;
          • frameset 視框格式總定義;

          多媒體元素降級(jí)處理

          給多媒體元素,比如canvas、videos、 images增加alt屬性,提高可用性(特別是常用的img標(biāo)簽,盡可量得加上alt屬性,提供圖片的描述信息)。

          <!-- 不推薦 -->
          <img src="world.jpg">
          <!-- 推薦 -->
          <img src="world.jpg"
          alt="our world images">

          type屬性

          在樣式表和腳本的標(biāo)簽中忽略type屬性。

          HTML5默認(rèn)type為text/css和text/javascript類型,所以沒(méi)必要指定。即便是老瀏覽器也是支持的。

          <!-- 不推薦 -->
          <link rel="stylesheet"
           href="//www.google.com/css/maia.css"
           type="text/css">
          <script src="
           //www.google.com/
           js/gweb/analytics/autotrack.js"
           type="text/javascript">
           </script>
          <!-- 推薦 -->
          <link rel="stylesheet"
           href="//www.google.com/css/maia.css">
          <script src="
           //www.google.com/
           js/gweb/analytics/autotrack.js">
           </script>

          HTML代碼格式規(guī)則

          每個(gè)塊元素、列表元素或表格元素都獨(dú)占一行,每個(gè)子元素都相對(duì)于父元素進(jìn)行縮進(jìn)。按設(shè)計(jì)稿劃分模塊,盡量使頁(yè)面模塊化,模塊與模塊之前要有清晰的注釋。

          如上面頁(yè)面框架,推薦寫法:

          <!-- hader -->
          <div class="header">header</div>
          <!-- /hader -->
          <!-- nav -->
          <div class="nav">nav</div>
          <!-- /nav -->
          <!-- main -->
          <div class="main">
            <!-- container -->
            <div class="container">
              <!--news-->
              <div class="news">
                <h2>news<h2>
                <p>...</p>
              </div>
              <!--news-->
            </div>
            <!--/container-->
            <!--sidebar-->
            <div class="sidebar">
          sidebar</div>
            <!--sidebar-->
          </div>
          <!--/main-->
          <!--footer-->
          <div class="footer">
          footer</div>
          <!--/footer-->

          HTML與SEO

          頁(yè)面良好層次

          保證整個(gè)頁(yè)面在未加載樣式表時(shí)仍有較好的層次清晰的頁(yè)面結(jié)構(gòu)。

          <!-- 不推薦 -->
          <div class="logo">My Site</div>
          <div class="nav">
            <a href="#">Home</a>
            <a href="#">News</a>
            <a href="#">Mobile</a>
          </div>
          <div class="news">
            <div>News</div>
            <a href="#">
          news list 1</a>
            <a href="#">
          news list 2</a>
            <a href="#">
          news list 3</a>
          </div>
          <!-- 推薦 -->
          <h1 class="logo">My Site</h1>
          <ul class="nav">
            <li><a href="#">
          Home</a></li>
            <li><a href="#">
          News</a></li>
            <li><a href="#">
          Mobile</a></li>
          </ul>
          <div class="news">
            <h2>News</h2>
            <ul>
              <li><a href="#">
          news list 1</a>
          </li>
              <li><a href="#">
          news list 2</a>
          </li>
              <li><a href="#">
          news list 3</a>
          </li>
            </ul>
          </div>

          權(quán)重標(biāo)簽使用

          H標(biāo)簽使用

          • h1 權(quán)重高,體現(xiàn)當(dāng)前網(wǎng)頁(yè)中相對(duì)比較重要的信息,但不宜過(guò)多,建議一個(gè)頁(yè)面只放一個(gè);
          • h2 可以做副標(biāo)題;
          • h3 可以做新聞列表;
          • h4-h6 可做相關(guān)新聞的列表標(biāo)簽屬性完整;

          strong、b使用

          將需要加粗的文字使用b標(biāo)簽來(lái)顯示。

          將需要強(qiáng)調(diào)的文字(主要指包含關(guān)鍵詞的信息)使用strong標(biāo)簽來(lái)強(qiáng)調(diào)主要內(nèi)容。

          注:b是粗體標(biāo)簽,屬于實(shí)體標(biāo)簽,它所包圍的字符將被設(shè)為bold(粗體);strong 是加重語(yǔ)氣標(biāo)簽,屬于邏輯標(biāo)簽,它的作用是加強(qiáng)字符語(yǔ)氣。

          標(biāo)簽屬性使用

          在很多情況下,a都要使用title來(lái)說(shuō)明該鏈接的相關(guān)說(shuō)明或目的意義。

          例如:當(dāng)使用overflow隱藏掉a中的溢出文字時(shí),該a中的title是必不可少的,它可以告訴用戶被隱藏掉的文字內(nèi)容是什么;又或者當(dāng)一個(gè)圖片型鏈接出現(xiàn)時(shí),該a中的title同樣是必不可少的,它可以告訴用戶這個(gè)圖片鏈接是做什么用的。

          注:僅在img里添加alt標(biāo)簽在火狐提示文字是出不來(lái)的,alt是圖片加載失敗或未加載完全時(shí)顯示出來(lái)的提示文字,要想鼠標(biāo)移上去顯示提示信息應(yīng)該用title,嚴(yán)謹(jǐn)?shù)膶懛ㄊ莍mg里加入alt和title這兩個(gè)標(biāo)簽。

          精簡(jiǎn)代碼

          代碼保持精簡(jiǎn),最優(yōu)化,這樣搜索引擎才更喜歡。

          算機(jī)網(wǎng)絡(luò)中的OSI七層模型

          計(jì)算機(jī)網(wǎng)絡(luò)中的OSI(Open Systems Interconnection)七層模型是一種理論框架,用于描述計(jì)算機(jī)網(wǎng)絡(luò)中數(shù)據(jù)通信的過(guò)程。OSI模型將計(jì)算機(jī)網(wǎng)絡(luò)通信過(guò)程劃分為七個(gè)層次,每個(gè)層次都有其特定的功能和協(xié)議。這種分層結(jié)構(gòu)有助于研究和理解計(jì)算機(jī)網(wǎng)絡(luò)中的通信原理。以下是OSI七層模型的各個(gè)層次及其主要功能:

          應(yīng)用層是OSI模型的第七層,也是網(wǎng)絡(luò)應(yīng)用程序和網(wǎng)絡(luò)協(xié)議之間的接口。應(yīng)用層主要負(fù)責(zé)為用戶提供各類應(yīng)用服務(wù),如文件傳輸、電子郵件、Web瀏覽等。

          表示層是OSI模型的第六層,主要負(fù)責(zé)處理在網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)的表示方式,如數(shù)據(jù)加密、解密、壓縮、解壓縮等。表示層確保了不同系統(tǒng)之間的數(shù)據(jù)兼容性。

          會(huì)話層是OSI模型的第五層,主要負(fù)責(zé)建立、維護(hù)和終止應(yīng)用程序之間的通信會(huì)話。會(huì)話層提供了數(shù)據(jù)交換的同步和確認(rèn)機(jī)制。

          傳輸層是OSI模型的第四層,主要負(fù)責(zé)在源主機(jī)和目標(biāo)主機(jī)之間提供可靠的、端到端的數(shù)據(jù)傳輸服務(wù)。傳輸層通過(guò)分段、封裝和重組數(shù)據(jù)來(lái)實(shí)現(xiàn)可靠的數(shù)據(jù)傳輸。常見(jiàn)的傳輸層協(xié)議包括TCP(傳輸控制協(xié)議)和UDP(用戶數(shù)據(jù)報(bào)協(xié)議)。

          網(wǎng)絡(luò)層是OSI模型的第三層,主要負(fù)責(zé)將數(shù)據(jù)包從源主機(jī)路由到目標(biāo)主機(jī)。網(wǎng)絡(luò)層主要負(fù)責(zé)邏輯尋址、路由選擇和分組轉(zhuǎn)發(fā)。常見(jiàn)的網(wǎng)絡(luò)層協(xié)議包括IP(互聯(lián)網(wǎng)協(xié)議)和ICMP(互聯(lián)網(wǎng)控制報(bào)文協(xié)議)。

          數(shù)據(jù)鏈路層是OSI模型的第二層,主要負(fù)責(zé)將網(wǎng)絡(luò)層傳來(lái)的數(shù)據(jù)包封裝成幀(Frame),并在同一局域網(wǎng)內(nèi)進(jìn)行傳輸。數(shù)據(jù)鏈路層主要負(fù)責(zé)物理尋址、數(shù)據(jù)成幀、錯(cuò)誤檢測(cè)和流量控制。常見(jiàn)的數(shù)據(jù)鏈路層協(xié)議包括以太網(wǎng)(Ethernet)、令牌環(huán)(Token Ring)和無(wú)線局域網(wǎng)(Wi-Fi)等。

          物理層是OSI模型的第一層,主要負(fù)責(zé)在物理介質(zhì)上實(shí)現(xiàn)比特流的透明傳輸。物理層主要關(guān)注硬件接口、電氣特性、光纖、無(wú)線傳輸?shù)确矫娴膯?wèn)題。

          OSI七層模型提供了一個(gè)通用的框架,幫助研究和理解計(jì)算機(jī)網(wǎng)絡(luò)中的通信原理。實(shí)際應(yīng)用中,我們通常使用TCP/IP四層模型,它包括了應(yīng)用層、傳輸層、網(wǎng)絡(luò)層和鏈路層,與OSI模型有一定的對(duì)應(yīng)關(guān)系。

          HTML框架的必要性

          HTML框架進(jìn)行分層設(shè)計(jì)的主要原因是為了提高代碼的可讀性、可維護(hù)性和可重用性。將HTML框架分層可以提高整體項(xiàng)目的結(jié)構(gòu)和邏輯,便于開(kāi)發(fā)者更好地理解和修改代碼。分層設(shè)計(jì)具有以下優(yōu)點(diǎn):

          1. 提高可讀性:通過(guò)將HTML框架劃分為不同的層次,可以使代碼結(jié)構(gòu)更清晰,有助于開(kāi)發(fā)者快速理解代碼的功能。
          2. 便于維護(hù):分層設(shè)計(jì)有助于將功能模塊化,這樣可以方便地修改或替換某個(gè)模塊,而不會(huì)影響其他部分的代碼。這有助于提高項(xiàng)目的可維護(hù)性。
          3. 可重用性:將HTML框架分層可以將公共部分提取為可重用的組件,這樣可以在不同項(xiàng)目中重復(fù)使用這些組件,提高開(kāi)發(fā)效率。
          4. 適應(yīng)性:分層設(shè)計(jì)可以讓HTML框架更容易適應(yīng)不同的設(shè)備和屏幕尺寸,提高項(xiàng)目的兼容性。
          5. 便于協(xié)作:在大型項(xiàng)目中,通常會(huì)有多個(gè)開(kāi)發(fā)者參與。通過(guò)分層設(shè)計(jì),開(kāi)發(fā)者可以專注于自己的模塊,減少代碼沖突和溝通成本。

          HTML框架的組成

          HTML框架包括Application層``middleware層``route層``codec層``transport層 Application層 應(yīng)用層通常包括與業(yè)務(wù)邏輯相關(guān)的代碼,如Web應(yīng)用程序的控制器(Controller)、視圖(View)和模型(Model)。應(yīng)用層的主要作用是處理用戶請(qǐng)求并返回相應(yīng)的響應(yīng)。

          Middleware層 中間件層是介于應(yīng)用層和底層框架之間的一層,負(fù)責(zé)處理一些通用的功能,如身份驗(yàn)證、授權(quán)、緩存、日志記錄等。中間件層有助于將業(yè)務(wù)邏輯與通用功能分離,使得應(yīng)用層更加簡(jiǎn)潔和易于維護(hù)。

          Route層 路由層負(fù)責(zé)處理HTTP請(qǐng)求的URL和HTTP方法(如GET、POST等),將請(qǐng)求分發(fā)到相應(yīng)的控制器和方法。路由層的主要作用是根據(jù)URL映射來(lái)定位具體的功能代碼。

          Codec層 編解碼層負(fù)責(zé)處理數(shù)據(jù)的編碼和解碼。在Web開(kāi)發(fā)中,編碼和解碼通常涉及到HTML、CSS、JavaScript等前端技術(shù)的處理,以及JSON、XML等數(shù)據(jù)交換格式的處理。編解碼層的主要作用是將數(shù)據(jù)轉(zhuǎn)換為特定的格式,以便在不同層之間進(jìn)行傳輸和處理。

          Transport層 傳輸層負(fù)責(zé)處理底層的網(wǎng)絡(luò)通信,如TCP、UDP等協(xié)議的使用。在Web開(kāi)發(fā)中,傳輸層通常涉及到HTTP協(xié)議的處理,包括請(qǐng)求和響應(yīng)的創(chuàng)建、發(fā)送和接收。傳輸層的主要作用是確保數(shù)據(jù)的可靠傳輸和在網(wǎng)絡(luò)中的正確路由。

          這些層次在實(shí)際應(yīng)用中可能因框架和場(chǎng)景的不同而有所差異。但是,從您提供的描述來(lái)看,它們分別負(fù)責(zé)處理Web應(yīng)用程序中的不同功能,共同構(gòu)成了一個(gè)完整的Web開(kāi)發(fā)框架。

          HTML框架和服務(wù)端客戶端之間的通信對(duì)比

          Application層應(yīng)用層設(shè)計(jì)

          應(yīng)用層設(shè)計(jì)主要是設(shè)置各種接口,用于路由使用。

          例如在字節(jié)后端進(jìn)階版中的大項(xiàng)目中的注冊(cè)接口。

          /douyin/user/register/ - 用戶注冊(cè)接口

          新用戶注冊(cè)時(shí)提供用戶名,密碼,昵稱即可,用戶名需要保證唯一。創(chuàng)建成功后返回用戶 id 和權(quán)限token.

          接口類型

          POST

          接口定義

          go復(fù)制代碼syntax = "proto2";
          package douyin.core;
          
          message douyin_user_register_request {
            required string username = 1; // 注冊(cè)用戶名,最長(zhǎng)32個(gè)字符
            required string password = 2; // 密碼,最長(zhǎng)32個(gè)字符
          }
          
          message douyin_user_register_response {
            required int32 status_code = 1; // 狀態(tài)碼,0-成功,其他值-失敗
            optional string status_msg = 2; // 返回狀態(tài)描述
            required int64 user_id = 3; // 用戶id
            required string token = 4; // 用戶鑒權(quán)token
          }
          
          go復(fù)制代碼func Register(username, password string) (id int64, token int64, err error) {
             if len(username) > 32 {
                return 0, 0, errors.New("用戶名過(guò)長(zhǎng),不可超過(guò)32位")
             }
             if len(password) > 32 {
                return 0, 0, errors.New("密碼過(guò)長(zhǎng),不可超過(guò)32位")
             }
             // 先查布隆過(guò)濾器,不存在直接返回錯(cuò)誤,降低數(shù)據(jù)庫(kù)的壓力
             if userNameFilter.TestString(username) {
                return 0, 0, errors.New("用戶名已經(jīng)存在!")
             }
             //雪花算法生成token
             node, err := snowflake.NewNode(1) //這里的userIdInt64就是 User.Id(主鍵)
             if err != nil {
                log.Println("雪花算法生成id錯(cuò)誤!")
                log.Println(err)
             }
             token1 := node.Generate().Int64()
             tokenStr := strconv.FormatInt(token1, 10)
             user := domain.User{}
             // 再查緩存
             data, err := dao.RedisClient.Get(context.Background(), tokenStr).Result()
             if err == redis.Nil {
                fmt.Println("token does not exist")
             } else if err != nil {
                fmt.Println("Error:", err)
             } else {
                num, err := strconv.ParseInt(data, 10, 64)
                if err != nil {
                   fmt.Println("Error:", err)
                   return num, 0, err
                }
          
                return num, token1, nil
             }
             //在查數(shù)據(jù)庫(kù)
             user = domain.User{}
             dao.DB.Model(&domain.User{}).Where("name = ?", username).Find(&user)
             if user.Id != 0 {
                return 0, 0, errors.New("用戶已存在")
             }
             user.Name = username
             // 加密存儲(chǔ)用戶密碼
             user.Salt = randSalt()
             buf := bytes.Buffer{}
             buf.WriteString(username)
             buf.WriteString(password)
             buf.WriteString(user.Salt)
             pwd, err1 := bcrypt.GenerateFromPassword(buf.Bytes(), bcrypt.MinCost)
             if err1 != nil {
                return 0, 0, err
             }
             user.Pwd = string(pwd)
          
             //存在mysql里邊
             dao.DB.Model(&domain.User{}).Create(&user)
             //再把用戶id作為鍵 用戶的所有信息作為值存在其中
             //用戶信息的緩存是 保存在redis中 一個(gè)以id為鍵 user json為值
             jsonuser, err1 := MarshalUser(user)
             if err1 != nil {
                fmt.Println("err1", err1)
                return 0, 0, err1
             }
             err = dao.RedisClient.Set(context.Background(), strconv.FormatInt(user.Id, 10), jsonuser, 0).Err()
             if err != nil {
                fmt.Println("err", err)
                return 0, 0, err
             }
             // 布隆過(guò)濾器中加入新用戶
             userIdFilter.AddString(strconv.FormatInt(user.Id, 10))
             userNameFilter.AddString(username)
             return user.Id, token1, nil
          }
          

          本接口注冊(cè)功能實(shí)現(xiàn):把所有信息存在mysql里邊當(dāng)然redis里邊也存在這些信息,當(dāng)然username也存在了布容過(guò)濾器中去,當(dāng)接收到用戶的username的時(shí)候我們現(xiàn)在布容過(guò)濾器中先查詢是否存在如果存在則直接返回err,不存在然后再在redis里邊查詢,因?yàn)閞edis相比于mysql是更為輕量級(jí)的所以我們要先在redis里邊進(jìn)行查,如果查不到再進(jìn)mysql里邊查去,查不到說(shuō)明沒(méi)有注冊(cè)過(guò),可以注冊(cè)。

          命名規(guī)范

          遵循命名規(guī)范原則。

          Middleware層中間件

          gin框架里的中間件分為全局中間件,局部中間件。那么什么是中間件?中間件是為應(yīng)用提供通用服務(wù)和功能的軟件。數(shù)據(jù)管理、應(yīng)用服務(wù)、消息傳遞、身份驗(yàn)證和 API 管理通常都要通過(guò)中間件。在gin框架里,就是我們的所有API接口都要經(jīng)過(guò)我們的中間件,我們可以在中間件做一些攔截處理。

          中間件常用模型

          全局中間件

          這個(gè)是在服務(wù)啟動(dòng)就開(kāi)始注冊(cè),全局意味著所有API接口都會(huì)經(jīng)過(guò)這里。Gin的中間件是通過(guò)Use方法設(shè)置的,它接收一個(gè)可變參數(shù),所以我們同時(shí)可以設(shè)置多個(gè)中間件。

          首先定義如下

          go復(fù)制代碼// 1.創(chuàng)建路由
          r := gin.Default()  //默認(rèn)帶Logger(), Recovery()這兩個(gè)內(nèi)置中間件
          r:= gin.New()      //不帶任何中間件
          // 注冊(cè)中間件  
          r.Use(MiddleWare())
          r.Use(MiddleWare2())
          

          注意的是

          gin.Default()默認(rèn)使用了Logger和Recovery中間件,其中:Logger中間件將日志寫入gin.DefaultWriter,即使配置了GIN_MODE=release。Recovery中間件會(huì)recover任何panic。如果有panic的話,會(huì)寫入500響應(yīng)碼。如果不想使用上面兩個(gè)默認(rèn)的中間件,可以使用gin.New()新建一個(gè)沒(méi)有任何默認(rèn)中間件的路由。

          go復(fù)制代碼// 定義中間
          func MiddleWare() gin.HandlerFunc {
              return func(c *gin.Context) {
                  t := time.Now()
                  fmt.Println("中間件開(kāi)始執(zhí)行了")
                  // 設(shè)置變量到Context的key中,可以通過(guò)Get()取
                  c.Set("request", "這是中間件設(shè)置的值")
                  status := c.Writer.Status()
                  fmt.Println("中間件執(zhí)行完畢", status)        
                  t2 := time.Since(t)
                  fmt.Println("time:", t2)
              }
          }
          

          然后啟動(dòng)我們的服務(wù),訪問(wèn)任意一個(gè)接口可以看到輸出如下

          這是請(qǐng)求先到了中間件,然后在到我們的API接口。在中間件里可以設(shè)置變量到Context的key中,然后在我們的API接口取值。

          go復(fù)制代碼        r.GET("/", func(c *gin.Context) {
                      // 取值
                      req, _ := c.Get("request")
                      fmt.Println("request:", req)
                      // 頁(yè)面接收
                      c.JSON(200, gin.H{"request": req})
                  })
          

          這時(shí)候在訪問(wèn)就可以看到中間件設(shè)置的值是

          next方法是在中間件里面使用,這個(gè)是執(zhí)行后續(xù)中間件請(qǐng)求處理的意思(含沒(méi)有執(zhí)行的中間件和我們定義的GET方法處理,如果連續(xù)注冊(cè)幾個(gè)中間件則會(huì)是按照順序先進(jìn)后出的執(zhí)行,遇到next就去執(zhí)行下一個(gè)中間件里的next前面方法。

          go復(fù)制代碼        // 執(zhí)行函數(shù)
                  c.Next()
                  // 中間件執(zhí)行完后續(xù)的一些事情
          

          局部中間件

          局部中間件意味著部分接口才會(huì)生效,只在局部使用,這時(shí)候訪問(wèn)http:127.0.0.1:8000/ 才會(huì)看到中間件的日志打印,其他API接口則不會(huì)出現(xiàn)。

          go復(fù)制代碼   //局部中間件使用
              r.GET("/", MiddleWare(), func(c *gin.Context) {
                  // 取值
                  req, _ := c.Get("request")
                  fmt.Println("request:", req)
                  // 頁(yè)面接收
                  c.JSON(200, gin.H{"request": req})
              })
          

          gin內(nèi)置中間件

          go復(fù)制代碼
          func BasicAuth(accounts Accounts) HandlerFunc
          
          func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc
          
          func Bind(val interface{}) HandlerFunc
          
          func ErrorLogger() HandlerFunc
          
          func ErrorLoggerT(typ ErrorType) HandlerFunc
          
          func Logger() HandlerFunc
          
          func LoggerWithConfig(conf LoggerConfig) HandlerFunc
          
          func LoggerWithFormatter(f LogFormatter) HandlerFunc
          
          func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc
          
          func Recovery() HandlerFunc
          
          func RecoveryWithWriter(out io.Writer) HandlerFunc
          
          func WrapF(f http.HandlerFunc) HandlerFunc
          
          func WrapH(h http.Handler) HandlerFunc
          

          總結(jié)

          通過(guò)自定義中間件,我們可以很方便的攔截請(qǐng)求,來(lái)做一些我們需要做的事情,比如日志記錄、授權(quán)校驗(yàn)、各種過(guò)濾等等。

          route層路由層

          Gin 是一個(gè)標(biāo)準(zhǔn)的 Web 服務(wù)框架,遵循 Restful API 接口規(guī)范,其路由庫(kù)是基于 httproute 實(shí)現(xiàn)的。

          本節(jié)將從 Gin 路由開(kāi)始,詳細(xì)講述各種路由場(chǎng)景下,如何通過(guò) Gin 來(lái)實(shí)現(xiàn)。

          基本路由

          1. GET:用于處理從客戶端發(fā)起的HTTP GET請(qǐng)求。GET請(qǐng)求用于從服務(wù)器獲取數(shù)據(jù),不應(yīng)對(duì)服務(wù)器上的數(shù)據(jù)進(jìn)行更改。例如,獲取用戶信息、獲取文章列表等。
          2. POST:用于處理從客戶端發(fā)起的HTTP POST請(qǐng)求。POST請(qǐng)求通常用于向服務(wù)器發(fā)送數(shù)據(jù),用于創(chuàng)建新的資源或更新已有的資源。例如,用戶注冊(cè)、發(fā)布文章、更新用戶信息等。
          3. PUT:用于處理從客戶端發(fā)起的HTTP PUT請(qǐng)求。PUT請(qǐng)求通常用于更新服務(wù)器上的資源。例如,更新用戶信息、更新文章內(nèi)容等。
          4. DELETE:用于處理從客戶端發(fā)起的HTTP DELETE請(qǐng)求。DELETE請(qǐng)求通常用于從服務(wù)器刪除資源。例如,刪除用戶賬戶、刪除文章等。
          5. PATCH:用于處理從客戶端發(fā)起的HTTP PATCH請(qǐng)求。PATCH請(qǐng)求通常用于對(duì)服務(wù)器上的資源進(jìn)行部分更新。例如,更新用戶的部分信息、更新文章標(biāo)題等。
          6. OPTIONS:用于處理從客戶端發(fā)起的HTTP OPTIONS請(qǐng)求。OPTIONS請(qǐng)求用于獲取服務(wù)器支持的HTTP方法。例如,跨域資源共享(CORS)場(chǎng)景。
          7. HEAD:用于處理從客戶端發(fā)起的HTTP HEAD請(qǐng)求。HEAD請(qǐng)求類似于GET請(qǐng)求,但不返回響應(yīng)體。主要用于獲取響應(yīng)頭信息。例如,檢查資源是否存在,但不需要獲取資源內(nèi)容。
          8. ANY:用于處理任何HTTP方法(GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)的請(qǐng)求。適用于處理多種HTTP方法的情況。
          9. CONNECT:用于處理從客戶端發(fā)起的HTTP CONNECT請(qǐng)求。CONNECT請(qǐng)求通常用于建立客戶端與服務(wù)器之間的隧道,用于代理或其他場(chǎng)景。
          10. TRACE:用于處理從客戶端發(fā)起的HTTP TRACE請(qǐng)求。TRACE請(qǐng)求用于測(cè)試或診斷網(wǎng)絡(luò)連接。服務(wù)器應(yīng)當(dāng)返回原始的請(qǐng)求信息,以便客戶端可以檢查中間代理或防火墻是否進(jìn)行了修改。

          示例

          字節(jié)大項(xiàng)目注冊(cè)接口

          go復(fù)制代碼syntax = "proto2";
          package douyin.core;
          
          message douyin_user_register_request {
            required string username = 1; // 注冊(cè)用戶名,最長(zhǎng)32個(gè)字符
            required string password = 2; // 密碼,最長(zhǎng)32個(gè)字符
          }
          
          message douyin_user_register_response {
            required int32 status_code = 1; // 狀態(tài)碼,0-成功,其他值-失敗
            optional string status_msg = 2; // 返回狀態(tài)描述
            required int64 user_id = 3; // 用戶id
            required string token = 4; // 用戶鑒權(quán)token
          }
          
          go復(fù)制代碼func Register(c *gin.Context) {
          
             username := c.Query("username")
             password := c.Query("password")
             id, token, err := service.Register(username, password)
             if err != nil {
                c.JSON(http.StatusOK, domain.Response{StatusCode: 1, StatusMsg: err.Error()})
             } else {
          
                c.JSON(http.StatusOK, domain.UserLoginResponse{
                   //可以直接去掉
                   Response: domain.Response{StatusCode: 0},
                   Id:       id,
                   Token:    token,
                })
             }
          }
          

          go復(fù)制代碼package main
          
          import (
             "github.com/gin-gonic/gin"
             "github.com/goTouch/TicTok_SimpleVersion/controller"
          )
          
          func initRouter(r *gin.Engine) {
             // public directory is used to serve static resources
             r.Static("/static", "./public")
          
             apiRouter := r.Group("/douyin")
          
             // basic apis
             //controller.VerifyToken,
             apiRouter.POST("/user/", controller.UserInfo)
             apiRouter.POST("/user/register/", controller.LoginLimit, controller.Register)
             apiRouter.POST("/user/login/", controller.LoginLimit, controller.Login)
             }
          

          codec層

          在Web開(kāi)發(fā)中,編碼和解碼通常涉及到HTML、CSS、JavaScript等前端技術(shù)的處理,以及JSON、XML等數(shù)據(jù)交換格式的處理。編解碼層的主要作用是將數(shù)據(jù)轉(zhuǎn)換為特定的格式,以便在不同層之間進(jìn)行傳輸和處理。

          示例

          在postman中的示例 json

          xml

          html復(fù)制代碼{"status_code":1,"status_msg":"redis: nil"}
          {"status_code":2,"status_msg":"no multipart boundary param in Content-Type"}
          
          Text復(fù)制代碼{"status_code":1,"status_msg":"redis: nil"}
          {"status_code":2,"status_msg":"no multipart boundary param in Content-Type"}
          
          Auto復(fù)制代碼{
              "status_code": 1,
              "status_msg": "redis: nil"
          }{
              "status_code": 2,
              "status_msg": "no multipart boundary param in Content-Type"
          }
          
          

          transport層傳輸層

          傳輸層負(fù)責(zé)處理底層的網(wǎng)絡(luò)通信,如TCP、UDP等協(xié)議的使用。在Web開(kāi)發(fā)中,傳輸層通常涉及到HTTP協(xié)議的處理,包括請(qǐng)求和響應(yīng)的創(chuàng)建、發(fā)送和接收。傳輸層的主要作用是確保數(shù)據(jù)的可靠傳輸和在網(wǎng)絡(luò)中的正確路由。

          golang語(yǔ)言中net/http這個(gè)庫(kù)中的conn 他是BIO自帶阻塞

          1. BIO (Blocking I/O)

          同步阻塞I/O模式,數(shù)據(jù)的讀取寫入必須阻塞在一個(gè)線程內(nèi)等待其完成。

          1.1 傳統(tǒng) BIO

          BIO通信(一請(qǐng)求一應(yīng)答)模型圖如下(圖源網(wǎng)絡(luò),原出處不明):

          采用 BIO 通信模型 的服務(wù)端,通常由一個(gè)獨(dú)立的 Acceptor 線程負(fù)責(zé)監(jiān)聽(tīng)客戶端的連接。我們一般通過(guò)在 while(true) 循環(huán)中服務(wù)端會(huì)調(diào)用 accept() 方法等待接收客戶端的連接的方式監(jiān)聽(tīng)請(qǐng)求,請(qǐng)求一旦接收到一個(gè)連接請(qǐng)求,就可以建立通信套接字在這個(gè)通信套接字上進(jìn)行讀寫操作,此時(shí)不能再接收其他客戶端連接請(qǐng)求,只能等待同當(dāng)前連接的客戶端的操作執(zhí)行完成, 不過(guò)可以通過(guò)多線程來(lái)支持多個(gè)客戶端的連接,如上圖所示。

          如果要讓 BIO 通信模型 能夠同時(shí)處理多個(gè)客戶端請(qǐng)求,就必須使用多線程(主要原因是 socket.accept()、 socket.read()、 socket.write() 涉及的三個(gè)主要函數(shù)都是同步阻塞的),也就是說(shuō)它在接收到客戶端連接請(qǐng)求之后為每個(gè)客戶端創(chuàng)建一個(gè)新的線程進(jìn)行鏈路處理,處理完成之后,通過(guò)輸出流返回應(yīng)答給客戶端,線程銷毀。這就是典型的 一請(qǐng)求一應(yīng)答通信模型 。我們可以設(shè)想一下如果這個(gè)連接不做任何事情的話就會(huì)造成不必要的線程開(kāi)銷,不過(guò)可以通過(guò) 線程池機(jī)制 改善,線程池還可以讓線程的創(chuàng)建和回收成本相對(duì)較低。使用FixedThreadPool 可以有效的控制了線程的最大數(shù)量,保證了系統(tǒng)有限的資源的控制,實(shí)現(xiàn)了N(客戶端請(qǐng)求數(shù)量):M(處理客戶端請(qǐng)求的線程數(shù)量)的偽異步I/O模型(N 可以遠(yuǎn)遠(yuǎn)大于 M),下面一節(jié)"偽異步 BIO"中會(huì)詳細(xì)介紹到。

          我們?cè)僭O(shè)想一下當(dāng)客戶端并發(fā)訪問(wèn)量增加后這種模型會(huì)出現(xiàn)什么問(wèn)題?

          程是寶貴的資源,線程的創(chuàng)建和銷毀成本很高,除此之外,線程的切換成本也是很高的。尤其在 Linux 這樣的操作系統(tǒng)中,線程本質(zhì)上就是一個(gè)進(jìn)程,創(chuàng)建和銷毀線程都是重量級(jí)的系統(tǒng)函數(shù)。如果并發(fā)訪問(wèn)量增加會(huì)導(dǎo)致線程數(shù)急劇膨脹可能會(huì)導(dǎo)致線程堆棧溢出、創(chuàng)建新線程失敗等問(wèn)題,最終導(dǎo)致進(jìn)程宕機(jī)或者僵死,不能對(duì)外提供服務(wù)。 golang實(shí)現(xiàn)BIO

          NIO

          NIO: NIO是一種同步非阻塞IO, 基于Reactor模型來(lái)實(shí)現(xiàn)的。其實(shí)相當(dāng)于就是一個(gè)線程處理大量的客戶端的請(qǐng)求,通過(guò)一個(gè)線程輪詢大量的channel,每次就獲取一批有事件的channel,然后對(duì)每個(gè)請(qǐng)求啟動(dòng)一個(gè)線程處理即可。這里的核心就是非阻塞,就那個(gè)selector一個(gè)線程就可以不停輪詢channel,所有客戶端請(qǐng)求都不會(huì)阻塞,直接就會(huì)進(jìn)來(lái),大不了就是等待一下排著隊(duì)而已。這里面優(yōu)化BIO的核心就是,一個(gè)客戶端并不是時(shí)時(shí)刻刻都有數(shù)據(jù)進(jìn)行交互,沒(méi)有必要死耗著一個(gè)線程不放,所以客戶端選擇了讓線程歇一歇,只有客戶端有相應(yīng)的操作的時(shí)候才發(fā)起通知,創(chuàng)建一個(gè)線程來(lái)處理請(qǐng)求。
          ————————————————
          NIO:模型圖

          Reactor模型:

          NIO核心組件詳細(xì)講解

          學(xué)習(xí)NIO先來(lái)搞清楚一些相關(guān)的概念,NIO通訊有哪些相關(guān)組件,對(duì)應(yīng)的作用都是什么,之間有哪些聯(lián)系?

          多路復(fù)用機(jī)制實(shí)現(xiàn)Selector

          首先我們來(lái)了解下傳統(tǒng)的Socket網(wǎng)絡(luò)通訊模型。

          傳統(tǒng)Socket通訊原理圖

          為什么傳統(tǒng)的socket不支持海量連接

          每次一個(gè)客戶端接入,都是要在服務(wù)端創(chuàng)建一個(gè)線程來(lái)服務(wù)這個(gè)客戶端的,這會(huì)導(dǎo)致大量的客戶端的時(shí)候,服務(wù)端的線程數(shù)量可能達(dá)到幾千甚至幾萬(wàn),幾十萬(wàn),這會(huì)導(dǎo)致服務(wù)器端程序負(fù)載過(guò)高,不堪重負(fù),最終系統(tǒng)崩潰死掉。

          • 接著來(lái)看下NIO是如何基于Selector實(shí)現(xiàn)多路復(fù)用機(jī)制支持的海量連接。

          NIO原理圖

          多路復(fù)用機(jī)制是如何支持海量連接

          NIO的線程模型 對(duì)Socket發(fā)起的連接不需要每個(gè)都創(chuàng)建一個(gè)線程,完全可以使用一個(gè)Selector來(lái)多路復(fù)用監(jiān)聽(tīng)N多個(gè)Channel是否有請(qǐng)求,該請(qǐng)求是對(duì)應(yīng)的連接請(qǐng)求,還是發(fā)送數(shù)據(jù)的請(qǐng)求,這里面是基于操作系統(tǒng)底層的Select通知機(jī)制的,一個(gè)Selector不斷的輪詢多個(gè)Channel,這樣避免了創(chuàng)建多個(gè)線程,只有當(dāng)莫個(gè)Channel有對(duì)應(yīng)的請(qǐng)求的時(shí)候才會(huì)創(chuàng)建線程,可能說(shuō)1000個(gè)請(qǐng)求, 只有100個(gè)請(qǐng)求是有數(shù)據(jù)交互的, 這個(gè)時(shí)候可能server端就提供10個(gè)線程就能夠處理這些請(qǐng)求。這樣的話就可以避免了創(chuàng)建大量的線程。

          NIO如何通過(guò)Buffer來(lái)緩沖數(shù)據(jù)的

          NIO中的Buffer是個(gè)什么東西 ?

          學(xué)習(xí)NIO,首當(dāng)其沖就是要了解所謂的Buffer緩沖區(qū),這個(gè)東西是NIO里比較核心的一個(gè)部分,一般來(lái)說(shuō),如果你要通過(guò)NIO寫數(shù)據(jù)到文件或者網(wǎng)絡(luò),或者是從文件和網(wǎng)絡(luò)讀取數(shù)據(jù)出來(lái)此時(shí)就需要通過(guò)Buffer緩沖區(qū)來(lái)進(jìn)行。Buffer的使用一般有如下幾個(gè)步驟:

          寫入數(shù)據(jù)到Buffer,調(diào)用flip()方法,從Buffer中讀取數(shù)據(jù),調(diào)用clear()方法或者compact()方法。

          Buffer中對(duì)應(yīng)的Position, Mark, Capacity,Limit都啥?

          capacity: 緩沖區(qū)容量的大小,就是里面包含的數(shù)據(jù)大小。
          limit: 對(duì)buffer緩沖區(qū)使用的一個(gè)限制,從這個(gè)index開(kāi)始就不能讀取數(shù)據(jù)了。
          position: 代表著數(shù)組中可以開(kāi)始讀寫的index, 不能大于limit。
          mark: 是類似路標(biāo)的東西,在某個(gè)position的時(shí)候,設(shè)置一下mark,此時(shí)就可以設(shè)置一個(gè)標(biāo)記,后續(xù)調(diào)用reset()方法可以把position復(fù)位到當(dāng)時(shí)設(shè)置的那個(gè)mark上去,把position或limit調(diào)整為小于mark的值時(shí),就丟棄這個(gè)mark。如果使用的是Direct模式創(chuàng)建的Buffer的話,就會(huì)減少中間緩沖直接使用的是DirectorBuffer來(lái)進(jìn)行數(shù)據(jù)的存儲(chǔ)。
          ————————————————

          如何通過(guò)Channel和FileChannel讀取Buffer數(shù)據(jù)寫入磁盤的

          NIO中,Channel是什么?

          Channel是NIO中的數(shù)據(jù)通道,類似流,但是又有些不同,Channel即可從中讀取數(shù)據(jù),又可以從寫數(shù)據(jù)到通道中,但是流的讀寫通常是單向的。Channel可以異步的讀寫。Channel中的數(shù)據(jù)總是要先讀到一個(gè)Buffer中,或者從緩沖區(qū)中將數(shù)據(jù)寫到通道中。

          FileChannel的作用是什么 Buffer有不同的類型,同樣Channel也有好幾個(gè)類型。 FileChannel,DatagramChannel,SocketChannel,ServerSocketChannel。這些通道涵蓋了UDP 和 TCP 網(wǎng)絡(luò)IO,以及文件IO。而FileChannel就是文件IO對(duì)應(yīng)的管道, 在讀取文件的時(shí)候會(huì)用到這個(gè)管道。 golang的NIO

          TML標(biāo)簽

          基本標(biāo)簽

          HTML頁(yè)面中內(nèi)容是由HTML標(biāo)簽組織起來(lái)的,如頁(yè)面中的文本、圖像、Flash視頻文件等都是通過(guò)HTML標(biāo)簽合理地顯示在頁(yè)面的各個(gè)位置。



          1 標(biāo)題標(biāo)簽<h1>~<h6>

          標(biāo)題標(biāo)簽表示一段文字的標(biāo)題(主題),并且支持多層次的內(nèi)容結(jié)構(gòu)。HTNL.共提供了6級(jí)標(biāo)題,分別為<h1>~<h6>,并賦予了標(biāo)題一定的外觀,所有標(biāo)題字體加粗,其中山<h1>字號(hào)最大,<h6>字號(hào)最小.


          2.圖像標(biāo)簽<img>

          在網(wǎng)頁(yè)中常用的圖像格式有4種,即JPG、GIF、BMP.PNG,其中使用比較多的是JPG、GIF和PNG,大多數(shù)瀏覽器都可以顯示這些圖像。


          顯示圖像的語(yǔ)法:

          < img src="ur1" alt="文本" width="x" height="y"/>


          在語(yǔ)法中:

          a、SrC屬性:表示顯示圖像的地址。

          b、alt屬性:指定圖像的替代文本,當(dāng)圖像無(wú)法顯示時(shí)(如圖片路徑錯(cuò)誤或網(wǎng)速太慢等)替代顯示的文本,這樣,即使圖像無(wú)法顯示,用戶還可以看到網(wǎng)頁(yè)丟失的信息,所以為頁(yè)面上的圖像都加上替換文本屬性是個(gè)好習(xí)慣,這樣有助于更好地顯示信息,并且對(duì)于那些使用純文本瀏覽器的人來(lái)說(shuō)是非常有幫助的。

          c、width屬性:表示圖像寬度.

          d、height屬性:表示圖像高度。


          3.段落標(biāo)簽<p>

          顧名思義,段落標(biāo)簽表示將一段文字組成一系列段落內(nèi)容,這樣做的目的是內(nèi)容應(yīng)用某些格式和布局,使各個(gè)段落的邏輯更清晰明了。在HTML文檔中,段落通過(guò)<p>標(biāo)簽定義。段落標(biāo)簽<p>表示段落的開(kāi)始,</p >表示段落的結(jié)束。


          4.換行標(biāo)簽<br/>

          在希望不產(chǎn)生一個(gè)新段落的情況下進(jìn)行換行,則使用<br>標(biāo)簽。<br>是一個(gè)空的HTML標(biāo)簽,由于關(guān)閉標(biāo)簽沒(méi)有任何意義,因此它沒(méi)有結(jié)束標(biāo)簽。


          注意:

          使用<b>和<br>的結(jié)果一樣,在XHTML以及未來(lái)的HTML版本中,根據(jù)W3C規(guī)范,不允許使用沒(méi)有結(jié)束標(biāo)簽的HTML元素,因此使用<br>頁(yè)面更規(guī)范,有更長(zhǎng)遠(yuǎn)的保障。


          5.水平線標(biāo)簽<hr/>

          水平線標(biāo)簽表示一條水平線,注意該標(biāo)簽與<br>標(biāo)簽一樣,沒(méi)有結(jié)束標(biāo)簽,直接使用<hr/>表示標(biāo)簽的開(kāi)始和結(jié)束。

          使用以上講解的基本標(biāo)簽,就可以進(jìn)行網(wǎng)頁(yè)內(nèi)容排版了。


          主站蜘蛛池模板: 日韩制服国产精品一区| 日韩精品电影一区亚洲| 91久久精品一区二区| 熟妇人妻一区二区三区四区| 精品无码日韩一区二区三区不卡| 在线视频精品一区| 色系一区二区三区四区五区| 一区二区不卡久久精品| 精品国产日韩亚洲一区91| 亚洲一区二区三区免费在线观看| 人妻少妇精品一区二区三区| 免费观看一区二区三区| 国产波霸爆乳一区二区| 精品无码av一区二区三区| 国产韩国精品一区二区三区久久| 韩国福利一区二区三区高清视频| 理论亚洲区美一区二区三区| 久久国产精品无码一区二区三区| 波多野结衣的AV一区二区三区| 国产一区二区在线观看麻豆| 国模一区二区三区| 中文字幕一区在线观看视频| 亚洲美女一区二区三区| 99精品国产一区二区三区不卡 | 亚洲欧洲日韩国产一区二区三区| 亚欧色一区W666天堂| 日本欧洲视频一区| 另类一区二区三区| 69福利视频一区二区| 国产香蕉一区二区在线网站| 波多野结衣一区二区| 在线|一区二区三区| 日本精品一区二区久久久| 国产成人精品一区二三区| 精品国产香蕉伊思人在线在线亚洲一区二区 | 久久精品国产亚洲一区二区三区| 亚洲色精品vr一区二区三区 | 午夜一区二区在线观看| 相泽南亚洲一区二区在线播放| 制服美女视频一区| 精品一区二区三区免费视频|