标签:header scheme 客户端代理 校验 sig lvs url 请求 serve
1 概念一种客户端代理技术,用于帮助客户端访问无法直接访问的网络资源,并隐藏客户端IP,常见的场景有***、浏览器HTTP代理
一种服务端代理技术,用于隐藏真实服务端节点,并实现负载均衡、缓存、安全校验、协议转换等,常见的有LVS、nginx
package main
import (
"fmt"
"io"
"log"
"net"
"net/http"
"strings"
)
type proxy struct {}
func (p *proxy)ServeHTTP(w http.ResponseWriter,r *http.Request){
fmt.Printf("Received request: %s %s %s\n",r.Method,r.Host,r.RemoteAddr)
transport := http.DefaultTransport
// 浅拷贝一个request 对象,避免后续修影响了源对象
req := new(http.Request)
*req = *r
// 设置X-Forward-For 头部
if clientIp,_,err := net.SplitHostPort(r.RemoteAddr);err ==nil{
if prior,ok := req.Header["X-Forward-For"];ok{
clientIp = strings.Join(prior,", ") + ", " + clientIp
}
req.Header.Set("X-Forward-For",clientIp)
}
// 构造新请求
response,err:=transport.RoundTrip(req)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
// 获取响应数据并返回
for k,v := range response.Header{
for _,v1 := range v{
w.Header().Add(k,v1)
}
}
w.WriteHeader(response.StatusCode)
io.Copy(w,response.Body)
response.Body.Close()
}
func main() {
//mux := http.NewServeMux()
server := &http.Server{
Addr: ":9090",
Handler: &proxy{},
}
if err:=server.ListenAndServe();err != nil{
log.Fatal("Http proxy server start failed.")
}
}
Http real Server 实现:监听8081和8082端口,返回请求的URL
package main
import (
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
type realServer struct {
Addr string
}
func (rs *realServer) HelloHandler(w http.ResponseWriter,r *http.Request){
reqUrl := fmt.Sprintf("http://%s%s\n",rs.Addr,r.RequestURI)
w.Write([]byte(reqUrl))
}
func (rs *realServer) Run(){
fmt.Println("Http server tart to serve at :",rs.Addr)
mux := http.NewServeMux()
mux.HandleFunc("/",rs.HelloHandler)
server := &http.Server{
Addr: rs.Addr,
Handler: mux,
WriteTimeout: time.Second * 3,
}
go func(){
if err := server.ListenAndServe();err != nil{
log.Fatal("Start http server failed,err:",err)
}
}()
}
func main() {
rs1 := &realServer{Addr:"127.0.0.1:8081"}
rs2 := &realServer{Addr:"127.0.0.1:8082"}
go rs1.Run()
go rs2.Run()
doneCh := make(chan os.Signal)
signal.Notify(doneCh,syscall.SIGINT,syscall.SIGTERM)
<- doneCh
}
模拟请求
// output
$ curl http://127.0.0.1:8081/hellotest?id=1 -s
http://127.0.0.1:8081/hellotest?id=1
$ curl http://127.0.0.1:8082/hellotest?id=2 -s
http://127.0.0.1:8082/hellotest?id=2
反向代理服务端实现
package main
import (
"bufio"
"fmt"
"log"
"net/http"
"net/url"
"time"
)
var serverPort = "8888"
// 为了测试,简单的通过当前时间戳取余的方式模拟随机访问后端rs
func GetRandServer()string{
ports := []string{"8081","8082"}
n := time.Now().Unix() % 2
return ports[n]
}
func handler(w http.ResponseWriter,r *http.Request){
// 解析并修改代理服务
port := GetRandServer()
proxyAddr := "http://127.0.0.1:" + port
proxy ,err := url.Parse(proxyAddr)
if err != nil{
log.Println(err)
return
}
r.URL.Scheme = proxy.Scheme
r.URL.Host = proxy.Host
// 代理请求
transport := http.DefaultTransport
resp ,err := transport.RoundTrip(r)
if err != nil{
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// 将响应结果返回
for key,value := range resp.Header{
for _,v := range value{
w.Header().Add(key,v)
}
}
defer resp.Body.Close()
bufio.NewReader(resp.Body).WriteTo(w)
}
func main() {
http.HandleFunc("/",handler)
fmt.Println("Http reverse proxy server start at : 127.0.0.1:",serverPort)
if err := http.ListenAndServe(":"+serverPort,nil);err != nil{
log.Fatal("Start server failed,err:",err)
}
}
测试
$ for i in {0..9};do curl http://127.0.0.1:8888/reversetest?id=111 -s;done
http://127.0.0.1:8082/reversetest?id=111
http://127.0.0.1:8082/reversetest?id=111
http://127.0.0.1:8082/reversetest?id=111
http://127.0.0.1:8082/reversetest?id=111
http://127.0.0.1:8081/reversetest?id=111
http://127.0.0.1:8081/reversetest?id=111
http://127.0.0.1:8081/reversetest?id=111
http://127.0.0.1:8081/reversetest?id=111
http://127.0.0.1:8081/reversetest?id=111
http://127.0.0.1:8082/reversetest?id=111
标签:header scheme 客户端代理 校验 sig lvs url 请求 serve
原文地址:https://blog.51cto.com/pmghong/2504475