Summary: ZUUL doesnt pick the right destination url for the input path since it doesnt do strict matching of the input path.
Below is my zuul routes :
zuul:
routes:
auth:
path: /v1/txn/**
url: http://localhost:8900/v1/cardhostauth
cardproduct:
path: /v1/customer/card/product/**
url: http://localhost:8800/v1/customer/card/product
cardcomposite:
path: /v1/customer/**
url: http://localhost:8400/v1/composite
For input path:"/v1/customer/card/product/" , It is expected to choose -http://localhost:8800/v1/customer/card/product but it chooses http://localhost:8400/v1/composite. My expectation was that the path pattern match happens in the order specified and is stricter but seems it doesnt work that way.
Can you let me know how ZUUL works when you have multiple routes defined for similar input path ?
Thx
P.S - I can see this issue when i run via Docker in AWS but the issue doesn't come up when i run from eclipse. Has the order of zuul route depend on the spring zuul jar (spring-cloud-starter-netflix-zuul - 2.0.0.RELEASE vs 2.0.1.RELEASE)
For picking the route based on best match, i found this thread helpful (thanks to @maximdim). Basically you can write your own custom router to pick best matching route.
https://github.com/spring-cloud/spring-cloud-netflix/issues/2408
Hope this helps. (And as it's my first answer, my apologies if it is not a good one.)
An example taken from github thread goes as follows:
public class CustomRouteLocator extends SimpleRouteLocator {
public CustomRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
}
@Override
protected ZuulRoute getZuulRoute(String adjustedPath) {
// Spring's AbstractUrlHandlerMapping already found best matching path for us
// and stored it into request attribute. See AbstractUrlHandlerMapping.exposePathWithinMapping
RequestContext ctx = RequestContext.getCurrentContext();
String bestMatchingPattern = (String)ctx.getRequest().getAttribute(HandlerMapping.class.getName() + ".bestMatchingPattern");
if (bestMatchingPattern == null) {
return super.getZuulRoute(adjustedPath);
}
if (!matchesIgnoredPatterns(adjustedPath)) {
return locateRoutes().get(bestMatchingPattern);
}
return null;
}
}
@maximdim:
Instead of duplicating logic to find 'best match' I simply getting it from request attribute, where Spring's HandlerMapping saves it. A bit hacky perhaps, but seems to work for me.