此内容没有您所选择的语言版本。
Chapter 10. Undertow
10.1. Introduction to Undertow Handler
Undertow is a web server designed to be used for both blocking and non-blocking tasks. It replaces JBoss Web in JBoss EAP 7. Some of its main features are:
- High Performance
- Embeddable
- Servlet 3.1
- Web Sockets
- Reverse Proxy
Request Lifecycle
When a client connects to the server, Undertow creates a io.undertow.server.HttpServerConnection
. When the client sends a request, it is parsed by the Undertow parser, and then the resulting io.undertow.server.HttpServerExchange
is passed to the root handler. When the root handler finishes, one of four things can happen:
- The exchange is completed
- And exchange is considered complete if both request and response channels have been fully read or written. For requests with no content, such as GET and HEAD, the request side is automatically considered fully read. The read side is considered complete when a handler has written out the full response and has closed and fully flushed the response channel. If an exchange is already complete, then no action is taken.
- The root handler returns normally without completing the exchange
-
In this case the exchange is completed by calling
HttpServerExchange.endExchange()
. - The root handler returns with an Exception
-
In this case a response code of
500
is set and the exchange is ended usingHttpServerExchange.endExchange()
. - The root handler can return after
HttpServerExchange.dispatch()
has been called, or after async IO has been started - In this case the dispatched task will be submitted to the dispatch executor, or if async IO has been started on either the request or response channels then this will be started. In this case the exchange will not be finished. It is up to your async task to finish the exchange when it is done processing.
By far the most common use of HttpServerExchange.dispatch()
is to move execution from an IO thread where blocking is not allowed into a worker thread, which does allow for blocking operations. This pattern generally looks like:
Example: Dispatching to a Worker Thread
public void handleRequest(final HttpServerExchange exchange) throws Exception { if (exchange.isInIoThread()) { exchange.dispatch(this); return; } //handler code }
Because exchange is not actually dispatched until the call stack returns, you can be sure that more that one thread is never active in an exchange at once. The exchange is not thread safe. However it can be passed between multiple threads as long as both threads do not attempt to modify it at once.
Ending the Exchange
There are two ways to end an exchange, either by fully reading the request channel, and calling shutdownWrites()
on the response channel and then flushing it, or by calling HttpServerExchange.endExchange()
. When endExchange()
is called, Undertow will check if the content has been generated yet. If it has, then it will simply drain the request channel and close and flush the response channel. If not and there are any default response listeners registered on the exchange, then Undertow will give each of them a chance to generate a default response. This mechanism is how default error pages are generated.
For more information on configuring the Undertow, see Configuring the Web Server in the JBoss EAP Configuration Guide.
10.2. Using Existing Undertow Handlers with a Deployment
Undertow provides a default set of handlers that you can use with any application deployed to JBoss EAP. You can find a full list of the available handlers as well as their attributes here.
To use a handler with a deployment, you need to add a WEB-INF/undertow-handlers.conf
file.
Example: WEB-INF/undertow-handlers.conf
File
allowed-methods(methods='GET')
All handlers may also take an optional predicate to apply that handler in specific cases.
Example: WEB-INF/undertow-handlers.conf
File with Optional Predicate
path('/my-path') -> allowed-methods(methods='GET')
The above example will only apply the allowed-methods
handler to the path /my-path
.
Some handlers have a default parameter, which allows you to specify the value of that parameter in the handler definition without using the name.
Example: WEB-INF/undertow-handlers.conf
File Using the Default Parameter
path('/a') -> redirect('/b')
You also may update the WEB-INF/jboss-web.xml
file to include the definition of one or more handlers but using WEB-INF/undertow-handlers.conf
is preferred.
Example: WEB-INF/jboss-web.xml
File
<jboss-web> <http-handler> <class-name>io.undertow.server.handlers.AllowedMethodsHandler</class-name> <param> <param-name>methods</param-name> <param-value>GET</param-value> </param> </http-handler> </jboss-web>
A full list of provided Undertow handlers can be found here.
10.3. Creating Custom Handlers
-
A custom handler can be defined in the
WEB-INF/jboss-web.xml
file.
Example: Define Custom Handler in WEB-INF/jboss-web.xml
<jboss-web> <http-handler> <class-name>org.jboss.example.MyHttpHandler</class-name> </http-handler> </jboss-web>
Example: HttpHandler
Class
package org.jboss.example; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; public class MyHttpHandler implements HttpHandler { private HttpHandler next; public MyHttpHandler(HttpHandler next) { this.next = next; } public void handleRequest(HttpServerExchange exchange) throws Exception { // do something next.handleRequest(exchange); } }
-
Parameters could also be set for the custom handler via the
WEB-INF/jboss-web.xml
file.
Example: Defining Parameters in WEB-INF/jboss-web.xml
<jboss-web> <http-handler> <class-name>org.jboss.example.MyHttpHandler</class-name> <param> <param-name>myParam</param-name> <param-value>foobar</param-value> </param> </http-handler> </jboss-web>
For these parameters to work, the handler class needs to have corresponding setters.
Example: Defining Setter Methods in Handler
package org.jboss.example; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; public class MyHttpHandler implements HttpHandler { private HttpHandler next; private String myParam; public MyHttpHandler(HttpHandler next) { this.next = next; } public void setMyParam(String myParam) { this.myParam = myParam; } public void handleRequest(HttpServerExchange exchange) throws Exception { // do something, use myParam next.handleRequest(exchange); } }
Instead of using the
WEB-INF/jboss-web.xml
for defining the handler, it could also be defined in theWEB-INF/undertow-handlers.conf
file.myHttpHandler(myParam='foobar')
For the handler defined in
WEB-INF/undertow-handlers.conf
to work, two things need to be created:An implementation of
HandlerBuilder
, which defines the corresponding syntax bits forundertow-handlers.conf
and is responsible for creating theHttpHandler
, wrapped in aHandlerWrapper
.Example:
HandlerBuilder
Classpackage org.jboss.example; import io.undertow.server.HandlerWrapper; import io.undertow.server.HttpHandler; import io.undertow.server.handlers.builder.HandlerBuilder; import java.util.Collections; import java.util.Map; import java.util.Set; public class MyHandlerBuilder implements HandlerBuilder { public String name() { return "myHttpHandler"; } public Map<String, Class<?>> parameters() { return Collections.<String, Class<?>>singletonMap("myParam", String.class); } public Set<String> requiredParameters() { return Collections.emptySet(); } public String defaultParameter() { return null; } public HandlerWrapper build(final Map<String, Object> config) { return new HandlerWrapper() { public HttpHandler wrap(HttpHandler handler) { MyHttpHandler result = new MyHttpHandler(handler); result.setMyParam((String) config.get("myParam")); return result; } }; } }
An entry in the file
META-INF/services/io.undertow.server.handlers.builder.HandlerBuilder
. This file must be on the class path, for example, inWEB-INF/classes
.org.jboss.example.MyHandlerBuilder