How to add CORS support on the server side in Java with Jersey

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏
In this post I will present how easy it is to enable HTTP response headers on the server sidein Java with Jersey, as defined by the Cross-Origing Resource Sharing (CORS) specification. For that I have extended the REST API built in the post Tutorial – REST API design and implementation in Java with Jersey and Spring, with CORS support.
But before we delve into that, I would like to start with a quick introduction to CORS as found on various great website like Wikipedia or Mozilla Development Network (MDN), I would myself like to reference later.
1. Quick intro to CORS
Well, according to Wikipedia:
“Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. Such “cross-domain” requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request. It is more useful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.” [1]
1.1. Overview
“The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET
, or for POST
usage with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with an HTTP OPTIONS
request method, and then, upon “approval” from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether “credentials” (including Cookies and HTTP Authentication data) should be sent with requests.” [2]
The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.[7]
1.2. CORS HTTP headers
The HTTP headers as defined by CORS are:
1.2.1. Client/Browser side – HTTP request headers
These are headers that clients may use when issuing HTTP requests in order to make use of the cross-sharing feature:
1.2.2. Server side – HTTP response headers
These are the HTTP headers that the server sends back for access control requests as defined by the Cross-Origin Resource Sharing specification:
- Access-Control-Expose-Headers: lets a server white list headers that browsers are allowed to access
- Access-Control-Max-Age: indicates how long the results of a preflight request can be cached.
- Access-Control-Allow-Credentials: indicates if the server allows credentials during CORS requests
- Access-Control-Allow-Methods: indicates the methods allowed when accessing the resource
- Access-Control-Allow-Headers: used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
2. Adding HTTP headers to resources with Jersey
In this post, because we are concerned with the server side of things, I will only use the Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers response headers.
There are two ways to add headers to a response with Jersey:
2.1. Response and ResponseBuilder
The first one is by using the header
method of the javax.ws.rs.core.Response
. This method adds an arbitrary header to the ResponseBuilder
(ResponseBuilder
is a class used to build Response
instances that contain metadata instead of or in addition to an entity):
@GET
@Path("{id}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getPodcastById(@PathParam("id") Long id, @QueryParam("detailed") boolean detailed)
throws IOException, AppException {
Podcast podcastById = podcastService.getPodcastById(id);
return Response.ok() //200
.entity(podcastById, detailed ? new Annotation[]{PodcastDetailedView.Factory.get()} : new Annotation[0])
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS").build();
}
As you can see on lines 9 and 10, the header
method extends the existing ResponseBuilder
and adds the HTTP headers Access-Control-Allow-Origin
and Access-Control-Allow-Methods
, suggesting that GET requests coming from any domain will be allowed for the resource identified by this method – /podcasts/{id}
Note: The javax.ws.rs.core.Response
has also a ResponseBuilder
allow(String... methods)
method, that you could also use to set the list of allowed methods for the resource.
2.2. ContainerResponseFilter
Another way to add the headers to the response is by using Jersey filters, which can modify inbound and outbound requests and responses including modification of headers, entity and other request/response parameters.
I think this is the better way to do it, especially if you want to expose the same HTTP headers in the response, for all the resources of the API – this is a sort of a cross-cutting concern capability powered by Jersey filters.
Ok, so let’s see how this works:
package org.codingpedia.demo.rest.util;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
public class CORSResponseFilter
implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
//headers.add("Access-Control-Allow-Origin", "https://podcastpedia.org"); //allows CORS requests only coming from podcastpedia.org
headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
headers.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia");
}
}
In the example above the CORSResponseFilter
always adds
Access-Control-Allow-Origin
header to the response(line 18). The “*” means the request can come from any domain – this is the way to set this header if you want to make your REST API public where everyone can access it
Access-Control-Allow-Methods
header to the response (line 20), which indicates that GET
, POST
, DELETE
, PUT
methods are allowed when accessing the resource
Access-Control-Allow-Headers
header to the response (line 21), which indicates that the X-Requested-With
, Content-Type
, X-Codingpedia
headers can be used when making the actual request.
The filter must inherit from the ContainerResponseFilter
interface and must be registered as a provider:
/**
* Register JAX-RS application components.
*/
public RestDemoJaxRsApplication(){
register(CORSResponseFilter.class);
//other registrations omitted for brevity
}
Well, that’s it – you’ve learned how easy it is to add CORS support to the server side with Jersey.
Thanks for sharing and connecting with us.
3. Resources
3.1. Source code – GitHub
- GitHub – Codingpedia/demo-rest-jersey-spring (instructions on how to install and run the project)