什么是网络代理
- 用户通过代理请求信息
- 请求通过网络代理完成转发到达目标服务器
- 目标服务器响应后再通过网络代理回传给用户
网络代理与网络转发的区别
网络代理:用户不直接连接服务器,网络代理去连接。获取数据后返回给用户
网络转发:路由器对报文进行转发操作,中间可能对数据包修改。
网络代理类型
正向代理:是一种客户端的代理技术,帮助客户端访问无法访问的服务资源,可以隐藏用户的真实 IP 。比如:浏览器 web 代理、 VPN 等
反向代理:是一种服务端的代理技术,帮助服务器做负载均衡、缓存、提供安全校验等,可以隐藏服务器的真实 IP 。比如: LVS 技术、 nginx proxy_pass 等
正向代理(实现一个 web 浏览器代理)
正向代理不是我们的研究重点,这里做最简单实现,方便理解
- 代理接收客户端请求,复制原请求对象,并根据数据配置新请求各种参数
- 把新请求发送到真实服务端,并接收到服务端返回
- 代理服务器对响应做一些处理,然后返回给客户端
简单代码实现如下:
package main
import (
"fmt"
"io"
"net"
"net/http"
"strings"
)
type Pxy struct{}
func (p *Pxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
fmt.Printf("Received request %s %s %s\n", req.Method, req.Host, req.RemoteAddr)
transport := http.DefaultTransport
// 1 浅拷贝对象,然后再新增属性数据
outReq := new(http.Request)
*outReq = *req
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
if prior, ok := outReq.Header["X-Forwarded-For"]; ok {
clientIP = strings.Join(prior, ", ") + ", " + clientIP
}
outReq.Header.Set("X-Forwarded-For", clientIP)
}
// 2 请求下游
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()
}
func main() {
fmt.Println("Serve on :8080")
http.Handle("/", &Pxy{})
http.ListenAndServe("0.0.0.0:8080", nil)
}
反向代理
简易版 HTTP 代理
这个功能比较复杂,我们先实现一个简易版 HTTP 反向代理
- 代理接收客户端请求,更改请求结构体信息
- 通过一定的负载均衡算法获取下游服务地址
- 把请求发送到下游服务器,并获取返回内容
- 对返回内容做一些处理,然后返回给客户端
真实服务器代码如下:
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
rs1 := &RealServer{Addr: "127.0.0.1:2003"}
rs1.Run()
rs2 := &RealServer{Addr: "127.0.0.1:2004"}
rs2.Run()
// 监听关闭信号
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
}
type RealServer struct {
Addr string
}
func (r *RealServer) Run() {
log.Println("Starting httpserver at " + r.Addr)
mux := http.NewServeMux()
mux.HandleFunc("/", r.HelloHandler)
mux.HandleFunc("/base/error", r.ErrorHandler)
server := &http.Server{
Addr: r.Addr,
WriteTimeout: 3 * time.Second,
Handler: mux,
}
go func() {
log.Fatal(server.ListenAndServe())
}()
}
func (r *RealServer) HelloHandler(w http.ResponseWriter, req *http.Request) {
upath := fmt.Sprintf("http://%s%s\n", r.Addr, req.URL.Path)
io.WriteString(w, upath)
}
func (r *RealServer) ErrorHandler(w http.ResponseWriter, req *http.Request) {
upath := "error handler"
w.WriteHeader(500)
io.WriteString(w, upath)
}
反向代理简单实现代码如下:
package main
import (
"bufio"
"log"
"net/http"
"net/url"
)
var (
proxy_addr = "http://127.0.0.1:2003"
port = "2002"
)
func handler(w http.ResponseWriter, r *http.Request) {
// 1 解析代理地址,并更改请求体的协议和主机
proxy, err := url.Parse(proxy_addr)
r.URL.Scheme = proxy.Scheme
r.URL.Host = proxy.Host
// 2 请求下游
transport := http.DefaultTransport
resp, err := transport.RoundTrip(r)
if err != nil {
log.Print(err)
return
}
// 3 把下游请求内容返回给上游
for k, vv := range resp.Header {
for _, v := range vv {
w.Header().Add(k, v)
}
}
defer resp.Body.Close()
bufio.NewReader(resp.Body).WriteTo(w)
}
func main() {
http.HandleFunc("/", handler)
log.Println("Start serving on port " + port)
err := http.ListenAndServe(":"+port, nil)
if err != nil {
log.Fatal(err)
}
}