Kratos HTTP

2022-04-25 10:19 更新

HTTP

transporter/http 中基于 gorilla/mux HTTP路由框架實(shí)現(xiàn)了?Transporter?,用以注冊(cè) http 到 ?kratos.Server()? 中。

Server

配置

  • ?Network(network string) ServerOption ?

配置服務(wù)端的 network 協(xié)議,如 tcp

  • ?Address(addr string) ServerOption ?

配置服務(wù)端監(jiān)聽的地址

  • ?Timeout(timeout time.Duration) ServerOption ?

配置服務(wù)端的超時(shí)設(shè)置

  • ?Logger(logger log.Logger) ServerOption ?

配置服務(wù)端使用日志

  • ?Middleware(m ...middleware.Middleware) ServerOption ?

配置服務(wù)端的 kratos Service中間件

  • ?Filter(filters ...FilterFunc) ServerOption ?

配置服務(wù)端的 kratos 全局HTTP原生Fitler,此Filter執(zhí)行順序在Service中間件之前

  • ?RequestDecoder(dec DecodeRequestFunc) ServerOption ?

配置kratos服務(wù)端的 HTTP Request Decode方法,用來將Request Body解析至用戶定義的pb結(jié)構(gòu)體中 我們看下kratos中默認(rèn)的RequestDecoder是怎么實(shí)現(xiàn)的:

func DefaultRequestDecoder(r *http.Request, v interface{}) error {
  // 從Request Header的Content-Type中提取出對(duì)應(yīng)的解碼器
  codec, ok := CodecForRequest(r, "Content-Type")
  // 如果找不到對(duì)應(yīng)的解碼器此時(shí)會(huì)報(bào)錯(cuò)
    if !ok {
        return errors.BadRequest("CODEC", r.Header.Get("Content-Type"))
    }
    data, err := ioutil.ReadAll(r.Body)
    if err != nil {
        return errors.BadRequest("CODEC", err.Error())
    }
    if err = codec.Unmarshal(data, v); err != nil {
        return errors.BadRequest("CODEC", err.Error())
    }
    return nil
}

那么如果我們想要擴(kuò)展或者替換Content-Type對(duì)應(yīng)的解析實(shí)現(xiàn),就可以通過http.RequestDecoder()來替換kratos默認(rèn)的RequestDecoder, 或者也可以通過在encoding中注冊(cè)或覆蓋一個(gè)Content-Type對(duì)應(yīng)的codec來進(jìn)行擴(kuò)展

  • ?ResponseEncoder(en EncodeResponseFunc) ServerOption ?

配置kratos服務(wù)端的 HTTP Response Encode方法,用來將用戶pb定義里的reply結(jié)構(gòu)體序列化后寫入Response Body中 我們看下kratos中默認(rèn)的ResponseEncoder是怎么實(shí)現(xiàn)的:

func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error {
  // 通過Request Header的Accept中提取出對(duì)應(yīng)的編碼器
  // 如果找不到則忽略報(bào)錯(cuò),并使用默認(rèn)json編碼器
    codec, _ := CodecForRequest(r, "Accept")
    data, err := codec.Marshal(v)
    if err != nil {
        return err
  }
  // 在Response Header中寫入編碼器的scheme
    w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
    w.Write(data)
    return nil
}

那么如果我們想要擴(kuò)展或者替換Accept對(duì)應(yīng)的序列化實(shí)現(xiàn),就可以通過http.ResponseEncoder()來替換kratos默認(rèn)的ResponseEncoder, 或者也可以通過在encoding中注冊(cè)或覆蓋一個(gè)Accept對(duì)應(yīng)的codec來進(jìn)行擴(kuò)展

  • ?ErrorEncoder(en EncodeErrorFunc) ServerOption ?

配置kratos服務(wù)端的 HTTP Error Encode方法,用來將業(yè)務(wù)拋出的error序列化后寫入Response Body中,并設(shè)置HTTP Status Code 我們看下kratos中默認(rèn)的ErrorEncoder是怎么實(shí)現(xiàn)的:

func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {
  // 拿到error并轉(zhuǎn)換成kratos Error實(shí)體
  se := errors.FromError(err)
  // 通過Request Header的Accept中提取出對(duì)應(yīng)的編碼器
    codec, _ := CodecForRequest(r, "Accept")
    body, err := codec.Marshal(se)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
  w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
  // 設(shè)置HTTP Status Code
    w.WriteHeader(int(se.Code))
    w.Write(body)
}

啟動(dòng) Server

??NewServer(opts ...ServerOption) *Server  ??

  • 傳入opts配置并啟動(dòng)HTTP Server
hs := http.NewServer()
app := kratos.New(
    kratos.Name("kratos"),
    kratos.Version("v1.0.0"),
    kratos.Server(hs),
)
  • HTTP server 中使用 kratos middleware
hs := http.NewServer(
    http.Address(":8000"),
    http.Middleware(
        logging.Server(),
    ),
)
  • middleware 中處理 http 請(qǐng)求
if tr, ok := transport.FromServerContext(ctx); ok {
    kind = tr.Kind().String()
    operation = tr.Operation()
    // 斷言成HTTP的Transport可以拿到特殊信息
    if ht,ok := tr.(*http.Tranport);ok{
        fmt.Println(ht.Request())
    } 
}

Server Router

  • ?func (s *Server) Route(prefix string, filters ...FilterFunc) *Router ?

