-
Notifications
You must be signed in to change notification settings - Fork 2.4k
zuul simple webapp
zuul-simple-webapp is an example web application that shows a few simple use cases of zuul-core.
The best way to understand it is to load it into your environment, run it, modify it, then run it again to notice the changes.
On a Mac or unix-like environment, cd into the zuul-simple-webapp
directory and run this command:
../gradlew jettyRun
After compilation you will see a message like this:
> Building > :zuul-simple-webapp:jettyRun > Running at http://localhost:8080//
By default zuul-simple-webapp uses apache.org as the origin. You can verify this by accessing http://localhost:8080 in a browser.
In build.gradle
we set the zuul.filter.root
system property to src/main/filters
in order to make it work.
zuul-simple-webapp/src/main/groovy/filters is a standard layout for Zuul Filters, containing pre, route, and post directories for each primary Filter type, respectively.
web.xml declarations
web.xml configures a few things:
-
StartServer as a
ServletContextListener
that initializes the app. - ZuulServlet is a servlet that matches all requests. It performs the core Zuul Filter flow of executing pre, routing, and post Filters.
-
ContextLifecycleFilter is a servlet filter matching all requests. It cleans up the
RequestContext
after each request, ensuring isolation.
<listener>
<listener-class>com.netflix.zuul.StartServer</listener-class>
</listener>
<servlet>
<servlet-name>Zuul</servlet-name>
<servlet-class>com.netflix.zuul.http.ZuulServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Zuul</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>ContextLifecycleFilter</filter-name>
<filter-class>com.netflix.zuul.context.ContextLifecycleFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ContextLifecycleFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
StartServer initialization
StartServer
first sets the FilterLoader
's compiler as a GroovyCompiler instance.
FilterLoader.getInstance().setCompiler(new GroovyCompiler());
The compiler can be set to any implementation of DynamicCodeCompiler that is capable of converting Files or named code snippets into Class instances.
We then initialize the FilterFileManager
to look for Groovy files on the filesystem in the specified pre, routing, and post directories every 5 seconds.
final String scriptRoot = System.getProperty("zuul.filter.root");
try {
FilterFileManager.setFilenameFilter(new GroovyFileFilter());
FilterFileManager.init(5,
scriptRoot + "/pre",
scriptRoot + "/route",
scriptRoot + "/post");
} catch (Exception e) {
throw new RuntimeException(e);
}
1. Debug executes with type "pre" and filterOrder 1
shouldFilter()
evaluates to true since the DynamicBooleanProperty routingDebug
defaults to true. If routingDebug
was changed to default to false it could be enabled by passing the HTTP parameter "d=true".
boolean shouldFilter() {
if ("true".equals(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get()))) return true;
return routingDebug.get();
}
run()
enables Zuul route and request debugging:
Object run() {
RequestContext ctx = RequestContext.getCurrentContext()
ctx.setDebugRouting(true)
ctx.setDebugRequest(true)
return null;
}
2. PreDecoration executes with type "pre" and filterOrder 5
shouldFilter()
is always true:
boolean shouldFilter() {
return true;
}
run()
sets the origin host (via RequestContext.setRouteHost() and adds a Cache-Control header to pass along (via RequestContext.addZuulRequestHeader()
Object run() {
RequestContext ctx = RequestContext.getCurrentContext()
// sets origin
ctx.setRouteHost(new URL("http://apache.org/"));
// sets custom header to send to the origin
ctx.addOriginRequestHeader("cache-control", "max-age=3600");
}
3. DebugRequest executes with type "pre" and filterOrder 10000
shouldFilter()
evaluates to true (since [Debug.debugRequest()](http://netflix.github.io/zuul/javadoc/zuul-core/com/netflix/zuul/context/Debug.html#debugRequest(\)) was set to true by [DebugFilter][]:
boolean shouldFilter() {
return Debug.debugRequest()
}
run()
adds request debug information via [Debug.addRequestDebug()](http://netflix.github.io/zuul/javadoc/zuul-core/com/netflix/zuul/context/Debug.html#addRequestDebug(java.lang.String\))
Object run() {
HttpServletRequest req = RequestContext.currentContext.request as HttpServletRequest
Debug.addRequestDebug("REQUEST:: " + req.getScheme() + " " + req.getRemoteAddr() + ":" + req.getRemotePort())
Debug.addRequestDebug("REQUEST:: > " + req.getMethod() + " " + req.getRequestURI() + " " + req.getProtocol())
// and so on
}
4. javaPreFilter executes with type "pre" and filterOrder 50000
This filter doesn't do anything of value - it serves as an example of a pure Java filter that can even be registered as an anonymous inner class.
5. SimpleHostRequest executes with type "routing" and filterOrder 100
shouldFilter
evaluates to true since the routeHost
was set by [PreDecorationFilter][] and sendZuulResponse
defaults to true:
boolean shouldFilter() {
return RequestContext.currentContext.getRouteHost() != null && RequestContext.currentContext.sendZuulResponse()
}
6. SendResponse executes with type "post" and filterOrder 1000
shouldFilter
evaluates to true since zuulResponseHeaders
, responseDataStream
and responseBody
were set by SimpleHostRequest.
boolean shouldFilter() {
return !RequestContext.currentContext.getZuulResponseHeaders().isEmpty() ||
RequestContext.currentContext.getResponseDataStream() != null ||
RequestContext.currentContext.responseBody != null
}
run
copies the origin response into Zuul's response - gruesome details omitted for brevity:
Object run() {
addResponseHeaders()
writeResponse()
}
7. Stats executes with type "post" and filterOrder 2000
shouldFilter
is hardcoded to true as we always want to log the stats if they exist.
run
logs the routing and request stats to stout:
Object run() {
dumpRoutingDebug()
dumpRequestDebug()
}
8. javaPostFilter executes with type "post" and filterOrder 50000
This filter doesn't do anything of value - it serves as an example of a pure Java filter that can even be registered as an anonymous inner class.
A Netflix Original Production
Tech Blog | Twitter @NetflixOSS | Jobs
-
Zuul 2.x
-
Zuul 1.x