Cross-Origin Request Blocked Spring REST service + AJAX - java

Unable to call spring REST service
My spring service
#RequestMapping(value = "/MAS/authenticate", method = RequestMethod.POST)
public ResponseEntity<Map<String, String>> authenticate(#RequestBody Subject subject) {
Map<String, String> result = new HashMap<String, String>();
result.put("result_detail", "Invalid Password");
result.put("result", "failure");
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
return new ResponseEntity<Map<String, String>>(result, responseHeaders, HttpStatus.OK);
}
My AJAX code
$.ajax(
{
crossDomain: true,
type: "POST",
contentType: "application/json; charset=utf-8",
async: false,
url: "http://localhost:8080/SpringMVC/rest/MAS/authenticate",
headers: {"Access-Control-Allow-Origin" : "*"},
data:{},
dataType: "json", //also tried "jsonp"
success: function(data, status, jqXHR)
{
alert('success');
},
error: function(jqXHR, status)
{
alert('error');
}
});
I am getting following error :(
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/SpringMVC/rest/MAS/authenticate. This can be fixed by moving the resource to the same domain or enabling CORS.
i have also tried dataType: "jsonp". its append my body object into URL which make different URL and cannot hit my service URL then and got 404 error.
My browser: firefox 36.0.4
How i can get rid from this error, any help?

My AJAX call and service were OK. After searching a lot on internet i have found that its server side problem not client side.
on server side with Spring we have to implement filter which will allow CORS requests.
filter will look like this.
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;
public class CORSFilter extends OncePerRequestFilter {
private static final Log LOG = LogFactory.getLog(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
LOG.trace("Sending Header....");
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// response.addHeader("Access-Control-Allow-Headers", "Authorization");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1");
}
filterChain.doFilter(request, response);
}
}
and in web.xml apply this filter on your service requests like this
<filter>
<filter-name>cors</filter-name>
<filter-class>com.test.common.controller.CORSFilter</filter-class> <!-- your package name and filter class -->
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This may help someone else who went through this problem. :)

By default the only method allowed is a GET, and you don't allow the POST on your server side:
Access-Control-Allow-Origin: *
This header only enables CORS, but you need to add this:
Access-Control-Allow-Methods: POST, GET
More detailed how-to about the HTTP access control (CORS) on Mozilla project
So your code should be something like this:
responseHeaders.add("Access-Control-Allow-Methods", "POST, GET"); // also added header to allow POST, GET method to be available
responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
Update:
I have re-read the article, and found out some details:
A simple cross-site request is one that:
Only uses GET, HEAD or POST. If POST is used to send data to the
server, the Content-Type of the data sent to the server with the HTTP
POST request is one of application/x-www-form-urlencoded,
multipart/form-data, or text/plain.
Does not set custom headers with
the HTTP Request (such as X-Modified, etc.)
As you can read in bold, you must set other Content-Type for your data (currently it is contentType: "application/json; charset=utf-8",) or use the preflight technique described later:
It uses methods other than GET, HEAD or POST. Also, if POST is used
to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as
X-PINGOTHER)
So I suggest you either change the contentType or try to work with this header into your request:
Access-Control-Request-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE
and this headers into your response:
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE
And after that you can try to call your method.

Following is the solution for cross platform spring boot web service call.
Application URL: http://localhost:8080
Webservice URL: http://localhost:9090
In your spring controller use following annotation
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping(value = "/uri", method = RequestMethod.GET)
public SomeObject someMethod(){
// your logic will come here
}

Related