創(chuàng)建一個(gè)新的HTTP Server Router,同時(shí)可以傳遞kratos的HTTP Filter攔截器 我們看下用法:

    r := s.Route("/v1")
    r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv))
  • ?func (s *Server) Handle(path string, h http.Handler) ?

將path添加到路由中,并使用標(biāo)準(zhǔn)的HTTP Handler來處理

  • ?func (s *Server) HandlePrefix(prefix string, h http.Handler) ?

前綴匹配的方式將prefix添加到路由中,并使用標(biāo)準(zhǔn)的HTTP Handler來處理

  • ?func (s *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) ?

實(shí)現(xiàn)了標(biāo)準(zhǔn)庫的HTTP Handler接口

其他路由使用方法參考: https://github.com/go-kratos/examples/tree/main/http/middlewares

在Kratos HTTP中使用gin框架: https://github.com/go-kratos/kratos/blob/main/examples/http/gin/main.go

Client

配置

  • ?WithTransport(trans http.RoundTripper) ClientOption ?

配置客戶端的HTTP RoundTripper

  • ?WithTimeout(d time.Duration) ClientOption ?

配置客戶端的請(qǐng)求默認(rèn)超時(shí)時(shí)間,如果有鏈路超時(shí)優(yōu)先使用鏈路超時(shí)時(shí)間

  • ?WithUserAgent(ua string) ClientOption ?

配置客戶端的默認(rèn)User-Agent

  • ?WithMiddleware(m ...middleware.Middleware) ClientOption ?

配置客戶端使用的 kratos client中間件

  • ?WithEndpoint(endpoint string) ClientOption ?

配置客戶端使用的對(duì)端連接地址,如果不使用服務(wù)發(fā)現(xiàn)則為ip:port,如果使用服務(wù)發(fā)現(xiàn)則格式為discovery://\<authority>/\<serviceName>,這里\<authority>可以默認(rèn)填空

  • ?WithDiscovery(d registry.Discovery) ClientOption ?

配置客戶端使用的服務(wù)發(fā)現(xiàn)

  • ?WithRequestEncoder(encoder EncodeRequestFunc) ClientOption ?

配置客戶端的 HTTP Request Encode方法,用來將戶定義的pb結(jié)構(gòu)體中序列化至Request Body 我們看下默認(rèn)的encoder:

func DefaultRequestEncoder(ctx context.Context, contentType string, in interface{}) ([]byte, error) {
    // 通過外部配置的contentType獲取encoder類型
    name := httputil.ContentSubtype(contentType)
    // 拿到實(shí)際的encoder
    body, err := encoding.GetCodec(name).Marshal(in)
    if err != nil {
        return nil, err
    }
    return body, err
}
  • ?WithResponseDecoder(decoder DecodeResponseFunc) ClientOption  ?

配置客戶端的 HTTP Response Decode方法,用來將Response Body解析至用戶定義的pb結(jié)構(gòu)體中 我們看下kratos中默認(rèn)的decoder是怎么實(shí)現(xiàn)的:

func DefaultResponseDecoder(ctx context.Context, res *http.Response, v interface{}) error {
    defer res.Body.Close()
    data, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return err
    }
    // 這里根據(jù)Response Header中的Content-Type拿到對(duì)應(yīng)的decoder
    // 然后進(jìn)行Unmarshal
    return CodecForResponse(res).Unmarshal(data, v)
}
  • ?WithErrorDecoder(errorDecoder DecodeErrorFunc) ClientOption ?

配置客戶端的Error解析方法 我們看下kratos中默認(rèn)的error decoder是怎么實(shí)現(xiàn)的:

func DefaultErrorDecoder(ctx context.Context, res *http.Response) error {
    // HTTP Status Code 為最高優(yōu)先級(jí)
    if res.StatusCode >= 200 && res.StatusCode <= 299 {
        return nil
    }
    defer res.Body.Close()
    data, err := ioutil.ReadAll(res.Body)
    if err == nil {
        e := new(errors.Error)
        // 這里根據(jù)Response Header中的Content-Type拿到對(duì)應(yīng)的response decoder
        // 然后解析出error主體內(nèi)容
        if err = CodecForResponse(res).Unmarshal(data, e); err == nil {
            // HTTP Status Code 為最高優(yōu)先級(jí)
            e.Code = int32(res.StatusCode)
            return e
        }
    }
    // 如果沒有返回合法的Response Body則直接以HTTP Status Code為準(zhǔn)
    return errors.Errorf(res.StatusCode, errors.UnknownReason, err.Error())
}
  • ?WithBalancer(b balancer.Balancer) ClientOption ?

配置客戶端的負(fù)載均衡策略

  • ?WithBlock() ClientOption ?

配置客戶端的Dial策略為阻塞(直到服務(wù)發(fā)現(xiàn)發(fā)現(xiàn)節(jié)點(diǎn)才返回),默認(rèn)為異步非阻塞

Client使用方式

  • 創(chuàng)建客戶端連接

conn, err := http.NewClient(
    context.Background(),
    http.WithEndpoint("127.0.0.1:8000"),
)

  • 使用中間件

conn, err := http.NewClient(
    context.Background(),
    http.WithEndpoint("127.0.0.1:9000"),
    http.WithMiddleware(
          recovery.Recovery(),
    ),
)

  • 使用服務(wù)發(fā)現(xiàn)

conn, err := http.NewClient(
    context.Background(),
    http.WithEndpoint("discovery:///helloworld"),
    http.WithDiscovery(r),
)


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)