Cross Origin Resource Sharing (CORS) Web Service Endpoints with JSON Using Jersey

In my previous posts, I had discussed quick hacks of using Spring MVC framework or Jersey to implement RESTful web service endpoint using XML, JSON, and JSONP.  What is JSON-P exactly?  JSON-P or JSONP is a hack script tag injection that passing the response from the server in to a user specified Javascript function. The web server will need to return the response as JSON data format but also need to wrap the response in the requested call back name. Since JSON-P is a hack, it has some problems:

  • JSON-P only allows HTTP GET operation. It does not support PUT or POST.
  • There is no error handling. Since the JSON-P HTTP GET operation just simply injects the result back to a JavaScript function, it is either working or not working.
  • Since JSON-P is a hack (again), there is security concerns. For example, a web service could return a function call for the JSON-P portion, but slip in another set of JavaScript logic that hacks the page into sending back private user’s data.

One of the alternatives of JSON-P is CORS (stands for Cross Origin Resource Sharing). The initial W3C draft was back in 2010. In abstract, CORS is an extension to the standard XMLHttpRequest object, which allows the browser to make calls across domains (despite the same-origin restriction) by first “preflighting” a request to the target server to ask it for permission. CORS supports both HTTP GET, PUT, and POST with not only XML but JSON data format as well.

Before we start, let’s take a look at the client side Javascript code.

<html>
   <head>
      <script type="text/javascript" src="jquery.js"></script>
      <script type="application/javascript">       
         (function($) {
            var url = 'http://localhost:8080/employee/id';

            $.ajax({
               type: 'put',
               url: url,
               async: true,
               contentType: 'application/json',
               data: '{"id": 1, "name": "Andy Chan"}',
               success: function(response) {
                  alert("success");
               },
               error: function(xhr) {
                  alert('Error!  Status = ' + xhr.status + " Message = " + xhr.statusText);
               }
            });
         })(jQuery);
      </script>
   </head>
   <body>
      <!-- we will add our HTML content here -->
   </body>
</html>

The browser will send a pre-flight request to the server as following:

Origin: http://127.0.0.1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-requested-with

The browser will wait for the following response:

X-Powered-By: Servlet/3.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: x-requested-with

THe browser will continue with the original request plus the following:

X-Requested-With: XMLHttpRequest

For the server side code, please refer to my previous post for the required dependency for the Java project. Since Jersey doesn’t have extension to support CORS, we have to add the following hack:


   private String corsHeaders;

   private Response makeCORS(ResponseBuilder responseBuilder, String returnMethod) {
       ResponseBuilder rb = responseBuilder.ok()
          .header("Access-Control-Allow-Origin", "*")
          .header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");

       if (!"".equals(returnMethod)) {
          rb.header("Access-Control-Allow-Headers", returnMethod);
       }

       return rb.build();
    }

    private Response makeCORS(ResponseBuilder responseBuilder) {
       return makeCORS(responseBuilder, corsHeaders);
    }

    @OPTION
    public Response getEmployee(@HeaderParam("Access-Control-Request-Headers") String request) {
        corsHeaders = request;
        return makeCORS(Response.ok(), request);
    }

    @GET
    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @Path("/{employeeId}")
    public Response getEmployee(@PathParam("employeeId") final String employeeId) {
        Response response = Response.status(404).build();
 
        Employee employee = employeeDao.getEmployee(employeeId);
 
        if (employee != null) {
            response = makeCORS(Response.status(200), entity(employee));
        } else {
            response = makeCORS(Response.status(500));
        }
 
        return response;
    }

My collegue, Zhentao Li, has documented how to implement CORS by using Spring MVC 3.1. Free feel to take a look and drop him comments.

Filed Under: Software DevelopmentTutorial

Tags:

About the Author: Andy H. Chan has years of enterprise software development and architecture experience. He is also the co-author of the book Pro Spring Integration. He can be reached Twitter @iceycake.

RSSComments (2)

Leave a Reply | Trackback URL

  1. Andy H. Chan says:

    Just browse the web and I have found a better way to hack Jersey to use CORS by using filter.

    http://2rdscreenretargeting.blogspot.com/2012/06/enable-cors-for-jersey.html

Leave a Reply