<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          多圖詳解萬(wàn)星 Restful 框架原理與實(shí)現(xiàn)

          共 3483字,需瀏覽 7分鐘

           ·

          2021-10-21 10:55

          rest框架概覽

          我們先通過(guò) go-zero 自帶的命令行工具 goctl 來(lái)生成一個(gè) api service,其 main 函數(shù)如下:

          func?main()?{
          ?flag.Parse()

          ?var?c?config.Config
          ?conf.MustLoad(*configFile,?&c)

          ?ctx?:=?svc.NewServiceContext(c)
          ?server?:=?rest.MustNewServer(c.RestConf)
          ?defer?server.Stop()

          ?handler.RegisterHandlers(server,?ctx)

          ?fmt.Printf("Starting?server?at?%s:%d...\n",?c.Host,?c.Port)
          ?server.Start()
          }
          1. 解析配置文件
          2. 將配置文件傳入,初始化 serviceContext
          3. 初始化 rest server
          4. context 注入 server 中:
            1. 注冊(cè)路由
            2. context 中的啟動(dòng)的 endpoint 同時(shí)注入到 router 當(dāng)中
          5. 啟動(dòng) server

          接下來(lái)我們來(lái)一步步講解其設(shè)計(jì)原理!Let's Go!

          web框架

          從日常開發(fā)經(jīng)驗(yàn)來(lái)說(shuō),一個(gè)好的 web 框架大致需要滿足以下特性:

          1. 路由匹配/多路由支持
          2. 支持自定義中間件
          3. 框架和業(yè)務(wù)開發(fā)完全解耦,方便開發(fā)者快速開發(fā)
          4. 參數(shù)校驗(yàn)/匹配
          5. 監(jiān)控/日志/指標(biāo)等服務(wù)自查功能
          6. 服務(wù)自保護(hù)(熔斷/限流)

          go-zero rest設(shè)計(jì)

          https://github.com/zeromicro/go-zero/tree/master/rest

          概覽

          1. 借助 context (不同于 gin 的 context),將資源初始化好 → 保存在 serviveCtx 中,在 handler 中共享(至于資源池化,交給資源自己處理,serviveCtx 只是入口和共享點(diǎn))
          2. 獨(dú)立 router 聲明文件,同時(shí)加入 router group 的概念,方便開發(fā)者整理代碼結(jié)構(gòu)
          3. 內(nèi)置若干中間件:監(jiān)控/熔斷/鑒權(quán)等
          4. 利用 goctl codegen + option 設(shè)計(jì)模式,方便開發(fā)者自己控制部分中間件的接入

          上圖描述了 rest 處理請(qǐng)求的模式和大部分處理路徑。

          1. 框架內(nèi)置的中間件已經(jīng)幫開發(fā)者解決了大部分服務(wù)自處理的邏輯
          2. 同時(shí) go-zero 在 business logic 處也給予開發(fā)者開箱即用的組件(dq、fx 等)
          3. 從開發(fā)模式上幫助開發(fā)者只需要關(guān)注自己的 business logic 以及所需資源準(zhǔn)備

          下面我們來(lái)細(xì)說(shuō)一下整個(gè) rest 是如何啟動(dòng)的?

          啟動(dòng)流程

          上圖描述了整體 server 啟動(dòng)經(jīng)過(guò)的模塊和大致流程。準(zhǔn)備按照如下流程分析 rest 實(shí)現(xiàn):

          1. 基于 http.server 封裝以及改造:把 engine(web框架核心) 和 option 隔離開
          2. 多路由匹配采取 radix-tree 構(gòu)造
          3. 中間件采用洋蔥模型 → []Middleware
          4. http parse 解析以及匹配校驗(yàn) → httpx.Parse()
          5. 在請(qǐng)求過(guò)程會(huì)收集指標(biāo) (createMetrics()) 以及監(jiān)控埋點(diǎn) (prometheus)

          server engine封裝

          點(diǎn)開大圖觀看

          engine 貫穿整個(gè) server 生命周期中:

          1. router 會(huì)攜帶開發(fā)者定義的 path/handler,會(huì)在最后的 router.handle() 執(zhí)行
          2. 注冊(cè)的自定義中間件 + 框架中間件,在 router handler logic 前執(zhí)行

          在這里:go-zero 處理的粒度在 route 上,封裝和處理都在 route 一層層執(zhí)行

          路由匹配

          那么當(dāng) request 到來(lái),首先是如何到路由這一層的?

          首先在開發(fā)最原始的 http server ,都有這么一段代碼:

          type?helloHandler?struct{}

          func?(h?*helloHandler)?ServeHTTP(w?http.ResponseWriter,?r?*http.Request)?{
          ????w.Write([]byte("Hello,?world!"))
          }

          func?main()?{
          ????http.Handle("/",?&helloHandler{})
          ????http.ListenAndServe(":12345",?nil)
          }

          http.ListenAndServe() ?內(nèi)部會(huì)執(zhí)行到:server.ListenAndServe()

          我們看看在 rest 里面是怎么運(yùn)用的:

          而傳入的 handler 其實(shí)就是:router.NewRouter() 生成的 router。這個(gè) router 承載了整個(gè) server 的處理函數(shù)集合。

          同時(shí) http.Server 結(jié)構(gòu)在初始化時(shí),是把 handler 注入到里面的:

          type?Server?struct?{
          ?...
          ?Handler?Handler
          }

          func?start(...,?handler?http.Handler,?run?func(srv?*http.Server)?error)?(err?error)?{
          ?server?:=?&http.Server{
          ??Addr:????fmt.Sprintf("%s:%d",?host,?port),
          ??Handler:?handler,
          ?}
          ?...
          ?return?run(server)
          }

          在 http.Server 接收 req 后,最終執(zhí)行的也是:handler.ServeHTTP(rw, req)

          所以內(nèi)置的 router 也需要實(shí)現(xiàn) ServeHTTP 。至于 router 自己是怎么實(shí)現(xiàn) ServeHTTP :無(wú)外乎就是尋找匹配路由,然后執(zhí)行路由對(duì)應(yīng)的 handle logic。

          解析參數(shù)

          解析參數(shù)是 http 框架需要提供的基本能力。在 goctl code gen 生成的代碼中,handler 層已經(jīng)集成了 req argument parse 函數(shù):

          //?generate?by?goctl
          func?QueryAllTaskHandler(ctx?*svc.ServiceContext)?http.HandlerFunc?{
          ?return?func(w?http.ResponseWriter,?r?*http.Request)?{
          ??//?custom?request?in?.api?file
          ??var?req?types.QueryAllTaskRequest
          ??//?parse?http?request
          ??if?err?:=?httpx.Parse(r,?&req);?err?!=?nil?{
          ???httpx.Error(w,?err)
          ???return
          ??}

          ??l?:=?logic.NewEventLogic(r.Context(),?ctx)
          ??resp,?err?:=?l.QueryAllTask(req)
          ??baseresponse.FormatResponseWithRequest(resp,?err,?w,?r)
          ?}
          }

          進(jìn)入到 httpx.Parse() ,主要解析以下幾塊:

          https://github.com/zeromicro/go-zero/blob/master/rest/httpx/requests.go#L32:6

          1. 解析path
          2. 解析form表單
          3. 解析http header
          4. 解析json

          Parse() 中的 參數(shù)校驗(yàn) 的功能見:

          https://go-zero.dev/cn/api-grammar.html 中的 tag修飾符

          Tips

          學(xué)習(xí)源碼推薦 fork 出來(lái)邊看邊寫注釋和心得,可以加深理解,以后用到這塊功能的時(shí)候也可以回頭翻閱。

          項(xiàng)目地址

          https://github.com/zeromicro/go-zero

          歡迎使用 go-zerostar 支持我們!



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù)?ebook?獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬(wàn) Gopher 交流學(xué)習(xí)。

          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大尺度一区二区 | 中日韩一级片 | 影音先锋最新男人资源 | 精品人妻人伦 | 91精品内射 |