I developed a web service (REST) with using java jersey library on tomcat server and it works well when I send requests via a rest client. And I created a front end for my web service with using Vue.js.
However when I try to send request with my vue.js project, I got this warning: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://{My ip,port ...}/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). (I am using mozilla)
Here is how I allowed CORS headers in my web service:
#POST
#Path("/login")
#Produces(MediaType.APPLICATION_JSON)
public Response loginUser(#Context HttpServletRequest request) throws Exception {
JSONObject data = UserInformationProvider.getUserInformation(request);
return Response.ok().entity(data.toString()).header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization, auth-user")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Max-Age", "9999999").build();
}
Where am I doing wrong?
Related
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();
}
}
I am using Spring boot with Jersey 2.1
and Ionic to develop an App, I've tried every single post I've found but none solved this problem for me the error I am getting, including those which say about creating the #PATCH interface annotation yourself.
So, the thing is I am getting this error on the client side when testing on the browser when doing a PATCH request:
Access to XMLHttpRequest at '' from origin 'http://localhost:8100' has
been blocked by CORS policy: Method PATCH is not allowed by
Access-Control-Allow-Methods in preflight response.
The filters I have for the response is the following, I don't understand why I'm getting this if I have PATCH as an allowed method and it works perfectly on Postman:
Filter:
#Provider
public final class ResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.putSingle("Accept-Patch", "*");
headers.putSingle("Access-Control-Allow-Origin", "*");
headers.putSingle("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE, PATCH");
headers.putSingle("Access-Control-Allow-Credentials", "true");
headers.putSingle("Access-Control-Max-Age", "3600");
headers.putSingle("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
}
}
Method which uses PATCH:
import javax.ws.rs.PATCH;
#PATCH
#Path("/{username}")
#Produces(MediaType.APPLICATION_JSON)
public Response actualizarPassword(#Valid #NotNull(message = "user must not be null") final UserDTO userDTO,
#PathParam("username") final String username,
#QueryParam("codigo") #NotNull(message = "codigo musnt be null") final String codigo) {
userDTO.setUsername(username);
this.usersService.actualizarPassword(this.userDTOMapper.map(userDTO), codigo);
return Response.noContent().build();
}
As I said, I also tried to create an annotation with PATCH as I read in some answers but this http method is supposed to be included on Jersey 2.1 and it indeed is as it can be see in the previous piece of code, the interface I created was:
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#HttpMethod("PATCH")
public #interface PATCH {
}
And if I do a POSTMAN request, these are the headers I get:
Accept-Patch →*
Access-Control-Allow-Origin →*
Access-Control-Allow-Methods →POST, PUT, GET, OPTIONS, DELETE, PATCH
Access-Control-Allow-Credentials →true
Access-Control-Max-Age →3600
Access-Control-Allow-Headers →Content-Type, Accept, Authorization
X-Content-Type-Options →nosniff
X-XSS-Protection →1; mode=block
Cache-Control →no-cache, no-store, max-age=0, must-revalidate
Pragma →no-cache
Expires →0
X-Frame-Options →DENY
Content-Type →application/json
Content-Length →54
Date →Wed, 07 Nov 2018 07:46:45 GMT
And incase it's somehow related, this is my SpringSecurity config:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
}
#Override
public void configure(WebSecurity web ) throws Exception
{
web.ignoring().antMatchers( HttpMethod.OPTIONS, "/**" );
}
}
UPDATE 1
I've printed the code that the response has and I get a 200. However, I keep getting this error.
UPDATE 2
As requested by sideshowbarker, I made an OPTIONS request with POSTMAN and this is the headers:
Allow →HEAD,GET,OPTIONS,PUT,PATCH
Last-modified →Wed, 07 Nov 2018 10:07:57 GMT+01:00
Accept-Patch →*
Access-Control-Allow-Origin →*
Access-Control-Allow-Methods →POST, PUT, GET, OPTIONS, DELETE, PATCH
Access-Control-Allow-Credentials →true
Access-Control-Max-Age →3600
Access-Control-Allow-Headers →Content-Type, Accept, Authorization
Content-Type →application/vnd.sun.wadl+xml
Content-Length →1165
Date →Wed, 07 Nov 2018 09:07:57 GMT
UPDATE 3
I checked the headers in dev tools as suggested by and the PATCH method isn't there. Why is this? Why is it there if I use POSTMAN but not with my Ionic App?
Please help, I've been struggling with this for days...
Thanks
Okay I am so idiot that I can't even believe it myself. I was using [this plugin for Chrome] 1
which was modifying the headers from the response. Noticed it thanks to #sideshowbarker . It's such an idiot thing but that I bet it might happen to other people too.
Thanks alot #sideshowbarker.
I had same issue as well. I had a chrome CORS plugin enabled for CORS, and seems it's modifying the header before making a request. Disabling it just worked, such a blunder :)
When I send a POST request to the server I get an error:
Failed to load http://localhost:8181/test: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.
The backend is written in Java Spring.
My method for creating a test:
createTest() {
const body = JSON.stringify({
'description': 'grtogjoritjhio',
'passingTime': 30,
'title': 'hoijyhoit'
});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
}
)
};
return this._http.post(`${this._config.API_URLS.test}`, body, httpOptions)
.subscribe(res => {
console.log(res );
}, error => {
console.log(error);
});
}
Get Method works, but Post doesn't. They both work in Swagger and Postman. I changed POST method many times. The headers in my code do not work, but I solved the problem with them expanding to Google Chrome. There was only an error:
Response for preflight has invalid HTTP status code 403.
It seems to me that this is not Angular problem. Please tell me how I or my friend (who wrote the backend) can solve this problem.
PROBLEM :
For any Cross-Origin POST request, the browser will first try to do a OPTIONS call and if and only if that call is successful, it will do the real POST call. But in your case, the OPTIONS call fails because there is no 'Access-Control-Allow-Origin' response header. And hence the actual call will not be done.
SLOUTION :
So for this to work you need to add CORS Configuration on the server side to set the appropriate headers needed for the Cross-Origin request like :
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "content-type, if-none-match");
response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Max-Age", "3600");
You need to ensure that the Spring accept CORS requests
Also if you have applied Spring security & require authorization headers for example for your API, then (only if you need to make your app support CORS) you should exclude the OPTIONS calls from authorization in your spring security configuration file.
It will be something like this:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
#Override
public void configure(WebSecurity web) throws Exception {
// Allow OPTIONS calls to be accessed without authentication
web.ignoring()
.antMatchers(HttpMethod.OPTIONS,"/**")
Note:
In production, probably it is better to use reverse proxy (like nginx) & not allow the browsers to call your API directly, in that case, you don't need to allow the OPTIONS calls as shown above.
I've had the exact same problem with Angular lately. It happens because some requests are triggering preflight requests eg. PATCH, DELETE, OPTIONS etc. This is a security feature in web browsers. It works from Swagger and Postman simply because they don't implement such a feature. To enable CORS requests in Spring you have to create a bean that returns WebMvcConfigurer object. Don't forget of #Configuration in case you made an extra class for this.
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
Of course, you can tune this up to your needs.
I'm having some problems using basic HTTP Authentication with CORS: We have a node express web server (UI), calling a HTTP API from a Java Dropwizard (Jersey) server, running on the same host.
The API is protected with HTTP basic authentication, and I''ve implemented the following filter on my Jersey server (taken from this post: How to handle CORS using JAX-RS with Jersey):
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "http://localhost:9000");
response.getHeaders().add("Access-Control-Allow-Headers",
"Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
However, when I try to load the web UI, my console gives me the following output:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:9000/intraday/parameters. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://localhost:9000’)
I'm unable to make sense of this error. Clearly the origin is the same (http://localhost:9000), so I don't get why it doesn't match.
I've also made sure that any preflighted OPTIONS requests are answered with HTTP code 200.
From the description in the question, it sounds like the Java Dropwizard (Jersey) server is running on http://localhost:9000 and the node express web server (UI) is running at another origin.
Regardless, you must set the value of the Access-Control-Allow-Origin response header in the CORSFilter code on the Jersey server to the origin of the frontend JavaScript code that’s making the request (apparently the node server). So if that’s, e.g., http://localhost:12345, then:
response.getHeaders().add("Access-Control-Allow-Origin", "http://localhost:12345");
It anyway must be something other than http://localhost:9000, because there’s no way your browser would emit that “disallows reading the remote resource at http://localhost:9000/…” error message if the frontend JavaScript code the request is getting sent from is being served from http://localhost:9000—since in that case it wouldn’t be a cross-origin request and your browser wouldn’t be blocking access to the response.
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
}