ProxyServlet is a way to create an HTTP or HTTP/S proxy in very few lines
of code. Even though it’s part of the Jetty project, it’s modularized to be
independent of the Jetty server, so you can use it even in cases where the
servlet won’t be run in Jetty.
A proxy might also be useful to allow a user to access a web service without providing all the information necessary to access it. In our example, we’ll be providing a proxy for Google’s Places API without having to send the Google API key down to the browser.
The proxy we’ll be looking at is a per-request proxy, so it’s not something that could conveniently be used for caching remote server responses in case of slow connections or server failures.
The example is part of the Spring WebMVC application I use to present
WebMVC and REST for a Java class. I’ve added the
PlacesProxyServlet and a
basic HTML page to demonstrate fetching Google Places search results and using
them in jQuery.
To get started, we need
jetty-proxy in our
pom.xml. Prior to Jetty 9, the
ProxyServlet class lived in
jetty-servlets, but it’s been moved, probably to
reduce the other Jetty dependencies that have to be pulled in.
Next, we create a class that extends
ProxyServlet. We need to know the right
URI to use for Google Places, and we need a Google API key. The best way to
handle this is to allow them to be passed in from the servlet context using
init-param, but I like to also allow them to be overridden using Java system
properties. We start by overriding the
To actually proxy the requests, the key method is
rewriteURI. Again, this is
new to Jetty 9; previously there was a method called
accomplished pretty much the same function.
This method returns the “real” URI that the Jetty proxy servlet will call. All of the data from the client request is available. In this case, we just need the browser’s query parameters so we can pass them on to Google Places.
To actually get this to work with the Google Places API, there were a couple other
changes required. First, the Places API enforces HTTP/S. Note that this doesn’t mean
that our client has to connect to our proxy servlet using HTTP/S; regular HTTP is
perfectly fine for that connection because our proxy servlet is making a brand new
HTTP/S connection (using Jetty’s
HttpClient class). However, it does mean that we
need to tell the Jetty
HttpClient that it’s OK to use HTTP/S. We do this by
overriding the method that the
ProxyServlet class uses to make a new
Second, Google Places didn’t like the fact that the Jetty proxy servlet adds a
Host header to the request with the name of the originating server. With this
header, the Google Places server returns 404 in response to the request.
Fortunately, this is easy to fix; we just have to remove that header before the
request goes out. We can do this by overriding the
ProxyServlet thoughtfully provides for just such a problem:
To get this servlet up and running, we need to add it to
web.xml. In the case of
the example application, this required updating to Servlet 3.0, since the Jetty proxy
servlet wants to use asynchronous connections. This is a good thing in terms of
increasing the number of simulataneous requests the proxy servlet can process, but it
requires enabling that feature in
async-supported tag is important; the proxy servlet won’t work without it.
The jQuery makes an AJAX call to the proxy servlet, which then makes a call to Google Places.
The resulting JSON response data is sent through as-is. The (anonymous)
“success” function then gets called. It iterates through the returned results,
<li> tags to the existing list for each result it finds.
Of course, a proxy servlet doesn’t have to be used for sites on the Internet. One of my motivations for creating the example application was to show how easy it was to REST-enable an existing standalone Java application. Many systems that use Java have multiple standalone Java applications, each performing some independent function. This would make it challenging to create a single unified web interface while still allowing each application to define its own REST API. Proxy servlets can help by making it look like there’s a single endpoint for all the various APIs, while not requiring any logic that knows about the contents of the interfaces.