-
Notifications
You must be signed in to change notification settings - Fork 2.4k
How To Use
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:
gradle jettyRun -Dzuul.script.root=`pwd`/src/main/filters
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.
You see that we passed the zuul.script.root property to zuul-simple-webapp in order to make it work.
zuul-simple-webapp/src/main/filters is a standard layout for Zuul Filters, containing preProcess, routing, and postProcess directories for each primary Filter type, respectively.
web.xml declares a few key parts:
-
StartServer as a
ServletContextListenerthat 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
RequestContextafter 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>1. DebugFilter executes with type "pre" and filterOrder 10000
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. PreDecorationFilter executes with type "pre" and filterOrder 5
shouldFilter() is always true:
boolean shouldFilter() {
return true;
}run() sets the origin host (via RequestContext.html.setRouteHost() and adds a Cache-Control header to pass along (via RequestContext.html.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");
}- DebugRequestFilter 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. SimpleHostRoutingFilter 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()
}5. SendResponseFilter executes with type "post" and filterOrder 1000
shouldFilter evaluates to true since zuulResponseHeaders, responseDataStream and responseBody were set by SimpleHostRoutingFilter.
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()
}6. StatsFilter 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()
}Verbose debug logging for Zuul is enabled by default.
Lines that begin with ZUUL_DEBUG show diagnostics about Zuul itself - typically details on running Filters and modifying the RequestContext:
ZUUL_DEBUG::Filter pre 5 PreDecorationFilter
ZUUL_DEBUG::Filter {PreDecorationFilter TYPE:pre ORDER:5} Execution time = 12ms
ZUUL_DEBUG::{PreDecorationFilter} added originResponseHeaders=[com.netflix.util.Pair@64edca63]
ZUUL_DEBUG::{PreDecorationFilter} added routeHost=http://apache.org/
ZUUL_DEBUG::Filter pre 10000 DebugRequest
ZUUL_DEBUG::Filter {DebugRequest TYPE:pre ORDER:10000} Execution time = 36ms
ZUUL_DEBUG::Invoking {route} type filters
ZUUL_DEBUG::Filter route 100 SimpleHostRoutingFilter
ZUUL_DEBUG::Filter {SimpleHostRoutingFilter TYPE:route ORDER:100} Execution time = 251ms
ZUUL_DEBUG::{SimpleHostRoutingFilter} added responseStatusCode=304
ZUUL_DEBUG::{SimpleHostRoutingFilter} added hostZuulResponse=HTTP/1.1 304 Not Modified [Date: Sun, 09 Jun 2013 02:09:19 GMT, Server: Apache/2.4.4 (Unix) mod_wsgi/3.4 Python/2.7.3 OpenSSL/1.0.0g, Connection: Keep-Alive, Keep-Alive: timeout=5, max=100, ETag: "90a0-4deae5495ba47", Expires: Sun, 09 Jun 2013 03:09:19 GMT, Cache-Control: max-age=3600]
ZUUL_DEBUG::{SimpleHostRoutingFilter} added zuulResponseHeaders=[com.netflix.util.Pair@28aa2b8a, com.netflix.util.Pair@efa5136, com.netflix.util.Pair@1615a33c, com.netflix.util.Pair@c8b48f6b, com.netflix.util.Pair@2bbdebb3]
ZUUL_DEBUG::{SimpleHostRoutingFilter} added zuulRequestHeaders={}
ZUUL_DEBUG::{SimpleHostRoutingFilter} added responseGZipped=false
ZUUL_DEBUG::Invoking {post} type filters
ZUUL_DEBUG::Filter post 1000 SendResponseFilter
ZUUL_DEBUG::Filter {SendResponseFilter TYPE:post ORDER:1000} Execution time = 22ms
ZUUL_DEBUG::Filter post 2000 Stats
Lines that begin with REQUEST_DEBUG show information about HTTP requests and responses: REQUEST is the incoming request to Zuul, ZUUL is the request that Zuul forwards to the origin, ORIGIN_RESPONSE is the response from the origin, and OUTBOUND is the outgoing response from Zuul back to the client.
Below you will see debug logging for the initial GET request to the "/" resource:
REQUEST_DEBUG::REQUEST:: http 0:0:0:0:0:0:0:1:51254 REQUEST_DEBUG::REQUEST:: > GET / HTTP/1.1 REQUEST_DEBUG::REQUEST:: > Host:localhost:8080 REQUEST_DEBUG::REQUEST:: > Connection:keep-alive REQUEST_DEBUG::REQUEST:: > Cache-Control:max-age=0 REQUEST_DEBUG::REQUEST:: > Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 REQUEST_DEBUG::REQUEST:: > User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31 REQUEST_DEBUG::REQUEST:: > DNT:1 REQUEST_DEBUG::REQUEST:: > Accept-Encoding:gzip,deflate,sdch REQUEST_DEBUG::REQUEST:: > Accept-Language:en-US,en;q=0.8 REQUEST_DEBUG::REQUEST:: > Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3 REQUEST_DEBUG::REQUEST:: > If-None-Match:"90a0-4deae5495ba47" REQUEST_DEBUG::REQUEST:: > If-Modified-Since:Sun, 09 Jun 2013 01:10:31 GMT REQUEST_DEBUG::REQUEST:: > REQUEST_DEBUG::ZUUL:: host=http://apache.org/ REQUEST_DEBUG::ZUUL::> Host localhost:8080 REQUEST_DEBUG::ZUUL::> Connection keep-alive REQUEST_DEBUG::ZUUL::> Cache-Control max-age=0 REQUEST_DEBUG::ZUUL::> Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 REQUEST_DEBUG::ZUUL::> User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31 REQUEST_DEBUG::ZUUL::> DNT 1 REQUEST_DEBUG::ZUUL::> Accept-Language en-US,en;q=0.8 REQUEST_DEBUG::ZUUL::> Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.3 REQUEST_DEBUG::ZUUL::> If-None-Match "90a0-4deae5495ba47" REQUEST_DEBUG::ZUUL::> If-Modified-Since Sun, 09 Jun 2013 01:10:31 GMT REQUEST_DEBUG::ZUUL:: > GET /?null HTTP/1.1 REQUEST_DEBUG::ZUUL::> REQUEST_DEBUG::ORIGIN_RESPONSE:: > Date, Sun, 09 Jun 2013 02:09:19 GMT REQUEST_DEBUG::ORIGIN_RESPONSE:: > Keep-Alive, timeout=5, max=100 REQUEST_DEBUG::ORIGIN_RESPONSE:: > ETag, "90a0-4deae5495ba47" REQUEST_DEBUG::ORIGIN_RESPONSE:: > Expires, Sun, 09 Jun 2013 03:09:19 GMT REQUEST_DEBUG::ORIGIN_RESPONSE:: > Cache-Control, max-age=3600 REQUEST_DEBUG::OUTBOUND: > Date:Sun, 09 Jun 2013 02:09:19 GMT REQUEST_DEBUG::OUTBOUND: > Keep-Alive:timeout=5, max=100 REQUEST_DEBUG::OUTBOUND: > ETag:"90a0-4deae5495ba47" REQUEST_DEBUG::OUTBOUND: > Expires:Sun, 09 Jun 2013 03:09:19 GMT REQUEST_DEBUG::OUTBOUND: > Cache-Control:max-age=3600
A Netflix Original Production
Tech Blog | Twitter @NetflixOSS | Jobs
-
Zuul 3.x
-
Zuul 2.x
-
Zuul 1.x