CORS-Compliant REST API with Jersey and ContainerResponseFilter

Posted: février 27th, 2012 | Author: | Filed under: Dev, Java, Java EE, JAX-RS, Jersey, Tools, Tutorial | Tags: , , , , , , , | 25 Comments »

I recently had to consume a REST API with a cross-domain call and i’ve found a solution in this excellent blog post from Kdecherf.

The problem with this implementation is that you need to call a method for each of your api’s methods.

So with the ContainerResponseFilter interface, you could do this for ALL of your methods … transparently.

1 – Configure web.xml

You just have to add an init-param to your Jersey Servlet

<init-param>
	<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
	<param-value>com.ezakus.api.web.security.ResponseCorsFilter</param-value>
</init-param>

2 – ResponseCorsFilter

package com.ezakus.api.web.security;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

public class ResponseCorsFilter implements ContainerResponseFilter {

	@Override
	public ContainerResponse filter(ContainerRequest req, ContainerResponse contResp) {

		ResponseBuilder resp = Response.fromResponse(contResp.getResponse());
		resp.header("Access-Control-Allow-Origin", "*")
	      		.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");

		String reqHead = req.getHeaderValue("Access-Control-Request-Headers");

		if(null != reqHead && !reqHead.equals("")){
			resp.header("Access-Control-Allow-Headers", reqHead);
		}

		contResp.setResponse(resp.build());
        	return contResp;
	}

}

And that’s all !

Thanks again to Kdecherf for his war upon JSONP and for sharing those headers :D

 

  • http://.... Ivan

    God bless you for that! =))) Spend 2 days in war with jsonp, was trying nginx proxy… this solution is so much simpler and nicer =)

  • http://Website Amir

    You saved my life.
    Thx for posting this.

  • http://twitter.com/tpires Tiago Pires

    Thank you for your helpful post :)

  • Tobi

    You made my day :-) Thanks so much

    • fdussert

      Happy that my post helps you ;)

      • Akash Bansal

        This is working for Chrome and FireFox but not working for IE and Eclipse Keepler browser itself.. Please help..

        • fdussert

          This is server code, not related to any browser, I guess you have to check the client part of your code (e.g. jquery or javascript)

  • Leonardo

    Thank you very much! The configuration you suggested completely solved my trouble! You are my today’s hero! :-)

  • Gianluca Tessarolo

    GREAT !

    Finally a clear, simple and working solution.

    Many thanks !!!

  • http://twitter.com/osandum Ole Sandum

    that !reqHead.equals(null) at the end seems redundant. Did you mean .equals(«  »)?

    • usul

      Yes thanks, I edited the post

    • fdussert

      Thanks, you’re right, I edited

  • Martin Schayna

    Thank you for sharing. I have to rewrite your code because it failed for non-String entity in response (no message writers blah blah…):

    // add CORS headers
    MultivaluedMap headers = response.getHttpHeaders();
    // allow all origins
    headers.add("Access-Control-Allow-Origin", "*");
    // allow all methods
    headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
    // allow all requested headers
    String requestHeaders = request.getHeaderValue("Access-Control-Request-Headers");
    if (requestHeaders != null) {
    headers.add("Access-Control-Allow-Headers", requestHeaders);
    }

    But original idea is yours.

    • Lakshmisri Gopalan

      This is not working for me. Can you tell me if I am missing out anything. Once adding the headers, how did u add the header to the response. Once I make this change, I am getting an error ‘Aborted’

  • Gili

    Please vote for https://java.net/jira/browse/JAX_RS_SPEC-21 for simpler and more flexible way to implement this.

  • AllieCat

    What would be a good way of checking a successful implementation? I’m using HTTP Headers to check for:Access-Control-Allow-Origin*But that isn’t showing up. How did you debug?

    • usul

      What do you mean by ‘How did you debug’
      If you doesn’t implement CORS, you can’t call the REST methods from another domain, so I guess you can test this way ;)
      If you are using jquery for example, you have to activate CORS
      $.support.cors = true;
      After that, you’ll see an OPTIONS request for each ajax request you’ll fire.

    • fdussert

      What do you mean by ‘How did you debug’
      If you doesn’t implement CORS, you can’t call the REST methods from another domain, so I guess you can test this way
      If you are using jquery for example, you have to activate CORS
      $.support.cors = true;
      After that, you’ll see an OPTIONS request for each ajax request you’ll fire.

      • Yergalem

        right click > inspect element on any of your pages. Go to – Network Tab – where you can see the requests( like ajax ). If you see the path you provided in your ajax call, click on it and it’ll show you request and response headers including the payload.

    • V V

      I debugged in Jquery by setting the type in the .ajax to ‘OPTIONS’. Then using Firebug (NET options) viewed the network traffic, and verified the options headers. I could do this with the App on the same server. After testing that ‘Options’ returned the proper headers, deployed to a different domain, and verified that cross-domain calls were fine. This avoids involving the other domain in testing cross-domain calls.

      Jquery ajax call:

      $.ajax({ url: Url,
      success: function(data){
      alert(« Options Response:  » + data); //should be empty
      },
      type: ‘OPTIONS’,
      data: null,
      error: function(error,textStatus, errorThrown ){
      alert(« An unexpected error occurred: error/textStatus/errorThrown » + error+ »/ »+textStatus+ »/ »+errorThrown);
      },
      });

  • Iamar Zuza Araujo

    Thanks so much. Easy and clean. Worked perfectly for me. Best wishes.

  • Pingback: CORS Rest | Zherui LiuZherui Liu

  • Ashish Patel

    Thanks, super.

  • Amit Khandelwal

    Great Post , solved a problem in 2 mins , thanks a ton Man

  • Sharadha

    I did the same, but I am getting an error
    ResponseCorsFilter is not found. Can you please help me with the same?