Gin: Reverse Proxy issues

Created on 25 Dec 2018  Â·  9Comments  Â·  Source: gin-gonic/gin

  • With issues:

    router

    apiv1.GET("/videos/:vid-id", ProxyVideoHandler)
    apiv1.POST("/upload/:vid-id", ProxyVideoHandler)

handler

func ProxyVideoHandler(c *gin.Context) {
    u, err := url.Parse(setting.AppSetting.ProxyURL)
    if err != nil {
        logging.Info(err)
        c.String(http.StatusInternalServerError, "internal server error")
        return
    }
    proxy := httputil.NewSingleHostReverseProxy(u)
    c.Request.Host = u.Host
    proxy.ServeHTTP(c.Writer, c.Request)
}
  • isson is
[GIN] 2018/12/25 - 12:48:58 | 200 |     15.5698ms |       127.0.0.1 | GET      /static/js/jquery-3.3.1.min.js
[GIN] 2018/12/25 - 12:48:58 | 200 |    20.02673ms |       127.0.0.1 | POST     /api/v1/api
[GIN] 2018/12/25 - 12:48:58 | 200 |   40.379618ms |       127.0.0.1 | POST     /api/v1/api
[GIN] 2018/12/25 - 12:48:58 | 200 |     582.992µs |       127.0.0.1 | GET      /static/img/preloader.jpg


2018/12/25 12:48:58 [Recovery] 2018/12/25 - 12:48:58 panic recovered:
GET /api/v1/videos/973fd869-cba7-4dce-a1c7-8ce2626a1046 HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
Accept-Encoding: identity;q=1, *;q=0
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Cookie: session=8a9e75ba-ed79-4c5a-8724-ec3a8e796580; username=hhhhh
Range: bytes=0-
Referer: http://127.0.0.1:8080/api/v1/userhome
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36


net/http: abort Handler
/usr/local/opt/go/libexec/src/runtime/panic.go:513 (0x102bcd8)
    gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
/usr/local/opt/go/libexec/src/net/http/httputil/reverseproxy.go:284 (0x155a317)
    (*ReverseProxy).ServeHTTP: panic(http.ErrAbortHandler)
/Users/hx/goprojects/src/github.com/haibeichina/gin_video_server/web/routers/api/v1/webhandles.go:174 (0x16030ff)
    ReverseProxy.func1: proxy.ServeHTTP(c.Writer, c.Request)
/Users/hx/GoLang/src/github.com/gin-gonic/gin/context.go:108 (0x155b802)
    (*Context).Next: c.handlers[c.index](c)
/Users/hx/GoLang/src/github.com/gin-gonic/gin/recovery.go:52 (0x156cd99)
    RecoveryWithWriter.func1: c.Next()
/Users/hx/GoLang/src/github.com/gin-gonic/gin/context.go:108 (0x155b802)
    (*Context).Next: c.handlers[c.index](c)
/Users/hx/GoLang/src/github.com/gin-gonic/gin/logger.go:84 (0x156bf21)
    LoggerWithWriter.func1: c.Next()
/Users/hx/GoLang/src/github.com/gin-gonic/gin/context.go:108 (0x155b802)
    (*Context).Next: c.handlers[c.index](c)
/Users/hx/GoLang/src/github.com/gin-gonic/gin/gin.go:362 (0x156409a)
    (*Engine).handleHTTPRequest: c.Next()
