Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
73 views
in Technique[技术] by (71.8m points)

java - How to handle CORS using JAX-RS with Jersey

I'm developing a java script client application, in server-side I need to handle CORS, all the services I had written in JAX-RS with JERSEY. My code:

@CrossOriginResourceSharing(allowAllOrigins = true)
@GET
@Path("/readOthersCalendar")
@Produces("application/json")
public Response readOthersCalendar(String dataJson) throws Exception {  
     //my code. Edited by gimbal2 to fix formatting
     return Response.status(status).entity(jsonResponse).header("Access-Control-Allow-Origin", "*").build();
}

As of now, i'm getting error No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.”

Please assist me with this.

Thanks & Regards Buddha Puneeth

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Note: Make sure to read the UPDATE at the bottom. The original answer includes a "lazy" implementation of the CORS filter

With Jersey, to handle CORS, you can just use a ContainerResponseFilter. The ContainerResponseFilter for Jersey 1.x and 2.x are a bit different. Since you haven't mentioned which version you're using, I'll post both. Make sure you use the correct one.

Jersey 2.x

import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

@Provider
public class CORSFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext request,
            ContainerResponseContext response) throws IOException {
        response.getHeaders().add("Access-Control-Allow-Origin", "*");
        response.getHeaders().add("Access-Control-Allow-Headers",
                "CSRF-Token, X-Requested-By, Authorization, Content-Type");
        response.getHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }
}

If you use package scanning to discover providers and resources, the @Provider annotation should take care of the configuration for you. If not, then you will need to explicitly register it with the ResourceConfig or the Application subclass.

Sample code to explicitly register filter with the ResourceConfig:

final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new CORSFilter());
final final URI uri = ...;
final HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, resourceConfig);

For Jersey 2.x, if you are having problems registering this filter, here are a couple resources that might help

Jersey 1.x

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

@Provider
public class CORSFilter implements ContainerResponseFilter {
    @Override
    public ContainerResponse filter(ContainerRequest request,
            ContainerResponse response) {

        response.getHttpHeaders().add("Access-Control-Allow-Origin", "*");
        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "CSRF-Token, X-Requested-By, Authorization, Content-Type");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");

        return response;
    }
}

web.xml configuration, you can use

<init-param>
  <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
  <param-value>com.yourpackage.CORSFilter</param-value>
</init-param>

Or ResourceConfig you can do

resourceConfig.getContainerResponseFilters().add(new CORSFilter());

Or package scanning with the @Provider annotation.


EDIT

Please note that the above example can be improved. You will need to know more about how CORS works. Please see here. For one, you will get the headers for all responses. This may not be desirable. You may just need to handle the preflight (or OPTIONS). If you want to see a better implemented CORS filter, you can check out the source code for the RESTeasy CorsFilter


UPDATE

So I decided to add a more correct implementation. The above implementation is lazy and adds all the CORS headers to all requests. The other mistake is that being that it is only a response filter, the request is still processes. This means that when the preflight request comes in, which is an OPTIONS request, there will be no OPTIONS method implemented, so we will get a 405 response, which is incorrect.

Here's how it should work. So there are two types of CORS requests: simple requests and preflight requests. For a simple request, the browser will send the actual request and add the Origin request header. The browser expects for the response to have the Access-Control-Allow-Origin header, saying that the origin from the Origin header is allowed. In order for it to be considered a "simple request", it must meet the following criteria:

  • Be one of the following method:
    • GET
    • HEAD
    • POST
  • Apart from headers automatically set by the browser, the request may only contain the following manually set headers:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Save-Data
    • Viewport-Width
    • Width
  • The only allowed values for the Content-Type header are:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

If the request doesn't meet all of these three criteria, a Preflight request is made. This is an OPTIONS request that is made to the server, prior to the actual request being made. It will contain different Access-Control-XX-XX headers, and the server should respond to those headers with its own CORS response headers. Here are the matching headers:

REQUEST HEADER RESPONSE HEADER
Origin Access-Control-Allow-Origin
Access-Control-Request-Headers Access-Control-Allow-Headers
Access-Control-Request-Method Access-Control-Allow-Methods
XHR.withCredentials Access-Control-Allow-Credentials

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...