I'm trying to forward all requests to my API to a single endpoint based upon some condition.
The Gateway app runs on port 8080
I've created the following filter:
public class OutagePeriodFilter extends ZuulFilter {
@Override
public String filterType() {
return "route";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return isOutagePeriod();
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
// if outage - redirect everyone to http://localhost:8082/outage
try {
String url = UriComponentsBuilder.fromHttpUrl("http://localhost:8082").path("/outage").build()
.toUriString();
ctx.setRouteHost(new URL(url));
} catch(MalformedURLException mue) {
log.error("Cannot forward to outage period website");
}
return null;
}
private boolean isOutagePeriod() {
// returns true if outage
}
}
However after making a request to http://localhost:8080/alerts/public my API logs show:
2017-03-03 16:11:30.735 EST 0037 DEBUG o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/outage/alerts/public'; against '/beans/'
For some reason it appends the original PATH to the redirect PATH resulting in a request to /outage/alerts/public which doesn't exist. I want to make a request to just /outage.
Putting a breakpoint in my filter just as the ctx.setRouteHost() is called shows that correct URL (http://10.50.36.43:8082/outage/).
My application.properties:
zuul.routes.api.path=/api/**
zuul.routes.api.url=http://localhost:8082/
It should be a "pre" filter and it should run before PreDecorationFilter. I think setting the requestURI field in RequestContext will help. Otherwise spring cloud appends the original path.
The request still makes it to the original destination.
New code:
@Override
public int filterOrder() {
return 4;
}
@Override
public String filterType() {
return "pre";
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
try {
String url = UriComponentsBuilder.fromHttpUrl("http://localhost:8082").path("/outage").build()
.toUriString();
ctx.setRouteHost(new URL(url));
ctx.set("requestURI", url);
} catch(MalformedURLException mue) {
log.error("Cannot forward to outage period endpoint");
}
return null;
}
Breakpoint confirming it's run before PreDecorationFilter.

What happens in ProxyRequestHelper.buildZuulRequestURI()?
My guess is that predecorationfilter is still running later. Maybe it needs to happen after predecoration.
Changing the filter to run after PreDecorationFilter and setting ctx.set("requestURI", url) worked.
I removed ctx.setRouteHost(new URL(url)); as it doesn't appear to be required.
Final code:
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String url = UriComponentsBuilder.fromHttpUrl("http://localhost:8082").path("/outage").build()
.toUriString();
ctx.set("requestURI", url);
return null;
}
Strange because I had the same need and I succeeded thanks to this post but with ctx.setRouteHost
This solution is not working for me, please help me:
My pre filter class code:
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
System.out.println(
"Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());
String body = readRequestBody(request);
String url1 = UriComponentsBuilder.fromHttpUrl("http://localhost:8082").path("/wf-service").path("/_create")
.build().toUriString();
try {
ctx.setRouteHost(new URL(url1));
ctx.set("requestURI", url1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
requestParser.setReqAsMap(body);
if (requestParser.hasRequestInfo()) {
System.out.println("has req info");
}
return null;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public String filterType() {
return "pre";
}
application.properties
zuul.routes.wf.path=/wf-service/**
zuul.routes.wf.stripPrefix=false
zuul.routes.wf.url=http://localhost:8082/
The previous answers seems to indicate that the filter needs to be triggered after the PreDecoration.
Have you try to change the filterOrder to:
@Override
public int filterOrder() {
return 6;
}
i change this also now it appending complete url twise
{
"timestamp": 1510720356916,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/wf-service/_createhttp:/localhost:8082/wf-service/_create"
}
Worked for me too by changing the FilterOrder to 6. I was trying to prevent routing from happening.And so removed "routeHost" from the RequestContext in the Pre Filter. Thanks @spencergibb
Hi all, trying to achieve the same thing,
but the ctx.setRouteHost() actually sends a 302 (Redirect) to my browser, and therefore it is not proxied by Zuul.
Any suggestion would be highly appreciated.
This solution is not working for me, please help me:
My pre filter class code:@override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();System.out.println( "Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString()); String body = readRequestBody(request); String url1 = UriComponentsBuilder.fromHttpUrl("http://localhost:8082").path("/wf-service").path("/_create") .build().toUriString(); try { ctx.setRouteHost(new URL(url1)); ctx.set("requestURI", url1); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } requestParser.setReqAsMap(body); if (requestParser.hasRequestInfo()) { System.out.println("has req info"); } return null; } @Override public boolean shouldFilter() { return true; } @Override public int filterOrder() { return 1; } @Override public String filterType() { return "pre"; }application.properties
zuul.routes.wf.path=/wf-service/**
zuul.routes.wf.stripPrefix=false
zuul.routes.wf.url=http://localhost:8082/
GhanshyamRawat -> is resolved now?
I am also getting same issue.
Changing the filter to run after
PreDecorationFilterand settingctx.set("requestURI", url)worked.I removed
ctx.setRouteHost(new URL(url));as it doesn't appear to be required.Final code:
@Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String url = UriComponentsBuilder.fromHttpUrl("http://localhost:8082").path("/outage").build() .toUriString(); ctx.set("requestURI", url); return null; }
I did the same but it did not work
Here is my code :
bootstrao.yml:
zuul.routes.cp.path: /navxcp/**
zuul.routes.cp.service-id: navxcp
zuul.routes.web.path: /navx/**
zuul.routes.web.service-id: navxweb
Prefilter:
requestUri = requestUri.replace("navx", "navxcp");
ctx.set(FilterConstants.REQUEST_URI_KEY,requestUri );
log.info("--- request-uri has been modified -> {}",requestUri);
actually I am hitting http://host:port/gateway/navx/getData
Here getData endpoint is available on navxcp microservice
So I am trying to change the requestURIin pre-filter so that it should be routed to navxcp
I found one way to do this.
here is my zuul config:
zuul:
routes:
sevice-demo-b:
path: /b/**
url: http://localhost:5010
sevice-demo-a: /a/**
The filter should be pre and before PRE_DECORATION_FILTER
the requestUri attribute can change you uri after preDecorationFilter choose the route, but if you want to change the route, you need use this code request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, url);
here is the code
public class ChangeUriFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
final String uri = request.getRequestURI();
return uri.contains("/helloA");
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
final HttpServletRequest request = ctx.getRequest();
String uri = "/b/helloB"
// change uri
request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, url);
return null;
}
}
when you request 'http://host:port/a/helloA', it will forward to http://host:port/b/helloB
馃槅
Most helpful comment
I found one way to do this.
here is my zuul config:
The filter should be
preand beforePRE_DECORATION_FILTERthe
requestUriattribute can change you uri after preDecorationFilter choose the route, but if you want to change the route, you need use this coderequest.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, url);here is the code
when you request 'http://host:port/a/helloA', it will forward to
http://host:port/b/helloB馃槅