<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>

          基于Twirp RPC的簡(jiǎn)易JSON Api Gateway實(shí)現(xiàn)

          共 2260字,需瀏覽 5分鐘

           ·

          2020-07-10 15:22

          Twirp 是 Twichtv 2018 年開(kāi)源的一套極簡(jiǎn) RPC 框架,當(dāng)時(shí)官方的介紹文章 Twirp: a sweet new RPC framework for Go。功能上比不上大名鼎鼎的 grpc,但是勝在小巧靈活,兼容 Go 原生的?http.Handler,可以與現(xiàn)有的任意?Router?和中間件搭配使用;同時(shí)支持 protobuf 和 json 格式傳輸,調(diào)試方便;另外我個(gè)人很喜歡它的?Error?實(shí)現(xiàn),直觀并且可擴(kuò)展性還不錯(cuò)。

          Twirp 支持 json 格式的 api 請(qǐng)求,前端可以直接接入使用;但是請(qǐng)求全部是統(tǒng)一的 POST 請(qǐng)求,url 是 /twirp/package.name/method 這種格式。就算能說(shuō)服自己公司的前端接受這種接入方式,也不太好公開(kāi)出去給第三方合作方使用。所以需要類(lèi)似 grpc gateway 的東西,能提供 restful 風(fēng)格的 api 出去。并且由于項(xiàng)目歷史原因,希望返回的數(shù)據(jù)按照如下格式返回:

          //ok{
          "data":{//twirp返回的數(shù)據(jù)沒(méi)有data這層包裝
          "foo":"bar"
          }}//error{
          "code":10002,//twirp返回的errorcode'permission_denied'這種string
          "msg":"error msg"}

          需求明確之后剩下的實(shí)現(xiàn)也就清晰了。我們需要類(lèi)似?httputil.ReverseProxy?那樣對(duì)收到的?request?按照 twirp 的要求進(jìn)行改造,然后交給實(shí)現(xiàn)好的 twirp rpc service 去處理。對(duì)于 body 的處理,我們自定義一個(gè)?http.ResponsWriter?對(duì) body 進(jìn)行調(diào)整之后再寫(xiě)入真正的 Writer。下面我將使用 go-chi/chi 作為 Router 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 twirp api gateway 的例子。這個(gè)例子的完整代碼開(kāi)源在 yiplee/twirp-gateway-example。

          /reversetwirp.go

          • 將 url path params 以及 query params 打包到 body

          • 修改 request method 為 POST

          • 修改 url path 為對(duì)應(yīng)的 /twirp/package.name/method

          • 轉(zhuǎn)發(fā)給 twirp rpc handler 處理請(qǐng)求

          使用示例見(jiàn)?/api/books

          /render/response.go?包裝 Response

          • 攔截 response status

          • 如果是成功的返回,將 body 用 data 包裝后寫(xiě)入真正的 ResponseWriter

          • 如果是失敗的返回,還原 Twirp Error 然后構(gòu)造新的?errorResponse?寫(xiě)入 ResponseWriter

          Server

          Server 實(shí)現(xiàn)了 rpc 和 rest api 的 Handler

          Route RPC

          使用 path 前綴匹配的方式將 rpc 請(qǐng)求路由到對(duì)應(yīng)的實(shí)現(xiàn)上去

          func (s Server) HandleRpc() http.Handler {
          r := chi.NewRouter()
          r.Use(resetRoutePath)

          // book service
          {
          svc := book.New(s.Books)
          r.Mount(svc.PathPrefix(), svc)
          }

          return r
          }

          Route Rest Api

          提供 restful 風(fēng)格的 api 請(qǐng)求,由 ReverseTwirp 實(shí)現(xiàn)

          func (s Server) HandleApi() http.Handler {
          r := chi.NewRouter()
          r.Use(render.WrapResponse(true))

          r.Route("/books", func(r chi.Router) {
          svc := book.New(s.Books)
          rt := reversetwirp.NewSingleTwirpServerProxy(svc)

          r.Post("/", rt.Handle("Create", nil))
          r.Get("/{id}", rt.Handle("Find", nil))
          })

          return r
          }

          啟動(dòng) Server

          r := chi.NewMux()
          r.Use(middleware.Recoverer)
          r.Use(middleware.Logger)

          books := book.New()
          svr := handler.New(books)

          r.Mount("/twirp", svr.HandleRpc())
          r.Mount("/api", svr.HandleApi())
          r.Mount("/hc", hc.Handler())

          addr := fmt.Sprintf(":%d", cfg.port)
          if err := http.ListenAndServe(addr, r); err != nil {
          log.Fatal(err)
          }

          最后,我們既提供了由?twirp code generator?生成的?rpc 客戶(hù)端代碼?可以被內(nèi)部服務(wù)直接使用,也提供了

          GET /api/books/:id

          POST /api/books

          這兩個(gè) rest api 供前端使用。

          完整代碼見(jiàn) yiplee/twirp-gateway-example。


          瀏覽 86
          點(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>
                  国产熟妇毛多 久久久久一区 | 豆花视频在线资源站 | 久久香蕉网 | 日韩无码 国产精品 | 国产加勒比在线 |