golang实现简单http正向代理和反向代理

307次阅读
没有评论

共计 2190 个字符,预计需要花费 6 分钟才能阅读完成。

正向代理

package main

/**
正向代理
 */

import (
  "net/http"
  "fmt"
  "net"
  "strings"
  "io"
)

type Proxy struct {
}

func (p *Proxy) ServeHTTP(w http.ResponseWriter, req *http.Request){
  fmt.Printf("接受请求 %s %s %s\n",req.Method,req.Host,req.RemoteAddr)

  transport:=http.DefaultTransport

  // 第一步: 代理接受到客户端的请求,复制原来的请求对象,并根据数据配置新请求的各种参数(添加上X-Forward-For头部等)
  outReq:=new(http.Request)
  *outReq = *req // 这只是一个浅层拷贝

  clientIP,_,err:=net.SplitHostPort(req.RemoteAddr)
  if err==nil{
    prior,ok:=outReq.Header["X-Forwarded-For"]
    if ok {
      clientIP = strings.Join(prior,", ")+", "+clientIP
    }
    outReq.Header.Set("X-Forwarded-For",clientIP)
  }

  // 第二步: 把新请求复制到服务器端,并接收到服务器端返回的响应
  res,err:=transport.RoundTrip(outReq)
  if err!=nil{
    w.WriteHeader(http.StatusBadGateway) // 502
    return
  }

  // 第三步:代理服务器对响应做一些处理,然后返回给客户端
  for key,value:=range res.Header{
    for _,v:=range value{
      w.Header().Add(key,v)
    }
  }

  w.WriteHeader(res.StatusCode)
  io.Copy(w,res.Body)
  res.Body.Close()
}

func main() {
  fmt.Println("Serve on :8080")
  http.Handle("/",&Proxy{})
  http.ListenAndServe("0.0.0.0:8080",nil)
}

// 代码运行之后,会在本地的 8080 端口启动代理服务。修改浏览器的代理为 127.0.0.1::8080
// 再访问网站,可以验证代理正常工作,也能看到它在终端打印出所有的请求信息。

 

反向代理

package main

import (
  "net/url"
  "net/http/httputil"
  "net/http"
  "math/rand"
  "log"
)

/**
反向代理:编写反向代理按照上面的思路当然没有问题,只需要在第二步的时候,根据之前的配置修改 outReq 的 URL Host 地址可以了。
不过 Golang 已经给我们提供了编写代理的框架: httputil.ReverseProxy 。我们可以用非常简短的代码来实现自己的代理,而且内
部的细节问题都已经被很好地处理了。
实现一个简单的反向代理,它能够对请求实现负载均衡,随机地把请求发送给某些配置好的后端服务器。使用 httputil.ReverseProxy
编写反向代理最重要的就是实现自己的 Director 对象,这是 GoDoc 对它的介绍
Director必须是一个功能,它将请求修改为使用Transport发送的新请求。然后将其响应未经修改地复制回原始客户端。 Director返回
后不得访问提供的请求。
简单翻译的话, Director 是一个函数,它接受一个请求作为参数,然后对其进行修改。修改后的请求会实际发送给服务器端,因此我们编
写自己的 Director 函数,每次把请求的
Scheme 和 Host 修改成某个后端服务器的地址,就能实现负载均衡的效果(其实上面的正向代理也可以通过相同的方法实现)
 */

func NewMultipleHostsReverseProxy(targets []*url.URL) *httputil.ReverseProxy{
 	director:= func(req *http.Request) {
 		target:=targets[rand.Int()*len(targets)]
 		req.URL.Scheme = target.Scheme
 		req.URL.Host = target.Host
 		req.URL.Path = target.Path
  }
 	return &httputil.ReverseProxy{
 		Director:director,
  }
}

func main() {
  proxy:=NewMultipleHostsReverseProxy([]*url.URL{
    {
      Scheme:"http",
      Host:"localhost:9091",
    },
    {
      Scheme:"http",
      Host:"localhost:9092",
    },
  })
  log.Fatal(http.ListenAndServe(":9090",proxy))
}

// 让代理监听在 9090 端口,在后端启动两个返回不同响应的服务器分别监听
// 在 9091 和 9092 端口,通过 curl 访问,可以看到多次请求会返回不同的结果。
// curl http://127.0.0.1:9090
// curl http://127.0.0.1:9090

 

正文完
 
admin
版权声明:本站原创文章,由 admin 2022-03-26发表,共计2190字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码