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/examples/blob/main/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),
)