Skip to main content

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是怎么实现的:

func DefaultRequestDecoder(r *http.Request, v interface{}) error {  // 从Request Header的Content-Type中提取出对应的解码器  codec, ok := CodecForRequest(r, "Content-Type")  // 如果找不到对应的解码器此时会报错    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}

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

ResponseEncoder(en EncodeResponseFunc) ServerOption#

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

func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error {  // 通过Request Header的Accept中提取出对应的编码器  // 如果找不到则忽略报错,并使用默认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}

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

ErrorEncoder(en EncodeErrorFunc) ServerOption#

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

func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {  // 拿到error并转换成kratos Error实体  se := errors.FromError(err)  // 通过Request Header的Accept中提取出对应的编码器    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()))  // 设置HTTP Status Code    w.WriteHeader(int(se.Code))    w.Write(body)}

启动 Server#

NewServer(opts ...ServerOption) *Server #

传入opts配置并启动HTTP Server

hs := http.NewServer()app := kratos.New(    kratos.Name("kratos"),    kratos.Version("v1.0.0"),    kraotos.Server(hs),)

HTTP server 中使用 kratos middleware#

hs := http.NewServer(    http.Address(":8000"),    http.Middleware(        logging.Server(),    ),)

middleware 中处理 http 请求#

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#

创建一个新的HTTP Server Router,同时可以传递kraots的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添加到路由中,并使用标准的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/kratos/tree/main/examples/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:

func DefaultRequestEncoder(ctx context.Context, contentType string, in interface{}) ([]byte, error) {    // 通过外部配置的contentType获取encoder类型    name := httputil.ContentSubtype(contentType)    // 拿到实际的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结构体中 我们看下kratos中默认的decoder是怎么实现的:

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    }    // 这里根据Response Header中的Content-Type拿到对应的decoder    // 然后进行Unmarshal    return CodecForResponse(res).Unmarshal(data, v)}

WithErrorDecoder(errorDecoder DecodeErrorFunc) ClientOption#

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

func DefaultErrorDecoder(ctx context.Context, res *http.Response) error {    // HTTP Status Code 为最高优先级    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)        // 这里根据Response Header中的Content-Type拿到对应的response decoder        // 然后解析出error主体内容        if err = CodecForResponse(res).Unmarshal(data, e); err == nil {            // HTTP Status Code 为最高优先级            e.Code = int32(res.StatusCode)            return e        }    }    // 如果没有返回合法的Response Body则直接以HTTP Status Code为准    return errors.Errorf(res.StatusCode, errors.UnknownReason, err.Error())}

WithBalancer(b balancer.Balancer) ClientOption#

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

WithBlock() ClientOption#

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

Client使用方式#

创建客户端连接#

    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(),    ),)

使用服务发现#

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