位于github.com/go-kit/kit/transport/
,go-kit目前支持grpc、http、httprp、nats、netrpc、thrift
,传输层的作用是封装端点。使端点可以被不同的传输协议调用。
Server结构的作用是把端点封装成http.Handler
,http.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{}) error
type Server struct {
e endpoint.Endpoint //端点
dec DecodeRequestFunc //解码函数,需要自定义
enc EncodeResponseFunc //编码函数,需要自定义
before []RequestFunc //前置函数
after []ServerResponseFunc //后置函数
errorEncoder ErrorEncoder //错误函数
finalizer []ServerFinalizerFunc //终结器函数
logger log.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
}
可以理解为http爬虫,能发送各种http请求。
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
type Client struct {
client HTTPClient //接口
method string //方法(get、post、put、delete。。。)
tgt *url.URL //网址
enc EncodeRequestFunc //编码函数
dec DecodeResponseFunc //解码函数
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
err error
)
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、编码
注1:可以结合kit/examples/stringserver1
来学习本篇。看完原理再看他那个示例难度不大。