Hertz中的代理
正向代理
正向代理是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。
一些网关、路由器等网络设备具备网络代理功能。
一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。
一个完整的代理请求过程为:客户端(Client)首先与代理服务器创建连接,接着根据代理服务器所使用的代理协议,请求对目标服务器创建连接、或者获得目标服务器的指定资源。
定义
// Proxy 结构体,根据 request 来选定访问的代理 uri
type Proxy func(*protocol.Request) (*protocol.URI, error)
// ProxyURI 用来生成只会返回固定代理 uri 的 Proxy
func ProxyURI(fixedURI *protocol.URI) Proxy
// SetProxy 用来设置 client 的 proxy,设置后 client 会与 proxy 建连发请求
func (c *Client) SetProxy(p protocol.Proxy)
示例
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app/client"
"github.com/cloudwego/hertz/pkg/protocol"
)
func main() {
proxyURL := "http://<__user_name__>:<__password__>@<__proxy_addr__>:<__proxy_port__>"
// 将代理的 uri 转成 *protocol.URI 的形式
parsedProxyURL := protocol.ParseURI(proxyURL)
c, err := client.NewClient()
if err != nil {
return
}
// 设置代理
c.SetProxy(protocol.ProxyURI(parsedProxyURL))
upstreamURL := "http://google.com"
_, body, _ := c.Get(context.Background(), nil, upstreamURL)
}
客户端默认不支持 TLS,如果要访问 https 地址,应该使用标准库
c, err := client.NewClient(client.WithDialer(standard.NewDialer()))
如果报证书错误还需要跳过证书验证
clientCfg := &tls.Config{
InsecureSkipVerify: true,
}
c, err := client.NewClient(client.WithTLSConfig(clientCfg), client.WithDialer(standard.NewDialer()))
反向代理
反向代理在计算机网络中是代理服务器的一种。
服务器根据客户端的请求,从其关系的一组或多组后端服务器(如 Web 服务器)上获取资源,然后再将这些资源返回给客户端,客户端只会得知反向代理的 IP 地址,而不知道在代理服务器后面的服务器集群的存在。
安装
go get github.com/hertz-contrib/reverseproxy
具体实现
type ReverseProxy struct {
// 用于转发的客户端,可以通过 SetClient 方法对其进行配置
client *client.Client
// 设置反向代理的目标地址
target string
// 用于转换 request,可以通过 SetDirector 方法来自定义
// director 必须是将一个请求转换为一个新的请求的函数。
// 响应直接未经修改重定向返回给原始客户端
// 请求返回后 direcotr 不得访问
director func (*protocol.Request)
// modifyResponse 这是一个可选的函数,用于修改来自后端的响应
// 可以通过 SetModifyResponse 方法进行修改
// 如果后端返回任意响应,不管状态码是什么,这个方法将会被调用。
// 如果后端不可访问,errorHandler 方法会使用错误信息做入参被调用。
// 如果 modifyResponse 方法返回一个错误,errorHandler 方法将会使用错误做入参被调用。
// 如果 errorHandler 未设置,将使用默认实现。
modifyResponse func(*protocol.Response) error
// errorHandler 是一个可选的函数,用于处理到达后台的错误或来自 modifyResponse 的错误。
// 如果未进行设置,默认返回 StatusBadGateway (502)
errorHandler func(*app.RequestContext, error)
}
// NewSingleHostReverseProxy 返回一个新的反向代理来路由请求到指定后端。如果后端路径是”/base“请求路径是”/dir” ,目标路径将会是“/base/dir” 。
// NewSingleHostReverseProxy 不会重写 Host 请求头。
// 要想覆盖 Host 请求头,可以选择自定义 director
func NewSingleHostReverseProxy(target string, opts ...config.Option) (*reverseProxy, error)
NewSingleHostReverseProxy方法如果没有设置
config.ClientOption将会使用默认的全局client.Client实例;如果设置了
config.ClientOption将会初始化一个client.Client实例。如果你需要共享一个
client.Client实例,可以使用ReverseProxy.SetClient来设置。反向代理会重置响应头,如果在请求之前修改了响应头将不会生效。
我们提供了 SetXxx() 函数用于设置私有属性
| 方法 | 描述 |
|---|---|
SetDirector |
用于指定 protocol.Request |
SetClient |
用于指定转发的客户端 |
SetModifyResponse |
用于指定响应修改方法 |
SetErrorHandler |
用于指定处理到达后台的错误或来自 modifyResponse 的错误 |
示例
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/reverseproxy"
)
func main() {
h := server.Default(server.WithHostPorts("127.0.0.1:8000"))
// 设置目标地址
proxy, err := reverseproxy.NewSingleHostReverseProxy("http://127.0.0.1:8000/proxy")
if err != nil {
panic(err)
}
h.GET("/proxy/backend", func(ctx context.Context, c *app.RequestContext) {
c.JSON(200, utils.H{
"msg": "proxy success!!",
})
})
// 设置代理
h.GET("/backend", proxy.ServeHTTP)
h.Spin()
}
配合中间件使用代理
可以在 hertz handler 中也使用 ReverseProxy.ServeHTTP 来实现复杂的需求而不是直接将 ReverseProxy.ServeHTTP 注册到路由。
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol"
"github.com/hertz-contrib/reverseproxy"
)
func main() {
h := server.New()
// 创建反向代理并配置路径和查询参数处理
proxy, err := reverseproxy.NewSingleHostReverseProxy("http://gzglnet.cn:8000")
if err != nil {
panic(err)
}
// 重写请求路径 主机 请求方法
proxy.SetDirector(
func(req *protocol.Request) {
req.SetRequestURI("/post")
req.SetMethod("POST")
req.SetHost("gzglnet.cn:8000")
},
)
h.Use(
func(ctx context.Context, c *app.RequestContext) {
if c.Query("country") == "cn" {
proxy.ServeHTTP(ctx, c)
c.Abort()
return
}
c.Next(ctx)
},
)
h.GET(
"/ping", func(ctx context.Context, c *app.RequestContext) {
c.String(200, "pong")
},
)
h.Spin()
}
当访问 http://127.0.0.1:8888/ping?country=cn 则代理到 http://gzglnet.cn:8000/post请求上,并且请求方法是post
而如果访问的是 http://127.0.0.1:8888/ping 怎直接本地响应
反向代理 Websocket
Websocket 反向代理,受 fasthttp-reverse-proxy 启发。
示例
package main
import (
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/hertz-contrib/reverseproxy"
)
func main() {
h := server.Default()
h.GET("/backend", reverseproxy.NewWSReverseProxy("ws://example.com").ServeHTTP)
h.Spin()
}
配置
| 配置 | 默认值 | 描述 |
|---|---|---|
WithDirector |
nil |
自定义转发头 |
WithDialer |
gorillaws.DefaultDialer |
自定义 Dialer |
WithUpgrader |
hzws.HertzUpgrader |
自定义 Upgrader |
更多示例
| 用途 | 示例代码 |
|---|---|
| 代理 tls | code |
| 使用服务发现 | code |
| 配合中间件使用 | code |
| 代理 websocket | code |
更多使用方法可参考如下 examples。
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/18745508

浙公网安备 33010602011771号