简单的 Golang http反向代理

这篇博客介绍了如何使用Go语言构建一个简单的HTTP服务器,包括错误处理和超时控制,并实现了一个基本的代理服务,该代理服务能够转发请求但未实现负载均衡等高级功能。文中展示了代码实现,包括服务器的启动、请求处理和代理请求的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先起一个目标服务

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)
	mux.HandleFunc("/test_http_string/test_http_string/aaa", r.TimeoutHandler)
	server := &http.Server{
		Addr:         r.Addr,
		WriteTimeout: time.Second * 3,
		Handler:      mux,
	}
	go func() {
		log.Fatal(server.ListenAndServe())
	}()
}

func (r *RealServer) HelloHandler(w http.ResponseWriter, req *http.Request) {
	//127.0.0.1:8008/abc?sdsdsa=11
	//r.Addr=127.0.0.1:8008
	//req.URL.Path=/abc
	//fmt.Println(req.Host)
	upath := fmt.Sprintf("http://%s%s\n\n", r.Addr, req.URL.Path)
	realIP := fmt.Sprintf("RemoteAddr=%s,X-Forwarded-For=%v,X-Real-Ip=%v\n\n", req.RemoteAddr, req.Header.Get("X-Forwarded-For"), req.Header.Get("X-Real-Ip"))
	header:=fmt.Sprintf("headers =%v\n\n",req.Header)
	io.WriteString(w, upath)
	io.WriteString(w, realIP)
	io.WriteString(w, header)

}

func (r *RealServer) ErrorHandler(w http.ResponseWriter, req *http.Request) {
	upath := "error handler"
	w.WriteHeader(500)
	io.WriteString(w, upath)
}

func (r *RealServer) TimeoutHandler(w http.ResponseWriter, req *http.Request) {
	time.Sleep(2*time.Second)
	upath := "timeout handler"
	w.WriteHeader(200)
	io.WriteString(w, upath)
}

下边是我们编辑的代理

这里边只是简单代理转发 错误处理,负载等等 均没有实现

package main

import (
	"bufio"
	"fmt"
	"log"
	"net/http"
	"net/url"
)

var (
	proxy_addr = "http://127.0.0.1:2003/111"
	port       = "2002"
)

func handler(w http.ResponseWriter, r *http.Request) {
	//step 1 解析代理地址,并更改请求体的协议和主机
	proxy, err := url.Parse(proxy_addr)
	fmt.Println("proxy",proxy)
	r.URL.Scheme = proxy.Scheme
	r.URL.Host = proxy.Host

	fmt.Println("URL",r.URL.Scheme)

	//step 2 请求下游
	transport := http.DefaultTransport
	resp, err := transport.RoundTrip(r)
	if err != nil {
		log.Print(err)
		return
	}

	//step 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)
	}
}

其实这个时候可以思考一下 这一篇代理文章和上篇的区别

Golang中实现WebSocket反向代理相对简单。你可以使用`gorilla/websocket`包来处理WebSocket连接,并使用`net/http/httputil`包来实现反向代理。 首先,你需要安装`gorilla/websocket`包。可以使用以下命令来安装: ``` go get github.com/gorilla/websocket ``` 接下来,你可以使用以下代码来创建一个WebSocket反向代理: ```go package main import ( "log" "net/http" "net/http/httputil" "net/url" "github.com/gorilla/websocket" ) func main() { // 创建一个反向代理的目标URL backendURL := "ws://localhost:8081/ws" targetURL, err := url.Parse(backendURL) if err != nil { log.Fatal(err) } // 创建WebSocket代理 proxy := httputil.NewSingleHostReverseProxy(targetURL) // WebSocket处理函数 websocketHandler := func(w http.ResponseWriter, r *http.Request) { // 升级HTTP连接到WebSocket连接 upgrader := websocket.Upgrader{} conn, err := upgrader.Upgrade(w, r, nil) if err != nil { http.Error(w, "Failed to upgrade to WebSocket", http.StatusInternalServerError) return } defer conn.Close() // 反向代理WebSocket连接 proxy.ServeHTTP(w, r) } // 注册WebSocket处理函数 http.HandleFunc("/ws", websocketHandler) // 启动HTTP服务器 log.Println("Starting server on :8080") err = http.ListenAndServe(":8080", nil) if err != nil { log.Fatal(err) } } ``` 以上代码创建了一个简单的WebSocket反向代理,将所有连接到`/ws`路径的WebSocket连接转发到`ws://localhost:8081/ws`。你可以根据实际需求修改代理的目标URL和端口。 请注意,这只是一个简单的示例,你可能需要根据你的具体需求进行修改和扩展。此外,你还可以添加身份验证、错误处理等功能来完善代理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JwCode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值