Go|Go - Kit 笔记 - 02 - Transport-http

Transport – 传输层 位于github.com/go-kit/kit/transport/,go-kit目前支持grpc、http、httprp、nats、netrpc、thrift,传输层的作用是封装端点。使端点可以被不同的传输协议调用。
Server结构 Server结构的作用是把端点封装成http.Handlerhttp.Handler位于net/http/server.go中,实则是一个接口,定义如下:

type Handler interface { ServeHTTP(ResponseWriter, *Request) } 注:如果对```net/http```包不太了解,可以看一看《go-web编程》。

Server结构定义如下:
type ErrorEncoder func(ctx context.Context, err error, w http.ResponseWriter) type DecodeRequestFunc func(context.Context, *http.Request) (request interface{}, err error) type EncodeRequestFunc func(context.Context, *http.Request, interface{}) errortype Server struct { eendpoint.Endpoint//端点 decDecodeRequestFunc//解码函数,需要自定义 encEncodeResponseFunc//编码函数,需要自定义 before[]RequestFunc //前置函数 after[]ServerResponseFunc //后置函数 errorEncoder ErrorEncoder //错误函数 finalizer[]ServerFinalizerFunc //终结器函数 loggerlog.Logger //日志 }

NewServer开始跟代码:
type ServerOption func(*Server) func NewServer( e endpoint.Endpoint, //e,不解释 dec DecodeRequestFunc, //调用端点之前,会调用dec对数据进行解码 enc EncodeResponseFunc, //调用端点之后,会调用enc对数据进行编码 options ...ServerOption, //看函数体中的for循环。 ) *Server { s := &Server{ e:e, dec:dec, enc:enc, errorEncoder: DefaultErrorEncoder, //transport/http/server.go里面有定义,有兴趣的可以看一眼。 logger:log.NewNopLogger(),//go-kit自己的log模块,有机会看。 } for _, option := range options { //循环执行option。option是可以自定义的。 option(s) } return s }

重点来了,Server结构实现了ServerHTTP方法,所以可以当作http.Handler接口使用,然后可已调用http.HandFunc添加到http服务中。
func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context()//获取上下文if len(s.finalizer) > 0 {//如果终结器个数大于0,当函数退出后执行终结器(默认终结器个数为0的) iw := &interceptingWriter{w, http.StatusOK, 0} defer func() {//ServerHTTP退出时,会执行里面相应的函数 ctx = context.WithValue(ctx, ContextKeyResponseHeaders, iw.Header()) ctx = context.WithValue(ctx, ContextKeyResponseSize, iw.written) for _, f := range s.finalizer { f(ctx, iw.code, r) } }() w = iw }//执行befor中设置的函数 for _, f := range s.before { ctx = f(ctx, r) }//执行解码函数 request, err := s.dec(ctx, r) if err != nil {//如果出错,记录日志,执行错误处理函数 s.logger.Log("err", err) s.errorEncoder(ctx, err, w) return }//执行端点 response, err := s.e(ctx, request) if err != nil {//如果出错,记录日志,执行错误处理函数 s.logger.Log("err", err) s.errorEncoder(ctx, err, w) return }//执行after函数 for _, f := range s.after { ctx = f(ctx, w) }//执行编码函数 if err := s.enc(ctx, w, response); err != nil { s.logger.Log("err", err) s.errorEncoder(ctx, err, w) return }

Client结构 可以理解为http爬虫,能发送各种http请求。
type HTTPClient interface { Do(req *http.Request) (*http.Response, error) } type Client struct { clientHTTPClient//接口 methodstring//方法(get、post、put、delete。。。) tgt*url.URL//网址 encEncodeRequestFunc//编码函数 decDecodeResponseFunc//解码函数 before[]RequestFunc//前置函数 after[]ClientResponseFunc//后置函数 finalizer[]ClientFinalizerFunc//终结器函数 bufferedStream bool //是否开启缓冲 } func NewClient( method string,//设置方法 tgt *url.URL,//网址 enc EncodeRequestFunc,//编码函数 dec DecodeResponseFunc,//解码函数 options ...ClientOption,//选项函数 ) *Client { c := &Client{ client:http.DefaultClient,//net/http包中定义的,直接拿来用了 method:method, tgt:tgt, enc:enc, dec:dec, before:[]RequestFunc{}, after:[]ClientResponseFunc{}, bufferedStream: false, } for _, option := range options { option(c) } return c }

重点看下下面这个函数:
func (c Client) Endpoint() endpoint.Endpoint {//此函数返回一个端点。 return func(ctx context.Context, request interface{}) (interface{}, error) { ctx, cancel := context.WithCancel(ctx)var ( resp *http.Response errerror ) if c.finalizer != nil {//终结器 defer func() { if resp != nil { ctx = context.WithValue(ctx, ContextKeyResponseHeaders, resp.Header) ctx = context.WithValue(ctx, ContextKeyResponseSize, resp.ContentLength) } for _, f := range c.finalizer { f(ctx, err) } }() }//新建一个http请求对象 req, err := http.NewRequest(c.method, c.tgt.String(), nil) if err != nil {//如果新建失败,则切出上下文 cancel() return nil, err }//解码,如果出错切出上下文 if err = c.enc(ctx, req, request); err != nil { cancel() return nil, err }//执行befor for _, f := range c.before { ctx = f(ctx, req) }//发送请求 resp, err = c.client.Do(req.WithContext(ctx))if err != nil { cancel() return nil, err }//是否开启缓冲 if c.bufferedStream { resp.Body = bodyWithCancel{ReadCloser: resp.Body, cancel: cancel} } else { defer resp.Body.Close() defer cancel() }//执行after函数 for _, f := range c.after { ctx = f(ctx, resp) }//编码 response, err := c.dec(ctx, resp) if err != nil { return nil, err }//返回 return response, nil } }

总结 只能说简单看了下代码吧。最重要的还是里面的执行顺序。
server:
1、befor函数
2、解码
3、端点
4、after函数
5、编码
6、finalizer
client:
1、解码
2、befor函数
3、发请求
4、after函数
5、编码
【Go|Go - Kit 笔记 - 02 - Transport-http】注1:可以结合kit/examples/stringserver1来学习本篇。看完原理再看他那个示例难度不大。

    推荐阅读