由于发文章时涉及到一些 m g 词汇,所以反复删除了原有的一些理解,这才能发表成功。
其中,一些词也纯拼音表示了,比如 dai li
ReverseProxy
位于 net.http.httputil
包下(只保留了这句 55555…)
功能点:
- 支持自定义修改响应内容
- 支持连接池
- 支持错误信息自定义处理
- 支持 websocket 服务
- 支持自定义负载均衡
- 支持 https dai li
- 支持 url 重写
源码分析
声明:go.14 版本
核心结构体
type ReverseProxy struct {
Director func(*http.Request)
Transport http.RoundTripper
FlushInterval time.Duration
ErrorLog *log.Logger
BufferPool BufferPool
ModifyResponse func(*http.Response) error
ErrorHandler func(http.ResponseWriter, *http.Request, error)
}
字段解释
字段 | 解释 |
---|---|
Director | 控制器 是一个函数,函数内容可以对请求进行修改 |
Transport | 连接池,如果为 nil,则使用 http.DefaultTransport |
FlushInterval | 刷新内容到客户端的时间间隔 |
ErrorLog | 错误记录器 |
BufferPool | 缓冲池,在复制 http 响应时使用,用以提高请求效率 |
ModifyResponse | 可自定义修改响应的函数 |
ErrorHandler | 错误处理回调函数,如果为 nil,则遇到错误会显示 502 |
核心方法
// 根据目的URL对象,返回一个新的 ReverseProxy
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
}
// 核心中的核心,实现了Handler接口
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
本文具体讲解 ServeHTTP
方法,逻辑比较长,所以概括了下实现步骤:
声明:每个步骤的代码都是单独列出,是连续的,中间没有删除和增加任何代码,和源码保持一致,除了一些注释信息
step 1 设置连接池
如果没有配置,则使用 http 的默认连接池
transport := p.Transport
if transport == nil {
transport = http.DefaultTransport
}
step 2 验证请求是否终止
从请求中取出上下文,然后通过类型断言 rw.(http.CloseNotifier)
,来判断连接(请求)是否终止,true 表示终止
如果终止了则直接放弃本次请求,即调用cancel()
,取消此上下文,当然对应的资源也就释放了。
其中http.CloseNotifier
是一个接口,只有一个方法CloseNotify() <-chan bool
,作用是检测连接是否断开
ctx := req.Context()
if cn, ok := rw.(http.CloseNotifier); ok {
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
defer cancel