27. Wicket HTTP/2 Support (Experimental)
With Wicket 8.0.0-M2 the new HTTP/2 push API is supported which uses the PushBuilder.
The advantage of this is that you reduce the latency and thus save a lot of time in waiting for requests.
27.1. Example Usage
Currently there are different implementations for each server to be used until the Servlet 4.0 (JSR 369) specification reaches the final state.
Current supported servers are: * Eclipse Jetty 9.3+ * Apache Tomcat 8.5+ * RedHat Undertow 2+
For the setup you need to follow those steps:
Setup your server to use HTTP/2 and follow the instructions provided by the vendor specific documentation. (Because of HTTP/2 a HTTPS setup is also required)
Add the respective dependency for your web server to provide the push functionality.
<dependency>
<groupId>org.apache.wicket.experimental.wicket8</groupId>
<artifactId>wicket-http2-jetty</artifactId>
<!--<artifactId>wicket-http2-tomcat</artifactId>-->
<!--<artifactId>wicket-http2-undertow</artifactId>-->
<version>0.X-SNAPSHOT</version>
</dependency>
- Use the PushHeader Item like in this example page: Example:
public class HTTP2Page extends WebPage
{
private static final long serialVersionUID = 1L;
private transient Response webPageResponse;
private transient Request webPageRequest;
public HTTP2Page()
{
webPageResponse = getRequestCycle().getResponse();
webPageRequest = getRequestCycle().getRequest();
add(new Label("label", "Label"));
}
@Override
public void renderHead(IHeaderResponse response)
{
super.renderHead(response);
TestResourceReference instance = TestResourceReference.getInstance();
response.render(CssHeaderItem.forReference(instance));
response.render(new PushHeaderItem(this, webPageRequest, webPageResponse)
.push(Arrays.asList(new PushItem(instance))));
}
@Override
protected void setHeaders(WebResponse response)
{
// NOOP just disable caching
}
}
Basically the resource is pushed before the actual response of the component is send to the client (browser) and because of this the client does not need to send an additional request.
The PushHeaderItem behaves like explained in the following steps:
When a browser requests the page with an initial commit everything is going to be pushed with (200)
When a browser requests the page a second time resources are not pushed (304) not modified, because of the actual ResourceReferences headers
When a browser requests the page a second time and the markup of the page has changed everything is going to be pushed again (200)
When a browser requests the page a second time and resource references has been changed but not the page markup, all changed resource references are shipped via separate requests
Note: Chrome does not set cache headers if the https connection is not secure (self signed) / valid - so ensure that a valid https connection is available with your server. Browser not caching files if HTTPS is used even if it’s allowed by webserver via response headers If you want to change the cache behavior to not only look at the markup of the page and based on this proceed the push, override the method protected Time getPageModificationTime() of the PushHeaderItem (for more information have a look at the javadoc)
To change the cache headers override the method protected void applyPageCacheHeader() of the PushHeaderItem
27.2. Create server specific http/2 push support
To create a server specific http/2 push support of the Wicket PushBuilder API just follow these steps:
- Add the following dependency to your projects pom.xml (and of course adjust the version)
<dependency>
<groupId>org.apache.wicket.experimental.wicket8</groupId>
<artifactId>wicket-http2-core</artifactId>
<version>0.X-SNAPSHOT</version>
</dependency>
Add a text file called org.apache.wicket.IInitializer into the folder src/main/resources/META-INF/services/
Add a single line with the name of the IInitializer class example: org.apache.wicket.http2.Initializer to the created file
Implement your own server specific PushBuilder class which implements the interface org.apache.wicket.http2.markup.head.PushBuilder This is an example how it was done for jetty:
public class Jetty9PushBuilder implements PushBuilder
{
@Override
public void push(HttpServletRequest httpServletRequest, String... paths)
{
Request request = RequestCycle.get().getRequest();
HttpServletRequest httpRequest = (HttpServletRequest) request.getContainerRequest();
org.eclipse.jetty.server.PushBuilder pushBuilder =
org.eclipse.jetty.server.Request.getBaseRequest(httpRequest).getPushBuilder();
for (String path : paths)
{
pushBuilder.path(path);
}
pushBuilder.push();
}
}
- Implement the class within the package org.apache.wicket.http2.Initializer and add your own server specific PushBuilder class to the Http2Settings. This is an example how it was done for jetty:
public class Initializer implements IInitializer
{
/**
* Initializes the push builder API of Jetty 9.3+
*/
@Override
public void init(Application application)
{
Http2Settings http2Settings = Http2Settings.Holder.get(application);
http2Settings.setPushBuilder(new Jetty9PushBuilder());
}
@Override
public void destroy(Application application)
{
// NOOP
}
}