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: , , , , , , , | 24 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.

    • 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?