5分钟搭建高性能HTTP反向代理,Go语言极简实现
你有没有遇到过这样的场景:本地开发时,前端需要调用后端接口,但跨域问题让人头疼;或者线上服务需要把不同路径的请求转发到不同端口,配置Nginx又嫌太重。其实,用Go语言自己写一个HTTP反向代理,代码不到50行,运行效率却吊打大多数配置方案。
今天我就带你手写一个生产可用的反向代理,支持路径规则转发、请求头透传、错误处理。就算你刚学Go两周,也能看懂。
核心思路
反向代理的核心是:接收客户端请求,根据规则把请求转发给后端真实服务,再把后端响应原样返回给客户端。Go标准库 net/http/httputil 里的 ReverseProxy 已经帮我们封装好了大部分逻辑,你只需要写一个路由匹配器就够了。
完整代码实现
下面是完整的Go代码,每一行都有中文注释,你直接复制就能跑。
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings"
)
// 定义一个映射表:路径前缀 -> 目标服务器地址
var routes = map[string]string{
"/api/": "http://localhost:8081", // 所有 /api/ 开头的请求转发到 8081
"/web/": "http://localhost:8082", // 所有 /web/ 开头的请求转发到 8082
}
// createProxy 根据目标地址创建一个反向代理处理器
func createProxy(target string) *httputil.ReverseProxy {
// 解析目标URL,比如 "http://localhost:8081"
targetURL, err := url.Parse(target)
if err != nil {
log.Fatalf("目标地址解析失败: %v", err)
}
// 新建反向代理实例
proxy := httputil.NewSingleHostReverseProxy(targetURL)
// 自定义错误处理:当后端服务挂掉时,返回友好的500页面
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
log.Printf("代理错误: %v", err)
http.Error(w, "后端服务暂时不可用,请稍后再试", http.StatusServiceUnavailable)
}
return proxy
}
// 路由分发处理器
func handler(w http.ResponseWriter, r *http.Request) {
// 遍历路由表,寻找匹配的前缀
for prefix, target := range routes {
if strings.HasPrefix(r.URL.Path, prefix) {
// 匹配成功,创建对应代理并转发请求
proxy := createProxy(target)
proxy.ServeHTTP(w, r)
return
}
}
// 没有匹配任何路由,返回404
http.NotFound(w, r)
}
func main() {
// 注册路由处理函数
http.HandleFunc("/", handler)
// 启动代理服务器,监听8888端口
log.Println("反向代理已启动,监听端口 :8888")
err := http.ListenAndServe(":8888", nil)
if err != nil {
log.Fatalf("服务器启动失败: %v", err)
}
}
运行测试
- 先把代码保存为
proxy.go。 - 确保你的后端服务已经在对应的端口上运行(比如8081和8082)。
- 终端执行
go run proxy.go。 - 访问
http://localhost:8888/api/users,请求会被自动转发到http://localhost:8081/users。 - 访问
http://localhost:8888/web/index.html,请求被转发到http://localhost:8082/index.html。
进阶玩法
- 负载均衡:可以把同一个路径映射到多个后端,用轮询或随机策略。
- 请求头修改:在
ReverseProxy的Director回调里修改r.Header。 - HTTPS支持:用
http.ListenAndServeTLS启动,或者在外面套一层Nginx。
这个代理占用的内存极小,启动速度毫秒级,特别适合微服务场景下的本地开发调试。如果你不想装Nginx或者用Docker,这个方案就是最轻量的选择。