from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource [duplicate]

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
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
Registering Resources and Providers in Jersey 2
What exactly is the ResourceConfig class in Jersey 2?
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
With the Origin request header, the value will be the origin server domain, and the response Access-Control-Allow-Origin should be either this same address or * to specify that all origins are allowed.
If the client tries to manually set any headers not in the above list, then the browser will set the Access-Control-Request-Headers header, with the value being a list of all the headers the client is trying to set. The server should respond back with a Access-Control-Allow-Headers response header, with the value being a list of headers it allows.
The browser will also set the Access-Control-Request-Method request header, with the value being the HTTP method of the request. The server should respond with the Access-Control-Allow-Methods response header, with the value being a list of the methods it allows.
If the client uses the XHR.withCredentials, then the server should respond with the Access-Control-Allow-Credentials response header, with a value of true. Read more here.
So with all that said, here is a better implementation. Even though this is better than the above implementation, it is still inferior to the RESTEasy one I linked to, as this implementation still allows all origins. But this filter does a better job of adhering to the CORS spec than the above filter which just adds the CORS response headers to all request. Note that you may also need to modify the Access-Control-Allow-Headers to match the headers that your application will allow; you may want o either add or remove some headers from the list in this example.
#Provider
#PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
/**
* Method for ContainerRequestFilter.
*/
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request with
// a 200 status, and the CORS headers are added in the
// response filter method below.
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
/**
* A preflight request is an OPTIONS request
* with an Origin header.
*/
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
/**
* Method for ContainerResponseFilter.
*/
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
// if there is no Origin header, then it is not a
// cross origin request. We don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With, Authorization, " +
"Accept-Version, Content-MD5, CSRF-Token, Content-Type");
}
// Cross origin requests can be either simple requests
// or preflight request. We need to add this header
// to both type of requests. Only preflight requests
// need the previously added headers.
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
To learn more about CORS, I suggest reading the MDN docs on Cross-Origin Resource Sharing (CORS)
Remove annotation "#CrossOriginResourceSharing(allowAllOrigins = true)"
Then Return Response like below:
return Response.ok()
.entity(jsonResponse)
.header("Access-Control-Allow-Origin", "*")
.build();
But the jsonResponse should replace with a POJO Object!
The other answer might be strictly correct, but misleading. The missing part is that you can mix filters from different sources together. Even thought Jersey might not provide CORS filter (not a fact I checked but I trust the other answer on that), you can use tomcat's own CORS filter.
I am using it successfully with Jersey. I have my own implementation of Basic Authentication filter, for example, together with CORS. Best of all, CORS filter is configured in web XML, not in code.
peeskillet's answer is correct. But I get this error when refresh the web page (it is working only on first load):
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
So instead of using add method to add headers for response, I using put method. This is my class
public class MCORSFilter implements ContainerResponseFilter {
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD";
public static final String[] ALL_HEADERs = {
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS
};
public static final String[] ALL_HEADER_VALUEs = {
ACCESS_CONTROL_ALLOW_ORIGIN_VALUE,
ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE,
ACCESS_CONTROL_ALLOW_HEADERS_VALUE,
ACCESS_CONTROL_ALLOW_METHODS_VALUE
};
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
for (int i = 0; i < ALL_HEADERs.length; i++) {
ArrayList<Object> value = new ArrayList<>();
value.add(ALL_HEADER_VALUEs[i]);
response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method
}
return response;
}
}
And add this class to init-param in web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.MCORSFilter</param-value>
</init-param>
To solve this for my project I used Micheal's answer and arrived at this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>run-embedded</id>
<goals>
<goal>run</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<port>${maven.tomcat.port}</port>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
<contextFile>${project.basedir}/tomcat/context.xml</contextFile>
<!--enable CORS for development purposes only. The web.xml file specified is a copy of
the auto generated web.xml with the additional CORS filter added -->
<tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml>
</configuration>
</execution>
</executions>
</plugin>
The CORS filter being the basic example filter from the tomcat site.
Edit:
The maven.tomcat.web-xml.file variable is a pom defined property for the project and it contains the path to the web.xml file (located within my project)

Angular 6 - Spring MVC :: Options preflight request throws 500 internal Server Error

