亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

淺談go-restful框架的使用和實現

2020-04-01 18:57:57
字體:
來源:轉載
供稿:網友

REST(Representational State Transfer,表現層狀態轉化)是近幾年使用較廣泛的分布式結點間同步通信的實現方式。REST原則描述網絡中client-server的一種交互形式,即用URL定位資源,用HTTP方法描述操作的交互形式。如果CS之間交互的網絡接口滿足REST風格,則稱為RESTful API。以下是 理解RESTful架構 總結的REST原則:

  1. 網絡上的資源通過URI統一標示。
  2. 客戶端和服務器之間傳遞,這種資源的某種表現層。表現層可以是json,文本,二進制或者圖片等。
  3. 客戶端通過HTTP的四個動詞,對服務端資源進行操作,實現表現層狀態轉化。

為什么要設計RESTful的API,個人理解原因在于:用HTTP的操作統一數據操作接口,限制URL為資源,即每次請求對應某種資源的某種操作,這種 無狀態的設計可以實現client-server的解耦分離,保證系統兩端都有橫向擴展能力。

go-restful

go-restful is a package for building REST-style Web Services using Google Go。go-restful定義了Container WebService和Route三個重要數據結構。

  1. Route 表示一條路由,包含 URL/HTTP method/輸入輸出類型/回調處理函數RouteFunction
  2. WebService 表示一個服務,由多個Route組成,他們共享同一個Root Path
  3. Container 表示一個服務器,由多個WebService和一個 http.ServerMux 組成,使用RouteSelector進行分發

最簡單的使用實例,向WebService注冊路由,將WebService添加到Container中,由Container負責分發。

func main() {  ws := new(restful.WebService)  ws.Path("/users")  ws.Route(ws.GET("/").To(u.findAllUsers).    Doc("get all users").    Metadata(restfulspec.KeyOpenAPITags, tags).    Writes([]User{}).    Returns(200, "OK", []User{})) container := restful.NewContainer().Add(ws) http.ListenAndServe(":8080", container)}

container

container是根據標準庫http的路由器ServeMux寫的,并且它通過ServeMux的路由表實現了Handler接口,可參考以前的這篇 HTTP協議與Go的實現 。

type Container struct {  webServicesLock    sync.RWMutex  webServices      []*WebService  ServeMux        *http.ServeMux  isRegisteredOnRoot   bool  containerFilters    []FilterFunction  doNotRecover      bool // default is true  recoverHandleFunc   RecoverHandleFunction  serviceErrorHandleFunc ServiceErrorHandleFunction  router         RouteSelector // default is a CurlyRouter  contentEncodingEnabled bool     // default is false}
func (c *Container)ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) {  c.ServeMux.ServeHTTP(httpwriter, httpRequest)}

往Container內添加WebService,內部維護的webServices不能有重復的RootPath,

func (c *Container)Add(service *WebService)*Container {  c.webServicesLock.Lock()  defer c.webServicesLock.Unlock()  if !c.isRegisteredOnRoot {    c.isRegisteredOnRoot = c.addHandler(service, c.ServeMux)  }  c.webServices = append(c.webServices, service)  return c}

添加到container并注冊到mux的是dispatch這個函數,它負責根據不同WebService的rootPath進行分發。

func (c *Container)addHandler(service *WebService, serveMux *http.ServeMux)bool {  pattern := fixedPrefixPath(service.RootPath())  serveMux.HandleFunc(pattern, c.dispatch)}

webservice

每組webservice表示一個共享rootPath的服務,其中rootPath通過 ws.Path() 設置。

type WebService struct {  rootPath    string  pathExpr    *pathExpression   routes     []Route  produces    []string  consumes    []string  pathParameters []*Parameter  filters    []FilterFunction  documentation string  apiVersion   string  typeNameHandleFunc TypeNameHandleFunction  dynamicRoutes bool  routesLock sync.RWMutex}

通過Route注冊的路由最終構成Route結構體,添加到WebService的routes中。

func (w *WebService)Route(builder *RouteBuilder)*WebService {  w.routesLock.Lock()  defer w.routesLock.Unlock()  builder.copyDefaults(w.produces, w.consumes)  w.routes = append(w.routes, builder.Build())  return w}

route

通過RouteBuilder構造Route信息,Path結合了rootPath和subPath。Function是路由Handler,即處理函數,它通過 ws.Get(subPath).To(function) 的方式加入。Filters實現了個類似gRPC攔截器的東西,也類似go-chassis的chain。

