正向代理和反向代理实现
1. 两者基本概念
网络代理 : 控制和管理某个网络主机的访问
控制:客户端/服务端流量控制,黑/白名单,权限校验,URL重写
管理:流量控制,编解码,Header头转换,负载均衡,服务发现,连接池
访问流程:
用户访问代理服务器
请求通过网络代理完成转发等到目标服务器
目标服务器响应后再通过网络代理回传给用户
转发的区别在于
转发: 对 IP 分组进行发送
代理: 对下游服务器的访问控制 ( 源节点 , 目标节点 )
1.1 正向代理 (客户端代理)
功能:帮助客户访问无法访问的服务器资源,隐藏用户真实 IP ,浏览器 web代理,VPN
帮助客户访问无法访问的服务器资源
用户 A 无法直接访问 google 服务器,这时即可以通过代理服务器,讲请求发送给代理服务器,由代理服务器代替用户 A 访问 google 服务器,代理服务器将结果返回给用户 A
缓存数据
用户 A 通过代理服务器访问服务器上的某一份资源,代理服务器接收到数据后会一份数据到本地,如果用户 B 也想要同一份数据,就可以直接在代理服务器上获取
隐藏用户真实 IP
用户 A 想要访问某台服务器,但是不想让服务器知道是他在访问,就可以让代理服务器代替用户 A 访问,“肉鸡”就是一台代理服务器
1.2 反向代理 (服务端代理)
为服务器做负载均衡,缓存,提供安全校验等
保护服务器(隐藏服务器真实 IP)
为了保护真实的服务器,用户 A 只能通过访问代理服务器来请求真正的服务器,这样就保证了服务器的安全
负载均衡
假设有 1000 个用户在对某个服务发送请求,代理服务器通过负载均衡算法,可以讲这些求求分发到不同的服务器去进行处理,从而提供服务处理效率,减小服务器的压力
微服务中的限流和认证都可以理解为是反向代理的功能
2. 正向代理实现
实现步骤
启动一个真实的下游服务器
代理服务器接受客户端请求,复制,封装
发送新请求到真实服务器,接收响应
处理响应并返回客户单
// 启动真实的http服务器
func HttpServer() {
// 一: 设置不同路由对应的不同处理器
// 第一种方式: HandleFunc
http.HandleFunc("/ping", HandlerPing)
// 二:启动监听
addr := ":8080"
log.Println("HTTP 服务器正在监听: ", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatalln(err)
}
}
func HandlerPing(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "pong")
}
func ForwardProxyServer() {
fmt.Println("正向代理服务器启动 :8080")
http.Handle("/", &Pxy{})
http.ListenAndServe("127.0.0.1:8080", nil)
}
// Pxy 定义一个类型,实现 Handler interface
type Pxy struct{}
// ServeHTTP 具体实现方法
func (p *Pxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
fmt.Printf("Received request %s %s %s:\n", req.Method, req.Host, req.RemoteAddr)
// 1. 代理服务器接收客户端请求,复制,封装成新请求
outReq := &http.Request{}
*outReq = *req
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
// XFF,用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段
if prior, ok := outReq.Header["X-Forwarded-For"]; ok {
clientIP = strings.Join(prior, ", ") + ", " + clientIP
}
outReq.Header.Set("X-Forwarded-For", clientIP)
}
//fmt.Printf("req %s:\n", req.Header.Get("X-Forwarded-For"))
//fmt.Printf("outReq %s:\n", outReq.Header.Get("X-Forwarded-For"))
// 2. 发送新请求到下游真实服务器,接收响应
transport := http.DefaultTransport
res, err := transport.RoundTrip(outReq)
if err != nil {
rw.WriteHeader(http.StatusBadGateway)
return
}
// 3. 处理响应并返回上游客户端
for key, value := range res.Header {
for _, v := range value {
rw.Header().Add(key, v)
}
}
rw.WriteHeader(res.StatusCode)
io.Copy(rw, res.Body)
res.Body.Close()
}
3. 反向代理实现
实现步骤
启动一个真实服务器: gateway/proxy/http_proxy/downstream_real_server.go
代理接收客户端请求,更改请求结构体信息
通过一定的负载均衡算法获取下游服务地址 // 3.把请求发送到下游服务器,并获取返回内容
对返回内容做一些处理,然后返回给客户端
// 1.启动真实的服务器
func RealHTTPServer() {
// 初始化RealServer服务器结构体
server := RealServer{Addr: "127.0.0.1:8001"}
server.Run()
select {}
}
func (r *RealServer) Run() {
mux := http.NewServeMux()
mux.HandleFunc("/sakura", r.HelloHandler)
server := http.Server{
Addr: r.Addr,
Handler: mux,
WriteTimeout: time.Second * 3,
}
go func() {
fmt.Println("http服务器务已启动:", server.Addr)
server.ListenAndServe()
}()
}
type RealServer struct {
Addr string
}
func (r *RealServer) HelloHandler(w http.ResponseWriter, req *http.Request) {
// 拼接真实服务器地址
URL := fmt.Sprintf("这是真实服务器,地址为: http://%s%s", r.Addr, req.URL.Path)
w.Write([]byte(URL))
}
func CustomerReverseProxySever() {
var port = "8081" // 当前代理服务器端口
http.HandleFunc("/", handler)
fmt.Println("反向代理服务器启动: " + port)
http.ListenAndServe(":"+port, nil)
}
var (
proxyAddr = "http://127.0.0.1:8001"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Println("经过代理服务器地址")
// 1.解析下游服务器地址,更改请求地址
// 被代理的下游真实服务器地址.应该通过一定的负载均衡算法获取
realServer, err := url.Parse(proxyAddr)
r.URL.Scheme = realServer.Scheme // http
r.URL.Host = realServer.Host // 127.0.0.1:8001
// 2.请求下游(真实服务器),并获取返回内容
transport := http.DefaultTransport
resp, err := transport.RoundTrip(r) // 得到下游服务器响应
defer resp.Body.Close()
if err != nil {
log.Print(err)
return
}
// 3.把下游请求内容做一些处理,然后返回给上游(客户端)
for k, vv := range resp.Header { // 修改上游响应头
for _, v := range vv {
w.Header().Add(k, v)
}
}
bufio.NewReader(resp.Body).WriteTo(w) // 将下游响应体写回上游客户端
}
4. 使用 ReverseProxy 实现反向代理
使用 ReverseProxy 实现一个简易版的代理服务器
var (
//代理服务器地址
proxyAddr = "127.0.0.1:8081"
)
// 使用 ReverProxy 实现反向代理
func ReverseProxySever() {
// 解析下游服务器的真实地址
realServer := "http://127.0.0.1:8001"
serverUrl, err := url.Parse(realServer)
if err != nil {
log.Fatalln("parse fail,")
}
proxy := httputil.NewSingleHostReverseProxy(serverUrl)
log.Println("Starting proxy Server:", proxyAddr)
// proxy 就相当于 handle
http.ListenAndServe(proxyAddr, proxy)
}
启动代理服务器
启动真实服务器
使用代理服务器的地址访问真实服务器的路由
评论区