Go|Go - Kit 笔记 - 02 - Transport-http
Transport – 传输层 位于github.com/go-kit/kit/transport/
,go-kit目前支持grpc、http、httprp、nats、netrpc、thrift
,传输层的作用是封装端点。使端点可以被不同的传输协议调用。
Server结构 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{}) 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
来学习本篇。看完原理再看他那个示例难度不大。推荐阅读
- EffectiveObjective-C2.0|EffectiveObjective-C2.0 笔记 - 第二部分
- Android中的AES加密-下
- 【读书笔记】贝叶斯原理
- 【韩语学习】(韩语随堂笔记整理)
- 人性的弱点-笔记
- 读书笔记:博登海默法理学|读书笔记:博登海默法理学 —— 正义的探索(1)
- D034+3组苏曼+《写作这回事》读书笔记
- 《自我的追寻》读书笔记3
- 最有效的时间管理工具(赢效率手册和总结笔记)
- 机器学习|机器学习 Andrew Ng《Machine Learning》课程笔记1