/Users/hx/GoLang/src/github.com/gin-gonic/gin/gin.go:328 (0x15638f1)
    (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/opt/go/libexec/src/net/http/server.go:2741 (0x128fdea)
    serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/opt/go/libexec/src/net/http/server.go:1847 (0x128c045)
    (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/opt/go/libexec/src/runtime/asm_amd64.s:1333 (0x1059840)
    goexit: BYTE    $0x90   // NOP

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 206 with 500[GIN] 2018/12/25 - 12:48:58 | 500 |   16.338862ms |       127.0.0.1 | GET      /api/v1/videos/973fd869-cba7-4dce-a1c7-8ce2626a1046
[GIN] 2018/12/25 - 12:48:58 | 206 |    2.352201ms |       127.0.0.1 | GET      /api/v1/videos/973fd869-cba7-4dce-a1c7-8ce2626a1046
[GIN] 2018/12/25 - 12:48:58 | 200 |    74.00254ms |       127.0.0.1 | POST     /api/v1/api
bug

All 9 comments

server a:

➜  gotest cat g.go
package main

import (
    "github.com/gin-gonic/gin"
)

func FooBar(c * gin.Context) {
    c.JSON(200, gin.H{"msg": "Hello world"})
}

func main() {
    r := gin.Default()
    r.GET("/test", FooBar)
    r.Run()
}

server b:

➜  ~ cat x.go
package main

import (
    "net/http/httputil"
    "net/url"
    "github.com/gin-gonic/gin"
)

func hd(c *gin.Context) {
    remote, err := url.Parse("http://127.0.0.1:8080/test")
    if err != nil {
        panic(err)
    }
    proxy := httputil.NewSingleHostReverseProxy(remote)
    c.Request.Host = remote.Host
    proxy.ServeHTTP(c.Writer, c.Request)
}

func startServer() {
    r := gin.Default()
    r.GET("/", hd)
    r.Run(":8888")
}

func main() {
    startServer()
}

first, I run server a and then start server b.
and use the follow command:

➜  ~ curl -v http://localhost:8888
* Rebuilt URL to: http://localhost:8888/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8888 (#0)
> GET / HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Content-Length: 40
< Content-Type: text/html; charset=utf-8
< Date: Sun, 24 Feb 2019 16:02:21 GMT
< Location: /test
<
<a href="/test">Moved Permanently</a>.

* Connection #0 to host localhost left intact

server a log:

[GIN-debug] redirecting request 301: /test/ --> /test

server b log:

[GIN] 2019/02/25 - 00:02:21 | 301 |     653.048µs |             ::1 | GET      /

Seems proxy server has context path, and it append the new request uri after it?
a server actually requests 'http://127.0.0.1:8080/test' +'/', and redirect happen.
success when change '/test' to '/test/'
func main() {
r := gin.Default()
r.GET("/test/", FooBar)
r.Run()
}

the same with me,is there some body can fix it?

emmmmm I meet same problem.

I have got the same problem.

I don't think this is the original issue, but this work to solve

func hd(c *gin.Context) {
    remote, err := url.Parse("http://127.0.0.1:8080/test")
    if err != nil {
        panic(err)
    }
    director := func(req *http.Request) {
        req.URL.Scheme = "http"
        req.URL.Host = remote.Host
        req.URL.Path = remote.Path
    }

    proxy := &httputil.ReverseProxy{Director: director}
    proxy.ServeHTTP(c.Writer, c.Request)
}

func startServer() {
    r := gin.Default()
    r.GET("/", hd)
    r.Run(":8888")
}

I don't think this is the original issue, but this work to solve

func hd(c *gin.Context) {
  remote, err := url.Parse("http://127.0.0.1:8080/test")
  if err != nil {
      panic(err)
  }
  director := func(req *http.Request) {
      req.URL.Scheme = "http"
      req.URL.Host = remote.Host
      req.URL.Path = remote.Path
  }

  proxy := &httputil.ReverseProxy{Director: director}
  proxy.ServeHTTP(c.Writer, c.Request)
}

func startServer() {
  r := gin.Default()
  r.GET("/", hd)
  r.Run(":8888")
}

not work for me

Hi,

I just made a reverse proxy using gin and it works well. Here is the code I used :

package main

import (
    "fmt"
    "net/http"
    "net/http/httputil"
    "net/url"

    "github.com/gin-gonic/gin"
)

func proxy(c *gin.Context) {
    remote, err := url.Parse("http://myremotedomain.com")
    if err != nil {
        panic(err)
    }

    proxy := httputil.NewSingleHostReverseProxy(remote)
    proxy.Director = func(req *http.Request) {
        req.Header = c.Request.Header
        req.Host = remote.Host
        req.URL.Scheme = remote.Scheme
        req.URL.Host = remote.Host
        req.URL.Path = c.Param("proxyPath")
    }

    proxy.ServeHTTP(c.Writer, c.Request)
}

func main() {

    r := gin.Default()

    r.Any("/*proxyPath", proxy)

    r.Run(":8080")
}

https://gist.github.com/seblegall/2a2697fc56417b24a7ec49eb4a8d7b1b

I'm seeing a similar issue:

2020/12/18 14:09:59 [Recovery] 2020/12/18 - 14:09:59 panic recovered:
net/http: abort Handler
net/http/httputil/reverseproxy.go:338 (0x43b945c)
myhttpserver.go:134 (0x4f4e05c)

Seems like http.ErrAbortHandler should be ignored like in https://github.com/gorilla/handlers/pull/159/files

Was this page helpful?
0 / 5 - 0 ratings