type Route struct {  Method  string  Produces []string  Consumes []string  Path   string // webservice root path + described path  Function RouteFunction  Filters []FilterFunction  If    []RouteSelectionConditionFunction  // cached values for dispatching  relativePath string  pathParts  []string  pathExpr   *pathExpression  // documentation  Doc           string  Notes          string  Operation        string  ParameterDocs      []*Parameter  ResponseErrors     map[int]ResponseError  ReadSample, WriteSample interface{}   Metadata map[string]interface{}  Deprecated bool}

dispatch

server側的主要功能就是路由選擇和分發。http包實現了一個 ServeMux ,go-restful在這個基礎上封裝了多個服務,如何在從container開始將路由分發給webservice,再由webservice分發給具體處理函數。這些都在 dispatch 中實現。

  1. SelectRoute根據Req在注冊的WebService中選擇匹配的WebService和匹配的Route。其中路由選擇器默認是 CurlyRouter 。
  2. 解析pathParams,將wrap的請求和相應交給路由的處理函數處理。如果有filters定義,則鏈式處理。
func (c *Container)dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {  func() {    c.webServicesLock.RLock()    defer c.webServicesLock.RUnlock()    webService, route, err = c.router.SelectRoute(      c.webServices,      httpRequest)  }()  pathProcessor, routerProcessesPath := c.router.(PathProcessor)  pathParams := pathProcessor.ExtractParameters(route, webService, httpRequest.URL.Path)  wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer,  httpRequest, pathParams)  if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 {    chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) {      // handle request by route after passing all filters      route.Function(wrappedRequest, wrappedResponse)    }}    chain.ProcessFilter(wrappedRequest, wrappedResponse)  } else {    route.Function(wrappedRequest, wrappedResponse)  }}

go-chassis

go-chassis實現的rest-server是在go-restful上的一層封裝。Register時只要將注冊的schema解析成routes,并注冊到webService中,Start啟動server時 container.Add(r.ws) ,同時將container作為handler交給 http.Server , 最后開始ListenAndServe即可。

type restfulServer struct {  microServiceName string  container    *restful.Container  ws        *restful.WebService  opts       server.Options  mux       sync.RWMutex  exit       chan chan error  server      *http.Server}

根據Method不同,向WebService注冊不同方法的handle,從schema讀取的routes信息包含Method,Func以及PathPattern。

func (r *restfulServer)Register(schemainterface{}, options ...server.RegisterOption)(string, error) {  schemaType := reflect.TypeOf(schema)  schemaValue := reflect.ValueOf(schema)  var schemaName string  tokens := strings.Split(schemaType.String(), ".")  if len(tokens) >= 1 {    schemaName = tokens[len(tokens)-1]  }    routes, err := GetRoutes(schema)  for _, route := range routes {    lager.Logger.Infof("Add route path: [%s] Method: [%s] Func: [%s]. ",      route.Path, route.Method, route.ResourceFuncName)    method, exist := schemaType.MethodByName(route.ResourceFuncName)    ...    handle := func(req *restful.Request, rep *restful.Response) {      c, err := handler.GetChain(common.Provider, r.opts.ChainName)      inv := invocation.Invocation{        MicroServiceName:  config.SelfServiceName,        SourceMicroService: req.HeaderParameter(common.HeaderSourceName),        Args:        req,        Protocol:      common.ProtocolRest,        SchemaID:      schemaName,        OperationID:    method.Name,      }      bs := NewBaseServer(context.TODO())      bs.req = req      bs.resp = rep      c.Next(&inv, func(ir *invocation.InvocationResponse)error {        if ir.Err != nil {          return ir.Err        }        method.Func.Call([]reflect.Value{schemaValue, reflect.ValueOf(bs)})        if bs.resp.StatusCode() >= http.StatusBadRequest {          return ...        }        return nil      })    }     switch route.Method {    case http.MethodGet:      r.ws.Route(r.ws.GET(route.Path).To(handle).       Doc(route.ResourceFuncName).       Operation(route.ResourceFuncName))    ...    }  }  return reflect.TypeOf(schema).String(), nil}

實在是比較簡單,就不寫了。今天好困。

遺留問題

  1. reflect在路由注冊中的使用,反射與性能
  2. route select時涉及到模糊匹配 如何保證處理速度
  3. pathParams的解析

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久国产精品久久国产精品| 在线免费观看羞羞视频一区二区| 伊人亚洲福利一区二区三区| 国产精品久久久久久久久久东京| 欧美午夜精品久久久久久人妖| 97视频在线观看亚洲| 亚洲黄色免费三级| 亚洲全黄一级网站| 一本久久综合亚洲鲁鲁| 奇米一区二区三区四区久久| 亚洲精品999| 国产精品久久久久久久美男| 国产精品99蜜臀久久不卡二区| 欧美激情a在线| 中文字幕亚洲一区在线观看| 欧美激情第三页| 日韩中文字幕视频在线| 日韩av三级在线观看| 菠萝蜜影院一区二区免费| 97色在线视频观看| 亚洲有声小说3d| 欧美性理论片在线观看片免费| 粗暴蹂躏中文一区二区三区| 91久久精品视频| 久久久之久亚州精品露出| 日韩中文字幕在线视频| 2021久久精品国产99国产精品| 91综合免费在线| 另类美女黄大片| 中文国产亚洲喷潮| 国产婷婷色综合av蜜臀av| 国内外成人免费激情在线视频| 少妇激情综合网| 国产精品国产三级国产专播精品人| 欧美中在线观看| 日韩欧美成人区| 国产福利精品av综合导导航| 91成人在线观看国产| 欧美成人午夜影院| 在线观看91久久久久久| 欧美日韩在线视频首页| 欧美黄色性视频| 国产69久久精品成人看| 成人动漫网站在线观看| 久久久久久欧美| 国产精品久久久久久久久男| 欧美成人手机在线| 黄色一区二区三区| 国产成人精品一区二区| 97在线免费观看视频| 欧美国产日韩一区| 亚洲丝袜av一区| 欧美日韩电影在线观看| 国产91ⅴ在线精品免费观看| 欧美国产在线视频| 91精品久久久久久久久久| 久久精品成人欧美大片古装| 亚洲国产精品视频在线观看| 国产精品日韩欧美综合| 亚洲综合日韩中文字幕v在线| 国产精品黄页免费高清在线观看| 午夜精品www| 国产精品视频xxx| 国产精品亚洲一区二区三区| 最新日韩中文字幕| 深夜福利国产精品| 亚洲精品乱码久久久久久按摩观| 一本色道久久88亚洲综合88| 琪琪第一精品导航| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产精品成熟老女人| 亲爱的老师9免费观看全集电视剧| 精品中文字幕乱| 日韩在线观看视频免费| 日韩国产精品亚洲а∨天堂免| 国产丝袜视频一区| 国产精品福利久久久| 日韩精品电影网| 国产精品日韩电影| 国产成人综合精品| 国产精品国产福利国产秒拍| 国产91精品在线播放| 国产精品国语对白| 亚洲美女中文字幕| 6080yy精品一区二区三区| 日韩高清电影免费观看完整版| 欧美成人精品一区二区| 国产精品久久久久久久av大片| 日韩一区二区三区国产| 色视频www在线播放国产成人| 久久亚洲欧美日韩精品专区| 欧美人与性动交a欧美精品| 日韩中文字幕在线看| 国产精品男女猛烈高潮激情| 国产中文字幕91| 国产精品久久久久久久久久久久久久| 久久av红桃一区二区小说| 国产精品视频内| 97在线视频观看| 福利视频第一区| 日韩av在线一区| 亚洲国产精彩中文乱码av在线播放| 国产va免费精品高清在线观看| 久久久精品美女| 国产精品视频xxxx| 日韩精品视频在线观看网址| 国产成人精品av| 国产精品成熟老女人| 日本精品一区二区三区在线| 国产欧美日韩精品丝袜高跟鞋| 91欧美激情另类亚洲| 亚洲日本中文字幕免费在线不卡| 国产免费一区视频观看免费| 日韩精品免费在线观看| 91精品国产成人| 日韩国产中文字幕| 91久久精品国产91久久| 国产在线拍揄自揄视频不卡99| 亚洲国产精品推荐| 久久精品成人一区二区三区| 最新国产成人av网站网址麻豆| 久久久精品久久久久| 国产男女猛烈无遮挡91| 成人精品视频久久久久| 大量国产精品视频| 国产亚洲精品美女| 久久成人av网站| 欧美日韩激情美女| 欧美日韩中文字幕综合视频| 国产精品福利在线| 深夜福利91大全| 欧美大胆在线视频| 久久韩国免费视频| 国产精品成熟老女人| 国产精品国产三级国产aⅴ浪潮| www.久久草.com| 亚洲国内精品在线| 日韩精品在线观看视频| 国产美女久久久| 欧美激情一二三| 国产精品一区二区久久| 国产精品高潮呻吟视频| 久久亚洲一区二区三区四区五区高| 国产一区二区久久精品| 爽爽爽爽爽爽爽成人免费观看| 91精品美女在线| 国产深夜精品福利| 国模私拍一区二区三区| 国精产品一区一区三区有限在线| 欧美一区在线直播| 亚洲国产精品99| 欧美美最猛性xxxxxx| 亚洲人成在线免费观看| 91精品国产91久久| 久久99精品久久久久久琪琪| 国产日韩中文字幕在线| 欧美丝袜一区二区| 日韩欧亚中文在线| 精品香蕉一区二区三区| 国产精品成人v| 亚洲国产小视频在线观看| 国产精品91久久久| 色综合久久88色综合天天看泰| 欧美人与性动交a欧美精品|