在 golang 中使用反向代理, 怎么处理代理失效的问题

2020-10-19 22:03:59 +08:00
 prenwang

如下代码, 使用了 echo 框架, 将主程序 /xy/* 的请求代理到 http://xy.abc.com/xy/*

proxy := httputil.NewSingleHostReverseProxy("http://xy.abc.com")

e.Any("/xy/*", echo.WrapHandler(proxy))

实际使用过程中发现很多不稳定, 用着用着 404 了, 如果 http://xy.abc.com 后启动, 主程序的代理也不生效, 这个用法感觉很原始,需要自己去处理状态检测。

有什么好的处理办法吗

1906 次点击
所在节点    Go 编程语言
6 条回复
cupen
2020-10-20 11:19:19 +08:00
你的描述比较模糊.

> 实际使用过程中发现很多不稳定, 用着用着 404 了
如果是 echo 返回了 404, bug 得去 echo 开发者那去问下.

> 如果 http://xy.abc.com 后启动, 主程序的代理也不生效
不生效是指 404 还是 502 ? 也得去看 echo 开发者去问下.

> 这个用法感觉很原始,需要自己去处理状态检测。
通常反向代理通常只负责转发请求, 并不负责返回 404. 报错或超时了会返回 502.
高级点确实需要健康检查, 比如定期给后端发送 HEAD /healthy . 收到 200 则认为 ok 否则认为挂球.
axex
2020-10-20 14:17:05 +08:00
这种用法有些罕见啊,一般都是 nginx 、envoy 、traefik 等专门来反向代理、负载均衡。
prenwang
2020-10-20 17:47:35 +08:00
@cupen
@axex

实际项目中,有几个不同的子系统模块,使用了其他语言 node,php 开发,和主系统一样都是提供 json api 的 webserver

所以在主程序这里对所有前端请求做 分发, 由于在前端直接调用子系统的 API 会有一些问题, 比如跨域的兼容性, 统一权限拦截处理,子系统是没有权限判断的,统一在主系统 webserver 处理。


这应该算是比较简单的微服务调用吧


现在处理有了一点进展, 主系统处理了一个大 bug, 由于 grpc 连接处理不当导致的内存泄露(大量连接没有关闭)。解决这个 bug 后截止为止, 这个反向代理一直正常。但不能确定是不是 bug 引起的问题,应该是很有相关性, 继续观察。


http://xy.abc.com 后启动, 主程序的代理也不生效, 这个 status 是 404,去 echo 的 issues 列表看了下,没有很直接相关的主题,还是先定位下是不是我自己程序的 bug 吧。


对于服务分发调用,确实需要考虑更好地可靠性, 但暂时还不想引用过多的第三方工具(还达不到多大的量级),只能手工去加强这块的管理了, 至少可以先通过运维脚本监控重启解决。
eudore
2020-10-23 14:49:24 +08:00
http.ResponseWriter 封装一下,如果写入状态码 404 了,不 Writer 数据了,在反向代理完后,检查下状态码是不是 404,404 就自己执行额外操作。
eudore
2020-10-23 14:54:35 +08:00
随手的伪代码,没调试。

```golang
type response struct{
http.ResponseWrite
Status int
}

func (w *response )Write(data []byte) (int, error) {
if w.Status==404 {
return 0,nil
}
return w.ResponseWrite.Write(data)
}

func (w *response )WriteHeader(code int) {
w.Status = code
w.ResponseWrite.WriteHeader(code)
}

func(addr string) echo.Handler {
proxy := httputil.NewSingleHostReverseProxy(addr)
return func(ctx echo.Context)
w := &response{
ResponseWrite: ctx.Response(),
}
proxy.ServeHTTP(w, ctx.Reuest())
if w.Status==404 {
ctx.WriteString("proxy 404 啦")
}
}
```
cupen
2022-03-24 18:29:45 +08:00
@prenwang 啊抱歉, 时隔一年多才上来看到回复.
> 实际使用过程中发现很多不稳定, 用着用着 404 了.
所以是哪些请求收到 404 了? 最好留下对应请求记录的,比如 http method 和 path 部分. 浏览器端 javascript 环境比较恶劣, 没准会出现 post get 傻傻分不清.

回到主题上, 你的反向代理, 如果后端给了响应就照实返回, 哪怕出错也会有个 5xx 之类的状态码返回.
其他情况比如后端启动慢, 一时半会访问不了, 这是后端的问题. 作为网关你只需返回 502. 这是 http 标准做法. 所有主流的反向代理都是这么干的.

p.s. 你实现的其实就是 api 网关, 挺合适, 甚至可以定制一些算法. 但我看你的例子里 http://xy.abc.com 是个外网地址? 虽然不影响逻辑. 但是通信质量会比内网差很多, 容易超时导致把账算在你网关的头上......

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/716504

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX