Netflix OSS project Zuul serves as a gateway to backend services and provides support for adding in edge features like security, routing. In the Zuul world specific edge features are provided by components called the Zuul Filter and writing such a filter for a Spring Cloud based project is very simple. A good reference to adding a filter is here. Here I wanted to demonstrate two small features - deciding whether a filter should act on a request and secondly to add a header before forwarding the request.
Writing a Zuul Filter is very easy for Spring Cloud, all we need to do is to add a Spring bean which implements the ZuulFilter, so for this example it would look something like this:
Some high level details of this implementation, this has been marked as a "Filter type" of "pre" which means that this filter would be called before the request is dispatched to the backend service, filterOrder determines when this specific filter is called in the chain of filters, should Filter determines if this filter is invoked at all for this request and run contains the logic for the filter.
So to my first consideration, whether this filter should act on the flow at all - this can be done on a request by request basis, my logic is very simple - if the request uri starts with /samplesvc then this filter should act on the request.
and the second consideration on modifying the request headers to the backend service:
A backing service getting such a request can look for the header and act accordingly, say in this specific case looking at the "payload.trace" header and deciding to log the incoming message:
Writing a Zuul Filter
Writing a Zuul Filter is very easy for Spring Cloud, all we need to do is to add a Spring bean which implements the ZuulFilter, so for this example it would look something like this:
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Service;
@Service
public class PayloadTraceFilter extends ZuulFilter {
private static final String HEADER="payload.trace";
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 999;
}
@Override
public boolean shouldFilter() {
....
}
@Override
public Object run() {
....
}
}
Some high level details of this implementation, this has been marked as a "Filter type" of "pre" which means that this filter would be called before the request is dispatched to the backend service, filterOrder determines when this specific filter is called in the chain of filters, should Filter determines if this filter is invoked at all for this request and run contains the logic for the filter.
So to my first consideration, whether this filter should act on the flow at all - this can be done on a request by request basis, my logic is very simple - if the request uri starts with /samplesvc then this filter should act on the request.
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
String requestUri = ctx.getRequest().getRequestURI();
return requestUri.startsWith("/samplesvc");
}
and the second consideration on modifying the request headers to the backend service:
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader("payload.trace", "true");
return null;
}
A backing service getting such a request can look for the header and act accordingly, say in this specific case looking at the "payload.trace" header and deciding to log the incoming message:
@RequestMapping(value = "/message", method = RequestMethod.POST)
public Resource<MessageAcknowledgement> pongMessage(@RequestBody Message input, @RequestHeader("payload.trace") boolean tracePayload) {
if (tracePayload) {
LOGGER.info("Received Payload: {}", input.getPayload());
}
....