Intention:
Consume a REST API in Angular that is exposed via a SpringMVC based web application. Both are running in different hosts
Problem:
Although the API I am requesting is a GET Request, Angular behind-the-scenes first makes an OPTIONS request to the REST API SpringMVC server. This throws back a 500 server error (see CURL output below).
Tried hitting the same API using Postman tool (GET request), surprisingly its giving desired output (i.e. also gives Access-Control-Allow-Origin header) without any error, but OPTIONS request throws 500 server error.
Tech Stack I am using:
Angular 6 (runs atop NodeJS)
Spring MVC 4.3.6.RELEASE (with no Spring security explicitly configured) [Java config based Spring configuration]
Jetty-Runner 9.4.1 (to run the WAR file of Spring MVC webapp).
Error Message got by Angular:
Access to XMLHttpRequest at 'http://localhost:8080/v1/create' from origin
'http://localhost:4200' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested resource.
Code Snippets:
Angular code:
public createDomainObj() {
return this.http.post('http://localhost:8080/v1/create', request body parameter)
}
SpringMVC code:
#ResponseBody
#RequestMapping(value = "/v1/create", method = RequestMethod.POST)
#AccessController(accessLevel = "Anonymous")
public <APIResponseModelClass> anAPIMethod(#RequestBody param1, param2) {
//code logic
return <obj>;
}
What's tried already:
CORS Filter in SpringMVC, all combinations of Annotations, but no luck.
Have also tried suggestions mentioned in below links to no success:
https://www.baeldung.com/spring-security-cors-preflight
How to add Access-Control-Allow-Origin to jetty server
CURL is able to reproduce the problem:
REQUEST:
curl -H "Origin:*" -H "Access-Control-Request-Method: GET, POST, PUT, DELETE"
-H "Access-Control-Request-Headers: X-Requested-With"
-X OPTIONS --verbose http://localhost:8080/v1/create
RESPONSE:
Trying 127.0.0.1...
Connected to localhost (127.0.0.1) port 8080 (#0)
OPTIONS /v1/create HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.47.0
Accept: */*
Origin:*
Access-Control-Request-Method: GET, POST, PUT, DELETE
Access-Control-Request-Headers: X-Requested-With
Content-Length: 392
Content-Type: application/x-www-form-urlencoded
upload completely sent off: 392 out of 392 bytes
HTTP/1.1 500 Server Error
Connection: close
Server: Jetty(9.4.2.v20170220)
Closing connection 0
So, how to make Angular to consume the REST API from SpringMVC that has OPTIONS preflight aspect?
I can say about issue,
CORS:Response to preflight request doesn't pass access control,
There are two types of requests,
1) Simple
Have some criteria, simple exchange of cors headers, allowed methods, headers, content-types
2) preflight
Those doesnt match simple request criteria are preflight, for example,
we send a DELETE request to the server. The browser sends OPTIONS request with headers containing info about the DELETE request we made.
OPTIONS /users/:id
Access-Control-Request-Method: DELETE
simple thing to fix is you can remove or change any complex headers that aren't needed.
Header set Access-Control-Allow-Origin "*" setting this will work for simple CORS requests, so for more complex request having custom headers value wont work, thats the preflight mechanism of the browser it checks that service accepts request or not,
remeber that it includeds,
Access-Control-Request-Headers
Access-Control-Request-Method
Access-Control-Allow-Origin
it seems you need to add cors in http configure thats cors filter,
different ways enabling cors,
1) Controller method CORS configuration
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
2) Global CORS configuration
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
}
};
}
3) Enabling webSecurity, try adding http.cors()
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    #Override
    protected void configure(HttpSecurity http) throws Exception {
        // ...
        http.cors();
    }
}

how to enable CORS filter in spring 4.2

I am trying to send a request from my Webstorm application to my backend application, which both are at different ports, I am working with angularJS in the front end and java spring 4.2.5 in backend. I have tried various things like adding cors filter,cors annotation However, after doing this my error, being
XMLHttpRequest cannot load http://localhost:8081/appUser. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 404.
The angularJS controller looks like
registerController.factory('registerFactory', function(){
return {
getClassification:function($http,tempString){
//TODO add URL
var url = "http://localhost:8081/example?eg="+tempString
return $http({
method: 'POST',
url: url
});
}
}
});
The spring controller looks like
#RequestMapping(value = "/example", method = RequestMethod.POST)
#ResponseBody
public String postAppUser(#RequestParam String eg) throws JsonProcessingException {
return "ok yes ";
}
I tried adding CORS filter but nothing seems to work. Not sure if it is picked up by the app. I mean if its in the config path.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
#Component
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
The web.xml looks like
<web-app>
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>cors</filter-name>
<filter-class>com.myApp.security.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
This is what the http call looks like. It doesnt contain allowed access headers
Request URL:http://localhost:8081/appUser
Request Method:GET
Status Code:404 Not Found
Remote Address:[::1]:8081
Response Headers
view source
Content-Length:965
Content-Type:text/html;charset=utf-8
Date:Sun, 19 Jun 2016 03:43:40 GMT
Server:Apache-Coyote/1.1
Request Headers
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:8081
Origin:http://localhost:63342
I would really appreciate if someone could guide me. I been stuck since last 5 days cant seem to get this working. if you could point to a blog/tutorial/video which i can refer to
Spring it self provide feature to enable cors. Please refer below example.
https://spring.io/guides/gs/rest-service-cors/
To enable CORS, annotate your request method with
#CrossOrigin(origins = "http://localhost:63342")
Have a look at the Spring documentation of CORS
UPDATE
I had the same problem in my application, removed CrossOrigin annotation in request method and added below in angular service js
delete $http.defaults.headers.common['X-Requested-With'];
and
return $http({
method: 'POST',
url: '/example'/ + '?eg=' + tempString
});

Always got Method DELETE is not allowed by Access-Control-Allow-Methods in preflight response

I am using jersey as my restful api implementation. In the front end, I am using angularjs $http service to make http request. When I request a delete method I always got below error.
"Method DELETE is not allowed by Access-Control-Allow-Methods in preflight response."
I read some articles and they say I need to allow delete on "Access-Control-Allow-Methods". I have setup the response filter as below but it still has such problem. What else should I do?
#Provider
public class CORSResponseFilter implements ContainerResponseFilter {
#Override
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-Methods", "*");
}
}
below is my angular code to make the request:
$http({
method: 'DELETE',
url: remoteUrl,
headers : {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
'ACCESS_TOKEN' : $cookieStore.get("access_token")
},
data : $httpParamSerializer({
'id':id
})
}).success(function(data,status,headers,config) {
$scope.refreshDepartments();
console.log(data);
alert("success");
}).error(function(data,status,headers,config){
console.log(data);
alert("error");
});
After some testing, I found the solution. I put the allow method on the header as below, then it works. I don't know why "*" doesn't work.
headers.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
The value " * " only counts as a special wildcard value for requests without credentials (requests without HTTP cookies or HTTP authentication information). In requests with credentials, it is treated as the literal method name "*" without special semantics.
Source : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods

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
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
Registering Resources and Providers in Jersey 2
What exactly is the ResourceConfig class in Jersey 2?
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
With the Origin request header, the value will be the origin server domain, and the response Access-Control-Allow-Origin should be either this same address or * to specify that all origins are allowed.
If the client tries to manually set any headers not in the above list, then the browser will set the Access-Control-Request-Headers header, with the value being a list of all the headers the client is trying to set. The server should respond back with a Access-Control-Allow-Headers response header, with the value being a list of headers it allows.
The browser will also set the Access-Control-Request-Method request header, with the value being the HTTP method of the request. The server should respond with the Access-Control-Allow-Methods response header, with the value being a list of the methods it allows.
If the client uses the XHR.withCredentials, then the server should respond with the Access-Control-Allow-Credentials response header, with a value of true. Read more here.
So with all that said, here is a better implementation. Even though this is better than the above implementation, it is still inferior to the RESTEasy one I linked to, as this implementation still allows all origins. But this filter does a better job of adhering to the CORS spec than the above filter which just adds the CORS response headers to all request. Note that you may also need to modify the Access-Control-Allow-Headers to match the headers that your application will allow; you may want o either add or remove some headers from the list in this example.
#Provider
#PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
/**
* Method for ContainerRequestFilter.
*/
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request with
// a 200 status, and the CORS headers are added in the
// response filter method below.
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
/**
* A preflight request is an OPTIONS request
* with an Origin header.
*/
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
/**
* Method for ContainerResponseFilter.
*/
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
// if there is no Origin header, then it is not a
// cross origin request. We don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With, Authorization, " +
"Accept-Version, Content-MD5, CSRF-Token, Content-Type");
}
// Cross origin requests can be either simple requests
// or preflight request. We need to add this header
// to both type of requests. Only preflight requests
// need the previously added headers.
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
To learn more about CORS, I suggest reading the MDN docs on Cross-Origin Resource Sharing (CORS)
Remove annotation "#CrossOriginResourceSharing(allowAllOrigins = true)"
Then Return Response like below:
return Response.ok()
.entity(jsonResponse)
.header("Access-Control-Allow-Origin", "*")
.build();
But the jsonResponse should replace with a POJO Object!
The other answer might be strictly correct, but misleading. The missing part is that you can mix filters from different sources together. Even thought Jersey might not provide CORS filter (not a fact I checked but I trust the other answer on that), you can use tomcat's own CORS filter.
I am using it successfully with Jersey. I have my own implementation of Basic Authentication filter, for example, together with CORS. Best of all, CORS filter is configured in web XML, not in code.
peeskillet's answer is correct. But I get this error when refresh the web page (it is working only on first load):
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
So instead of using add method to add headers for response, I using put method. This is my class
public class MCORSFilter implements ContainerResponseFilter {
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD";
public static final String[] ALL_HEADERs = {
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS
};
public static final String[] ALL_HEADER_VALUEs = {
ACCESS_CONTROL_ALLOW_ORIGIN_VALUE,
ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE,
ACCESS_CONTROL_ALLOW_HEADERS_VALUE,
ACCESS_CONTROL_ALLOW_METHODS_VALUE
};
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
for (int i = 0; i < ALL_HEADERs.length; i++) {
ArrayList<Object> value = new ArrayList<>();
value.add(ALL_HEADER_VALUEs[i]);
response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method
}
return response;
}
}
And add this class to init-param in web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.MCORSFilter</param-value>
</init-param>
To solve this for my project I used Micheal's answer and arrived at this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>run-embedded</id>
<goals>
<goal>run</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<port>${maven.tomcat.port}</port>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
<contextFile>${project.basedir}/tomcat/context.xml</contextFile>
<!--enable CORS for development purposes only. The web.xml file specified is a copy of
the auto generated web.xml with the additional CORS filter added -->
<tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml>
</configuration>
</execution>
</executions>
</plugin>
The CORS filter being the basic example filter from the tomcat site.
Edit:
The maven.tomcat.web-xml.file variable is a pom defined property for the project and it contains the path to the web.xml file (located within my project)

Categories