[已解决]Golang中ReverseProxy无法正常关闭的问题
[已解决]Golang中ReverseProxy无法正常关闭的问题 我正在尝试构建一个简单的反向代理,但在停止时遇到了问题。关闭命令已执行但代理仍在运行。有人知道该怎么办吗?
package main
import (
"context"
"log"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
go func() {
time.Sleep(1 * time.Second)
err := Stop()
if err != nil {
log.Println(err)
}
}()
err := Start("localhost:9999", "http://dockerhost:8065")
if err != nil {
log.Print(err)
}
}
var reverseProxy http.Server
func Start(bind string, remote string) error {
remoteUrl, err := url.Parse(remote)
if err != nil {
return err
}
reverseProxy := http.Server{
Handler: proxyHandler(remoteUrl),
Addr: bind,
}
err = reverseProxy.ListenAndServe()
if err != nil {
return err
}
log.Print("Stopped proxy")
return nil
}
func Stop() error {
log.Print("Stopper proxy.")
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
log.Print("Stopper proxy..")
if err := reverseProxy.Shutdown(ctx); err != nil {
return err
}
log.Print("Stopper proxy...")
return nil
}
func proxyHandler(remote *url.URL) *httputil.ReverseProxy {
handler := func(req *http.Request) {
req.URL.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.ParseForm()
log.Printf("%+v", req)
}
return &httputil.ReverseProxy{
Director: handler,
}
}
更多关于[已解决]Golang中ReverseProxy无法正常关闭的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
非常感谢,现在我终于可以安心睡觉了 😅
更多关于[已解决]Golang中ReverseProxy无法正常关闭的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
嗨 @muhaha,
这里的问题是你需要将这段代码:
reverseProxy := http.Server{
Handler: proxyHandler(remoteUrl),
Addr: bind,
}
改为:
reverseProxy = http.Server{
Handler: proxyHandler(remoteUrl),
Addr: bind,
}
否则你创建的是一个新的反向代理对象,它没有被赋值给你的全局变量,因此 Stop 方法实际上不会执行任何操作。
问题在于Start函数内部重新声明了reverseProxy变量,导致全局变量reverseProxy没有被正确初始化。在Go语言中,使用:=会在当前作用域创建一个新的局部变量,而不是使用全局变量。
以下是修复后的代码:
package main
import (
"context"
"log"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
go func() {
time.Sleep(1 * time.Second)
err := Stop()
if err != nil {
log.Println(err)
}
}()
err := Start("localhost:9999", "http://dockerhost:8065")
if err != nil {
log.Print(err)
}
}
var reverseProxy http.Server
func Start(bind string, remote string) error {
remoteUrl, err := url.Parse(remote)
if err != nil {
return err
}
// 移除 := 直接赋值给全局变量
reverseProxy = http.Server{
Handler: proxyHandler(remoteUrl),
Addr: bind,
}
err = reverseProxy.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
return err
}
log.Print("Stopped proxy")
return nil
}
func Stop() error {
log.Print("Stopper proxy.")
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
log.Print("Stopper proxy..")
if err := reverseProxy.Shutdown(ctx); err != nil {
return err
}
log.Print("Stopper proxy...")
return nil
}
func proxyHandler(remote *url.URL) *httputil.ReverseProxy {
handler := func(req *http.Request) {
req.URL.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.ParseForm()
log.Printf("%+v", req)
}
return &httputil.ReverseProxy{
Director: handler,
}
}
主要修改:
- 将
Start函数中的reverseProxy := http.Server{改为reverseProxy = http.Server{,直接赋值给全局变量 - 在
ListenAndServe的错误检查中添加了对http.ErrServerClosed的判断,因为正常关闭时服务器会返回这个错误
这样修改后,Stop函数就能正确访问到已初始化的reverseProxy实例,从而正常关闭服务器。

