mirror of
https://github.com/labstack/echo.git
synced 2025-01-12 01:22:21 +02:00
Rewrite rules for proxy middleware
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
62f95acdd7
commit
9ae7047759
@ -1,6 +1,12 @@
|
||||
package middleware
|
||||
|
||||
import "github.com/labstack/echo"
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
type (
|
||||
// Skipper defines a function to skip middleware. Returning true skips processing
|
||||
@ -8,6 +14,21 @@ type (
|
||||
Skipper func(c echo.Context) bool
|
||||
)
|
||||
|
||||
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
||||
groups := pattern.FindAllStringSubmatch(input, -1)
|
||||
if groups == nil {
|
||||
return nil
|
||||
}
|
||||
values := groups[0][1:]
|
||||
replace := make([]string, 2*len(values))
|
||||
for i, v := range values {
|
||||
j := 2 * i
|
||||
replace[j] = "$" + strconv.Itoa(i+1)
|
||||
replace[j+1] = v
|
||||
}
|
||||
return strings.NewReplacer(replace...)
|
||||
}
|
||||
|
||||
// DefaultSkipper returns false which processes the middleware.
|
||||
func DefaultSkipper(echo.Context) bool {
|
||||
return false
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -26,6 +28,17 @@ type (
|
||||
// Balancer defines a load balancing technique.
|
||||
// Required.
|
||||
Balancer ProxyBalancer
|
||||
|
||||
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Examples:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
Rewrite map[string]string
|
||||
|
||||
rewriteRegex map[*regexp.Regexp]string
|
||||
}
|
||||
|
||||
// ProxyTarget defines the upstream target.
|
||||
@ -187,6 +200,13 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||
if config.Balancer == nil {
|
||||
panic("echo: proxy middleware requires balancer")
|
||||
}
|
||||
config.rewriteRegex = map[*regexp.Regexp]string{}
|
||||
|
||||
// Initialize
|
||||
for k, v := range config.Rewrite {
|
||||
k = strings.Replace(k, "*", "(\\S*)", -1)
|
||||
config.rewriteRegex[regexp.MustCompile(k)] = v
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) (err error) {
|
||||
@ -198,6 +218,14 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||
res := c.Response()
|
||||
tgt := config.Balancer.Next()
|
||||
|
||||
// Rewrite
|
||||
for k, v := range config.rewriteRegex {
|
||||
replacer := captureTokens(k, req.URL.Path)
|
||||
if replacer != nil {
|
||||
req.URL.Path = replacer.Replace(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Fix header
|
||||
if req.Header.Get(echo.HeaderXRealIP) == "" {
|
||||
req.Header.Set(echo.HeaderXRealIP, c.RealIP())
|
||||
|
@ -84,4 +84,28 @@ func TestProxy(t *testing.T) {
|
||||
e.ServeHTTP(rec, req)
|
||||
body = rec.Body.String()
|
||||
assert.Equal(t, "target 2", body)
|
||||
|
||||
// Rewrite
|
||||
e = echo.New()
|
||||
e.Pre(ProxyWithConfig(ProxyConfig{
|
||||
Balancer: rrb,
|
||||
Rewrite: map[string]string{
|
||||
"/old": "/new",
|
||||
"/api/*": "/$1",
|
||||
"/js/*": "/public/javascripts/$1",
|
||||
"/users/*/orders/*": "/user/$1/order/$2",
|
||||
},
|
||||
}))
|
||||
req.URL.Path = "/api/users"
|
||||
e.ServeHTTP(rec, req)
|
||||
assert.Equal(t, "/users", req.URL.Path)
|
||||
req.URL.Path = "/js/main.js"
|
||||
e.ServeHTTP(rec, req)
|
||||
assert.Equal(t, "/public/javascripts/main.js", req.URL.Path)
|
||||
req.URL.Path = "/old"
|
||||
e.ServeHTTP(rec, req)
|
||||
assert.Equal(t, "/new", req.URL.Path)
|
||||
req.URL.Path = "/users/jack/orders/1"
|
||||
e.ServeHTTP(rec, req)
|
||||
assert.Equal(t, "/user/jack/order/1", req.URL.Path)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user