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

TLSConfig(c *tls.Config) ServerOption

为 kratos 服务端添加 tls 配置用于加密 http 通信 我们看下 kratos 中是如何配置的:

// TLSConfig with TLS config.
func TLSConfig(c *tls.Config) ServerOption {
return func(o *Server) {
o.tlsConf = c
}
}

StrictSlash(strictSlash bool) ServerOption

为 kratos 服务端添加 StrictSlash 配置,用于重定向路由 我们看下 kratos 中是如何配置的

// StrictSlash is with mux's StrictSlash
// If true, when the path pattern is "/path/", accessing "/path" will
// redirect to the former and vice versa.
func StrictSlash(strictSlash bool) ServerOption {
return func(o *Server) {
o.strictSlash = strictSlash
}
}

Listener(lis net.Listener) ServerOption

为 kratos 服务端添加 Listener 接口用于面向流协议的传输 我们看下 kratos 中是如何配置的

// Listener with server lis
func Listener(lis net.Listener) ServerOption {
return func(s *Server) {
s.lis = lis
}
}

启动 Server

NewServer(opts ...ServerOption) *Server

传入opts配置并启动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 请求

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

Server Router

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

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

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策略为阻塞(直到服务发现发现节点才返回),默认为异步非阻塞

WithTLSConfig(c *tls.Config) ClientOption

配置客户端的tls

// WithTLSConfig with tls config.
func WithTLSConfig(c *tls.Config) ClientOption {
return func(o *clientOptions) {
o.tlsConf = c
}
}

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