Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do URL Rewrite in Zuul Proxy?

One of the request that comes to my Zuul Filter is of URI /hello/World which i want to redirect to /myapp/test. This /myapp/test is a service that is registered in Eureka.

zuul:
  routes:
     xyz:
         path: /hello/World
         url: http://localhost:1234/myapp/test
         stripPrefix: true

When i try the above configuration, the incoming URI is suffixed to the configured URL like http://localhost:1234/myapp/test/World . Few of the links which i came across seem to be stating that URL Rewrite feature is not yet available in Zuul.

Is there any other way this can be done at the Zuul Layer ?

Note: At this point of time, i cannot do this reverse proxying in the Webserver or any other layer since, my Zuul filter is the one that is receiving the request directly.

like image 377
yathirigan Avatar asked Sep 15 '25 17:09

yathirigan


2 Answers

Using @Adelin solution, with little improvements

Use 'url' property as path to prepend for customizing the Url rewriting (I have disabled Eureka in my example) :

ribbon.eureka.enabled=false

zuul.routes.route1.path=/route1/**
zuul.routes.route1.serviceId=service1
zuul.routes.route1.url=/path/to/prepend

service1.ribbon.listOfServers=http://server1

Then implement the following filter :

/**
 * Fixing missing URL rewriting when using ribbon
 */
@Component
public class CustomPathZuulFilter extends ZuulFilter {

    @Autowired
    private ZuulProperties zuulProperties;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1;
    }

    @Override
    public boolean shouldFilter() {
        // override PreDecorationFilter only if executed previously successfully
        return RequestContext.getCurrentContext().getFilterExecutionSummary().toString()
                .contains("PreDecorationFilter[SUCCESS]");
    }

    @Override
    public Object run() {
        final RequestContext context = RequestContext.getCurrentContext();
        if (context.get(FilterConstants.SERVICE_ID_KEY) == null || context.getRouteHost() != null) {
            // not a Ribbon route
            return null;
        }

        // get current ZuulRoute
        final String proxy = (String) context.get(FilterConstants.PROXY_KEY);
        final ZuulRoute zuulRoute = this.zuulProperties.getRoutes().get(proxy);

        // patch URL by prefixing it with zuulRoute.url
        final Object originalRequestPath = context.get(FilterConstants.REQUEST_URI_KEY);
        final String modifiedRequestPath = zuulRoute.getUrl() + originalRequestPath;
        context.put(FilterConstants.REQUEST_URI_KEY, modifiedRequestPath);

        // patch serviceId because :
        // - has been set to route.location in PreDecorationFilter
        // - route.location has been set to zuulRoute.location in SimpleRouteLocator
        // - zuulRoute.location return zuulRoute.url if set
        context.set(FilterConstants.SERVICE_ID_KEY, zuulRoute.getServiceId());

        return null;
    }
}

Now calls to /route1 will be proxified to http://server1/path/to/prepend

This solution is also compatible with co-existing routes not using Ribbon.

Example of a co-existing route not using Ribbon :

zuul.routes.route2.path=/route2/**
zuul.routes.route2.url=http://server2/some/path

Calls to /route2 will be proxified to http://server2/some/path by SimpleHostRoutingFilter (if not disabled)

like image 89
cerdoc Avatar answered Sep 18 '25 08:09

cerdoc


Here is a posted solution in the link by @Vikash

@Component
public class CustomPathZuulFilter extends ZuulFilter
{
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return PreDecorationFilter.FILTER_ORDER + 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        Object originalRequestPath = context.get(REQUEST_URI_KEY);
        String modifiedRequestPath = "/api/microservicePath" + originalRequestPath;
        context.put(REQUEST_URI_KEY, modifiedRequestPath);

        return null;
    }
}
like image 42
Adelin Avatar answered Sep 18 '25 08:09

Adelin