Go语言基础负载均衡器404问题:请求未进入处理函数求助
Go负载均衡器请求未进入处理函数导致404问题排查
问题现象
运行程序后终端输出:
1 2 7 8 server serving at 'http://localhost:3000'
访问localhost:3000/时出现404错误,终端无额外输出,服务器未崩溃,且请求从未进入handleRedirect()函数。
用户代码
package main import ( "fmt" "net/http" "net/http/httputil" "net/url" "os" ) type Server interface { Address() string IsAlive() bool Serve(rw http.ResponseWriter, r *http.Request) } type SimpleServer struct { address string proxy *httputil.ReverseProxy } func newSimpleServer(address string) *SimpleServer { serverURL, err := url.Parse(address) handleError(err) return &SimpleServer{ address: address, proxy: httputil.NewSingleHostReverseProxy(serverURL), } } type LoadBalancer struct { port string roundRobinCount int servers []Server } func newLoadBalancer(port string, servers []Server) *LoadBalancer { return &LoadBalancer{ port: port, roundRobinCount: 0, servers: servers, } } func (s *SimpleServer) Address() string { return s.address } func (s *SimpleServer) IsAlive() bool { return true } func (s *SimpleServer) Serve(rw http.ResponseWriter, r *http.Request) { fmt.Println(6) s.proxy.ServeHTTP(rw, r) } func (lb *LoadBalancer) getNextAvailableServer() Server { server := lb.servers[lb.roundRobinCount%len(lb.servers)] for !server.IsAlive() { lb.roundRobinCount++ server = lb.servers[lb.roundRobinCount%len(lb.servers)] } lb.roundRobinCount++ return server } func (lb *LoadBalancer) ServeProxy(rw http.ResponseWriter, r *http.Request) { fmt.Println(4) targetServer := lb.getNextAvailableServer() fmt.Printf("forwarding reques to %q\n", targetServer.Address()) fmt.Println(5) targetServer.Serve(rw, r) } func main() { fmt.Println(1) servers := []Server{ newSimpleServer("https://www.fast.com/"), newSimpleServer("https://www.theverge.com/"), newSimpleServer("https://www.canva.com/"), } fmt.Println(2) lb := newLoadBalancer("3000", servers) handleRedirect := func(rw http.ResponseWriter, req *http.Request) { fmt.Println(3) lb.ServeProxy(rw, req) } fmt.Println(7) http.HandleFunc("/", handleRedirect) fmt.Println(8) fmt.Printf("server serving at 'http://localhost:%s'\n", lb.port) http.ListenAndServe(":"+lb.port, nil) } func handleError(err error) { if err != nil { fmt.Printf("you've got an error fix it asap %v\n", err) os.Exit(1) } }
解决方案
1. 修复路由未触发问题
默认全局http.DefaultServeMux可能被隐式操作修改,导致路由注册失效。替换为自定义多路复用器即可解决:
修改main函数:
func main() { fmt.Println(1) servers := []Server{ newSimpleServer("https://www.fast.com/"), newSimpleServer("https://www.theverge.com/"), newSimpleServer("https://www.canva.com/"), } fmt.Println(2) lb := newLoadBalancer("3000", servers) handleRedirect := func(rw http.ResponseWriter, req *http.Request) { fmt.Println(3) lb.ServeProxy(rw, req) } fmt.Println(7) // 创建自定义多路复用器,避免默认Mux的潜在问题 mux := http.NewServeMux() mux.HandleFunc("/", handleRedirect) fmt.Println(8) fmt.Printf("server serving at 'http://localhost:%s'\n", lb.port) // 使用自定义Mux启动服务,并检查启动错误 err := http.ListenAndServe(":"+lb.port, mux) handleError(err) }
2. 修复反向代理导致的404问题
默认反向代理会保留原请求的Host头(localhost:3000),目标服务器无法识别该Host,因此返回404。需修改代理的Director函数替换Host头:
修改newSimpleServer函数:
func newSimpleServer(address string) *SimpleServer { serverURL, err := url.Parse(address) handleError(err) proxy := httputil.NewSingleHostReverseProxy(serverURL) // 自定义Director,修改请求Host头为目标服务器的Host originalDirector := proxy.Director proxy.Director = func(req *http.Request) { originalDirector(req) req.Host = serverURL.Host } return &SimpleServer{ address: address, proxy: proxy, } }
额外排查建议
- 用
netstat类命令确认3000端口确实被你的程序监听 - 直接访问
http://localhost:3000/(确保路径带末尾斜杠),避免浏览器自动跳转影响 - 检查防火墙设置,确保本地请求能到达3000端口
内容的提问来源于stack exchange,提问作者zxcvbnm
相关产品推荐
相关产品推荐

