0

I'm using LabStack's Golang Echo Framework to build out a service.

One of the routes, needs to proxy requests and responses to and from a backend service.

But I also need CORS to work on this service as well.

So I'm using middleware.CORSWithConfig along w/ a middleware.ProxyWithConfig in my request/response stack.

I'm seeing some oddness w/ the Access-Control-Allow-Origins header where the value for that header on the response from the proxied service to my Echo server *, but once it passes through the proxy, it changes to *, * by the time it gets back into the client. Upon which I start seeing the following browser errors related to CORS violations:

VM1627:362 Access to XMLHttpRequest at 'http://localhost:6273/' from origin 'http://localhost:8002' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

Has anyone come across this? Anyone have any idea why this might be happening and maybe a way around it?

Here's some example code:

package main

func singleTargetBalancer(url *url.URL) middleware.ProxyBalancer {
    targetURL := []*middleware.ProxyTarget{
        {
            URL: url,
        },
    }
    return middleware.NewRoundRobinBalancer(targetURL)
}

func Noop(ctx echo.Context) (err error) {
    ctx.String(
        http.StatusNotImplemented,
        "No op handler should never be reached!",
    )

    return err
}

func main() {
        e := echo.New()
    e.HideBanner = true
    e.Use(
        middleware.CORSWithConfig(middlewares.CustomCorsConfig),
        middlewares.ThriftMetrics(),
    )

        // Have to use a Noop handler since we're not trying to set up a full-on proxy for the backend service.  We only want this one route to be proxied.
        e.POST(
        "/",
        handlers.Noop,
        middleware.ProxyWithConfig(middleware.ProxyConfig{
             Balancer: singleTargetBalancer("[backend service URL]"),
            })
    )
}
RavenHursT
  • 2,336
  • 1
  • 25
  • 46

1 Answers1

3

I ultimately solved this by writing a custom Echo middleware to hook into the response before Echo's proxy middleware could send the headers back to the client.

func setResponseACAOHeaderFromRequest (req http.Request, resp echo.Response) {
    resp.Header().Set(echo.HeaderAccessControlAllowOrigin, 
    req.Header.Get(echo.HeaderOrigin))
}

func ACAOHeaderOverwriteMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(ctx echo.Context) error {
        ctx.Response().Before(func() {
            setResponseACAOHeaderFromRequest(*ctx.Request(), *ctx.Response())
        })
        return next(ctx)
    }
}

Then just put this middleware in e.Use() right before your proxy middleware:

e.POST(
        "/",
        handlers.Noop,
        ACAOHeaderOverwriteMiddleware,
        middleware.ProxyWithConfig(middleware.ProxyConfig{
             Balancer: singleTargetBalancer("[backend service URL]"),
        })
)

Docs for Echo's Request::Before() hook: https://echo.labstack.com/guide/response#before-response

RavenHursT
  • 2,336
  • 1
  • 25
  • 46