I am using Zuul to make a URL appear to be part of an existing API when it is really serviced by a different microservice. So I want to make this route to use the route conventions of one service, but then match paths on the underlying microservice.
I want to route /api/v1/pathForGateway/** to /api/microservicePath/** on the micro service. An example full endpoint could be /api/v1/pathForGateway/function1, and it would map to the microservice at this full endpoint /api/microservicePath/function1.
Conceptually what I need is to strip the prefix, but then add a new prefix.
This is using Eureka Service Discovery, so I can't use uri.
zuul.routes.servicea.path=/api/v1/pathForGateway/**
zuul.routes.servicea.serviceId=microservice-a
zuul.routes.servicea.stripPrefix=true
# Is there a configuration like this?
zuul.routes.servicea.appendPrefix=/api/microservicePath/
There's not really a way to do this with configuration. You'd need to write a custom filter.
That sounds reasonable. So I'd like to write a custom filter that builds on the existing routing filter. But, would just append the path. How can I write a custom routing filter that builds on the underlying filter?
I'd write a 'pre' filter that runs after the PredecorationFilter and manipulates the 'requestUri' https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java#L117
Which gets used here https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java#L89-L104
That was a great suggestion @spencergibb.
For future reference, this setup works well.
@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;
}
}
application.properties:
zuul.routes.servicea.path=/api/v1/pathForGateway/**
zuul.routes.servicea.serviceId=microservice-a
zuul.routes.servicea.stripPrefix=true
shouldFilter() should probably only return true if the path matches. Good job, BTW.
Hi. I need to do something like @dlvenable but replace the whole path instead of part of the path. My intent is to be able to take an endpoint, such as /hello1, and route a certain percentage of the traffic to /hello2.
For example, let's say in Zuul, I mapped the endpoint, /hello, to go to /hello1. My application.yml looks this:
zuul:
routes:
hellohello:
path: /hello/**
url: http://localhost:8080/hello1
Then I have a prefilter that has a run method like so:
public static final String REQUEST_URI_KEY = "requestURI";
@Override
public Object run() {
final RequestContext context = RequestContext.getCurrentContext();
String modifiedPath = "/hello2";
context.put(REQUEST_URI_KEY, modifiedPath);
return null;
}
When I run a curl command: curl localhost:8080/hello
{"timestamp":1509505655531,"status":404,"error":"Not Found","message":"No message available","path":"/hello1/hello2"}
It seems that "/hello2" is being appended to the "/hello1".
How can I have it forward to "/hello2"?
Thanks in advance.
You could also do this by using a forward, e.g.
service:
path: /some/path
url: forward:/your/changed/path
other-service:
path: /your/changed/path/**
serviceId: downstream-service
i have tried as blow configuration but not working for me.
zuul:
routes:
CSRFToken:
path: /**/CSRFTokentest
url: forward:/api/public/CSRFToken
MyCSRFToken:
path: /**/CSRFToken
url: http://<ipaddress>:8080
stripPrefix: false
ribbon:
eureka:
enabled: false
Most helpful comment
That was a great suggestion @spencergibb.
For future reference, this setup works well.
application.properties: