- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我正在使用 Gin Gonic创建反向代理端点的框架,目标端点使用 grpc Gateway 提供服务使用下面给出的代码。这类似于为 Gin 建议的反向代理方法 here和 here
ep1 := v1.Group("/ep1")
{
ep1.GET("/ep2", reverseProxy("http://localhost:50000"))
}
func reverseProxy(target string) gin.HandlerFunc {
url, err := url.Parse(target)
if err != nil {
log.Println("Reverse Proxy target url could not be parsed:", err)
return nil
}
proxy := httputil.NewSingleHostReverseProxy(url)
return func(c *gin.Context) {
proxy.ServeHTTP(c.Writer, c.Request)
}
}
但是,当实际向此 gin 端点 (/ep1/ep2) 发送请求时,会出现 go panic:
interface conversion: *http.timeoutWriter is not http.CloseNotifier: missing method CloseNotify
/usr/local/Cellar/go/1.8/libexec/src/runtime/panic.go:489 (0x10288df)
gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
/usr/local/Cellar/go/1.8/libexec/src/runtime/iface.go:131 (0x100c3af)
additab: panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname})
/usr/local/Cellar/go/1.8/libexec/src/runtime/iface.go:79 (0x100bc34)
getitab: additab(m, true, canfail)
/usr/local/Cellar/go/1.8/libexec/src/runtime/iface.go:256 (0x100cbb8)
assertI2I: r.tab = getitab(inter, tab._type, false)
/path/to/vendor/github.com/gin-gonic/gin/response_writer.go:110 (0x14de6f3)
(*responseWriter).CloseNotify: return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
/usr/local/Cellar/go/1.8/libexec/src/net/http/httputil/reverseproxy.go:142 (0x14d4d12)
(*ReverseProxy).ServeHTTP: notifyChan := cn.CloseNotify()
/path/to/main.go:379 (0x16d2ead)
reverseProxy.func1: proxy.ServeHTTP(c.Writer, c.Request)
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/locale.go:12 (0x15737d9)
getLocaleMiddleware.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/session_cookie.go:27 (0x1574e7c)
getSessionCookieMiddleware.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/affiliate_api.go:27 (0x15729a1)
getAffiliateAPIMiddleware.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/metrics.go:17 (0x157465b)
getMetricsMiddleware.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/input_validations.go:75 (0x1572dcb)
getInputValidationMiddleware.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/logger.go:68 (0x1573aea)
LoggerWithWriter.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/middlewares/request_tracer.go:13 (0x1574d6c)
getTracerContext.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/vendor/github.com/gin-gonic/gin/recovery.go:45 (0x14e4b6a)
RecoveryWithWriter.func1: c.Next()
/path/to/vendor/github.com/gin-gonic/gin/context.go:97 (0x14d657a)
(*Context).Next: c.handlers[c.index](c)
/path/to/vendor/github.com/gin-gonic/gin/gin.go:284 (0x14dc710)
(*Engine).handleHTTPRequest: context.Next()
/path/to/vendor/github.com/gin-gonic/gin/gin.go:265 (0x14dc02b)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/Cellar/go/1.8/libexec/src/net/http/server.go:2967 (0x140fa53)
(*timeoutHandler).ServeHTTP.func1: h.handler.ServeHTTP(tw, r)
/usr/local/Cellar/go/1.8/libexec/src/runtime/asm_amd64.s:2197 (0x1054851)
关于为什么会发生这种情况或代码中有什么问题有什么想法吗?
最佳答案
我们发现这个问题是因为代码库没有直接使用 gin-gonic
的 Run()
方法。相反,它在启动 http 服务器时使用超时,如下所示(在此处使用部分相关代码):
type H struct {
sync.Mutex
Engine *gin.Engine
listener net.Listener
running bool
}
.
.
.
var h H
s := &http.Server{
Addr: address,
Handler: http.TimeoutHandler(h.Engine, time.Duration(100000)*time.Millisecond, ""),
ReadTimeout: time.Duration(100000) * time.Millisecond,
WriteTimeout: time.Duration(100000) * time.Millisecond,
}
h.listener, err := net.Listen("tcp", s.Addr)
if err != nil {
return err
}
h.running = true
s.Serve(h.listener)
但是,http.TimeoutHandler
并未实现 http://grokbase.com/t/gg/golang-dev/13796p5h1n/net-http-timeouthandler-vs-closenotify 中提到的 http.CloseNotifer
接口(interface)这导致了 panic
错误消息 interface conversion: *http.timeoutWriter is not http.CloseNotifier: missing method CloseNotify
因此,作为此问题的解决方法,将服务器处理程序修改为直接作为 gin 引擎,同时使用 http 的
。ReadTimeout
和 WriteTimeout
值。用于超时目的的服务器
修改后的代码不再 panic ,并导致成功的反向代理:
type H struct {
sync.Mutex
Engine *gin.Engine
listener net.Listener
running bool
}
.
.
.
var h H
s := &http.Server{
Addr: address,
Handler: h.Engine,
ReadTimeout: time.Duration(100000) * time.Millisecond,
WriteTimeout: time.Duration(100000) * time.Millisecond,
}
h.listener, err := net.Listen("tcp", s.Addr)
if err != nil {
return err
}
h.running = true
s.Serve(h.listener)
注意这里只有&http.Server
的Handler
需要修改。此外,不需要修改问题中的原始反向代理代码。
关于Golang gin-gonic 反向代理导致 panic "interface conversion: *http.timeoutWriter is not http.CloseNotifier: missing method CloseNotify",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43670872/
我有一个应用程序需要限制为少数 IP。如果请求 IP 不是来自允许列表,我可以编写一个中间件并返回,但是我希望这个过程尽可能高效。 IE。我想尽早断开连接。我可以断开连接的最早阶段是什么,最好是使用
我正在尝试为基于 GIN 框架的基于 go 的 Web 应用程序添加验证。在网页上,我正在选择一个文件并提交,服务器正在处理它。在服务器端,我尝试添加验证以检查文件是否已提供。如果没有,则重定向回原始
我在制作 Web 应用程序时使用 gin-gonic 登录时遇到了一些麻烦。我目前正在为此使用 API。我可以在那里提出进入请求。这是我的代码片段: 主要 // LOGIN router.GET("/
我的 webapp 有滥用的手段,用户可以访问他们不应该访问的东西,例如 127.0.0.1/users/1 & 127.0.0.1/users/2 & 127.0.0.1/users/3 等等,其中
所以我目前正在使用 gin-gonic 包在 go 中构建一个 restful api。我希望将代码部署到谷歌云平台计算引擎 VM。当我在我的本地机器上运行代码时,它使用本地主机工作,但是当在指定外部
我正在使用 Gin-Gonic 并正在创建自定义中间件。请参阅:https://github.com/gin-gonic/gin#custom-middleware 文档中的中间件是不是有这样写的原因
我们有一个基于 gin-gonic 的用 go 编写的 API 服务器。我们注意到一些奇怪的事情使我们相信它正在串行处理请求,而不是预期的并行操作。考虑这个日志文件: [GIN] 2016/04/05
我希望将我的 routes.go 分成多个文件,以便每个组都在自己的包中。有人可以指出一些代码示例,其中有人使用 Gin 完成了此操作吗? 即 package auth ... auth = rout
我是 gin-gonic 框架的新手,我一直在尝试从我在 html 获取请求中添加的输入中读取值,但我无法读取我编写的值。 当我提交请求时,浏览器发送这个 url: http://localhost:
我很新,想尝试学习,我正在设置一个带有 gin-gonic 服务器的应用程序。我设法让它与主包中的所有内容一起工作,我想更好地组织它与包中所有最相关的(我管理的)并按文件拆分每个组 CRUD。 所以在
我正在尝试使用 Gin framework for Go 创建一个小型 API ,并且在尝试将其拆分为多个文件时出现错误。由于我是 Go 的绝对初学者,我可能犯了一些愚蠢的大错误,所以请多多包涵 :)
go版本:go版本go1.11.2 linux/amd64 gin 版本(或提交引用):提交 #5acf660 操作系统:Ubuntu 16.04LTS 描述 我正在尝试使用示例应用程序为 gin 服
要进行模拟负载测试,请使用以下代码在 Go gin-gonic 框架中设置一个非常基本的 REST api,并在大约 1000 多个请求出现错误后 http: Accept error: accept
如何在 Gin Gonic 中将一些路由的代理 Web 请求反向到另一个后端网页golang框架 有没有办法在Handle函数中直接转发如下图? 路由器 := gin.New() router.Han
我正在学习 Go 并将 gin-gonic 用于网络应用程序。我正在尝试从模板错误中优雅地恢复,但一直无法弄清楚如何缓冲输出或正确重定向以实现此目的。 使用这段代码: package main imp
多年来,我一直在使用 Node/Python 进行开发,在假期期间,我一直在努力扩展我对 Go 的了解。我有一个宠物项目,我一直在努力学习它。 因为我一直在阅读 gin-gonic documenta
对于以下 golang 程序,如果我执行 fmt.Print 变量显示值,我无法使用 gin-gonic 库获取 json 输出,但是当我转换为 c.JSON(库存)时它显示空数组,我的代码有什么问题
我的项目分为三个主要部分: Controller 、服务和模型。当通过 URI 查询路由时,将调用 Controller ,然后调用服务与模型交互,然后模型通过 gorm 与数据库交互。 我正在尝试为
我正在使用 gin-gonic 包创建一个 API,但我被文件上传处理程序困住了。这是我的代码: func postPicture(c *gin.Context) { id, ok := c.
是否有使用 Gin Gonic 列出/遍历所有帖子值的简单方法? (去) 我试过: c.Request.ParseForm() for key, value := range c.Request.Po
我是一名优秀的程序员,十分优秀!