HTTP

transporter/http 中基于 gorilla/mux HTTP路由框架实现了Transporter,用以注册 http 到 kratos.Server() 中。

Server

配置

Network(network string) ServerOption

配置服务端的 network 协议,如 tcp

Address(addr string) ServerOption

配置服务端监听的地址

Timeout(timeout time.Duration) ServerOption

配置服务端的超时设置

Logger(logger log.Logger) ServerOption

配置服务端使用日志

Middleware(m ...middleware.Middleware) ServerOption

配置服务端的 kratos Service中间件

Filter(filters ...FilterFunc) ServerOption

配置服务端的 kratos 全局HTTP原生Fitler,此Filter执行顺序在Service中间件之前

RequestDecoder(dec DecodeRequestFunc) ServerOption

配置kratos服务端的 HTTP Request Decode方法,用来将Request Body解析至用户定义的pb结构体中 我们看下kratos中默认的RequestDecoder是怎么实现的:

  1. func DefaultRequestDecoder(r *http.Request, v interface{}) error {
  2. // 从Request Header的Content-Type中提取出对应的解码器
  3. codec, ok := CodecForRequest(r, "Content-Type")
  4. // 如果找不到对应的解码器此时会报错
  5. if !ok {
  6. return errors.BadRequest("CODEC", r.Header.Get("Content-Type"))
  7. }
  8. data, err := ioutil.ReadAll(r.Body)
  9. if err != nil {
  10. return errors.BadRequest("CODEC", err.Error())
  11. }
  12. if err = codec.Unmarshal(data, v); err != nil {
  13. return errors.BadRequest("CODEC", err.Error())
  14. }
  15. return nil
  16. }

那么如果我们想要扩展或者替换Content-Type对应的解析实现,就可以通过http.RequestDecoder()来替换kratos默认的RequestDecoder, 或者也可以通过在encoding中注册或覆盖一个Content-Type对应的codec来进行扩展

ResponseEncoder(en EncodeResponseFunc) ServerOption

配置kratos服务端的 HTTP Response Encode方法,用来将用户pb定义里的reply结构体序列化后写入Response Body中 我们看下kratos中默认的ResponseEncoder是怎么实现的:

  1. func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error {
  2. // 通过Request Header的Accept中提取出对应的编码器
  3. // 如果找不到则忽略报错,并使用默认json编码器
  4. codec, _ := CodecForRequest(r, "Accept")
  5. data, err := codec.Marshal(v)
  6. if err != nil {
  7. return err
  8. }
  9. // 在Response Header中写入编码器的scheme
  10. w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
  11. w.Write(data)
  12. return nil
  13. }

那么如果我们想要扩展或者替换Accept对应的序列化实现,就可以通过http.ResponseEncoder()来替换kratos默认的ResponseEncoder, 或者也可以通过在encoding中注册或覆盖一个Accept对应的codec来进行扩展

ErrorEncoder(en EncodeErrorFunc) ServerOption

配置kratos服务端的 HTTP Error Encode方法,用来将业务抛出的error序列化后写入Response Body中,并设置HTTP Status Code 我们看下kratos中默认的ErrorEncoder是怎么实现的:

  1. func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {
  2. // 拿到error并转换成kratos Error实体
  3. se := errors.FromError(err)
  4. // 通过Request Header的Accept中提取出对应的编码器
  5. codec, _ := CodecForRequest(r, "Accept")
  6. body, err := codec.Marshal(se)
  7. if err != nil {
  8. w.WriteHeader(http.StatusInternalServerError)
  9. return
  10. }
  11. w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
  12. // 设置HTTP Status Code
  13. w.WriteHeader(int(se.Code))
  14. w.Write(body)
  15. }

启动 Server

NewServer(opts ...ServerOption) *Server

传入opts配置并启动HTTP Server

  1. hs := http.NewServer()
  2. app := kratos.New(
  3. kratos.Name("kratos"),
  4. kratos.Version("v1.0.0"),
  5. kratos.Server(hs),
  6. )

HTTP server 中使用 kratos middleware

  1. hs := http.NewServer(
  2. http.Address(":8000"),
  3. http.Middleware(
  4. logging.Server(),
  5. ),
  6. )

middleware 中处理 http 请求

  1. if tr, ok := transport.FromServerContext(ctx); ok {
  2. kind = tr.Kind().String()
  3. operation = tr.Operation()
  4. // 断言成HTTP的Transport可以拿到特殊信息
  5. if ht,ok := tr.(*http.Tranport);ok{
  6. fmt.Println(ht.Request())
  7. }
  8. }

Server Router

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

创建一个新的HTTP Server Router,同时可以传递kratos的HTTP Filter拦截器 我们看下用法:

  1. r := s.Route("/v1")
  2. r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv))

func (s *Server) Handle(path string, h http.Handler)

将path添加到路由中,并使用标准的HTTP Handler来处理

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

前缀匹配的方式将prefix添加到路由中,并使用标准的HTTP Handler来处理

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

实现了标准库的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

配置客户端的请求默认超时时间,如果有链路超时优先使用链路超时时间

WithUserAgent(ua string) ClientOption

配置客户端的默认User-Agent

WithMiddleware(m ...middleware.Middleware) ClientOption

配置客户端使用的 kratos client中间件

WithEndpoint(endpoint string) ClientOption

配置客户端使用的对端连接地址,如果不使用服务发现则为ip:port,如果使用服务发现则格式为discovery://\<authority>/\<serviceName>,这里\<authority>可以默认填空

WithDiscovery(d registry.Discovery) ClientOption

配置客户端使用的服务发现

WithRequestEncoder(encoder EncodeRequestFunc) ClientOption

配置客户端的 HTTP Request Encode方法,用来将户定义的pb结构体中序列化至Request Body 我们看下默认的encoder:

  1. func DefaultRequestEncoder(ctx context.Context, contentType string, in interface{}) ([]byte, error) {
  2. // 通过外部配置的contentType获取encoder类型
  3. name := httputil.ContentSubtype(contentType)
  4. // 拿到实际的encoder
  5. body, err := encoding.GetCodec(name).Marshal(in)
  6. if err != nil {
  7. return nil, err
  8. }
  9. return body, err
  10. }

WithResponseDecoder(decoder DecodeResponseFunc) ClientOption

配置客户端的 HTTP Response Decode方法,用来将Response Body解析至用户定义的pb结构体中 我们看下kratos中默认的decoder是怎么实现的:

  1. func DefaultResponseDecoder(ctx context.Context, res *http.Response, v interface{}) error {
  2. defer res.Body.Close()
  3. data, err := ioutil.ReadAll(res.Body)
  4. if err != nil {
  5. return err
  6. }
  7. // 这里根据Response Header中的Content-Type拿到对应的decoder
  8. // 然后进行Unmarshal
  9. return CodecForResponse(res).Unmarshal(data, v)
  10. }

WithErrorDecoder(errorDecoder DecodeErrorFunc) ClientOption

配置客户端的Error解析方法 我们看下kratos中默认的error decoder是怎么实现的:

  1. func DefaultErrorDecoder(ctx context.Context, res *http.Response) error {
  2. // HTTP Status Code 为最高优先级
  3. if res.StatusCode >= 200 && res.StatusCode <= 299 {
  4. return nil
  5. }
  6. defer res.Body.Close()
  7. data, err := ioutil.ReadAll(res.Body)
  8. if err == nil {
  9. e := new(errors.Error)
  10. // 这里根据Response Header中的Content-Type拿到对应的response decoder
  11. // 然后解析出error主体内容
  12. if err = CodecForResponse(res).Unmarshal(data, e); err == nil {
  13. // HTTP Status Code 为最高优先级
  14. e.Code = int32(res.StatusCode)
  15. return e
  16. }
  17. }
  18. // 如果没有返回合法的Response Body则直接以HTTP Status Code为准
  19. return errors.Errorf(res.StatusCode, errors.UnknownReason, err.Error())
  20. }

WithBalancer(b balancer.Balancer) ClientOption

配置客户端的负载均衡策略

WithBlock() ClientOption

配置客户端的Dial策略为阻塞(直到服务发现发现节点才返回),默认为异步非阻塞

Client使用方式

创建客户端连接

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

使用中间件

  1. conn, err := http.NewClient(
  2. context.Background(),
  3. http.WithEndpoint("127.0.0.1:9000"),
  4. http.WithMiddleware(
  5. recovery.Recovery(),
  6. ),
  7. )

使用服务发现

  1. conn, err := http.NewClient(
  2. context.Background(),
  3. http.WithEndpoint("discovery:///helloworld"),
  4. http.WithDiscovery(r),
  5. )