I have tried everything. i dont know how to do it. it just doesent work.
I have added "#CrossOrigin" / "#CrossOrigin(maxAge = 3600)" practicaly everywere.
how do i configure java spring to allow cross-origin requests?
This is how my request looks like
$.ajax({
crossOrigin: true,
url: "http://localhost:80/adData",
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (responseSchools) {
//stuff
},
error: function (request, status, error) {
//stuff
}
});
Code of Java app
#GetMapping
#CrossOrigin
#RequestMapping(value = AD_DATA_ENDPOINT)
public String getAdData() {
return "wuwuwu";
}
A rather pedestrian, but working approach is to overwrite the header from within the handling method:
// remember to add an `HttpServletResponse response` parameter
response.setHeader("Access-Control-Allow-Origin", "*");
This however is a per-handler solution. On the bright side, it works for any and all headers: whatever Spring was going to do for you, you can always overwrite it in the handler itself.
After searching a lot for this I found the solution for this:
There is no problem in the code, since you are using Cross Origin request it first sent OPTIONS request to the server. In order to fix this I added following piece of code in my server configuration section:
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
Also create a file with following code:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
I am sure this will solve your problem ;)
First of all, most servers allow GET requests from everywhere. Second, there are multiple ways of handling CORS requests on your server.
#CrossOrigin annotation (which allows GET, HEAD a d POST methods by default) can be placed on your Controllers or your Controller Class.
A CORS Filter can be used which will allow OPTIONS requests.
Using WebMvConfigurer, you can specify your configuration.
Find more details here : https://spring.io/guides/gs/rest-service-cors/
Add below maven dependency
<!-- https://mvnrepository.com/artifact/com.thetransactioncompany/cors-filter -->
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.6</version>
</dependency>
And add below line into web.xml
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, PATCH, DELETE, OPTIONS</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
this solves my problem.
Related
I am new to spring webmvc plz bear with me and I am not able to post exactly what to ask due to my lack of understanding on this subject. All I can say is spring mvc file extentions.
inherited maven + spring webmvc 5.1.2.RELEASE project
deployed mvn built fooapp.war to tomcat 8.5.58 on linux platform
The question I have is when I fire rest api call in a browser for the /mail/{address} endpoint.
Case 1)
Without / at the end of uri, it returns http status 406 - The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request, and the server is unwilling to supply a default representation.
http://localhost:<port>/fooapp/mail/john#bar.com
Case 2)
However with / at the end of uri, it returns proper response in json format.
http://localhost:<port>/fooapp/mail/john#bar.com/
I was not able to formulate a proper question to start with not understanding its cause but I did my best searching for a clue from www. I came to many threads but these caught my eyes:
How to change spring request mapping to disallow url pattern with suffix
Spring MVC; avoiding file extension in url?
This is what I tried.
Frist replaced / with /* for url-pattern in the web.xml.
<servlet>
<servlet-name>fooapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:fooapp.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fooapp</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
From the fooapp.xml, <mvc:path-matching suffix-pattern="false"/> is added.
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false"/>
</mvc:annotation-driven>
And the watered down version of FooController.java.
#RestController
#RequestMapping("/mail/{address}")
public final class FooController {
#RequestMapping(method = RequestMethod.GET, produces = "application/json")
public String doSomething(
#PathVariable("address") String address, HttpServletResponse response) {
// execute code...
return josnData;
}
Not knowing what I am doing my attempts didn't change the outcome. Why .com vs .com/ is treated differently? And how to get a proper response back with .com?
update
I may found a clue: Spring does not ignore file extension
will give a try what it says.
With ^ suggestion, I was able to avoid http status 406 however when the FooController consume email address, it chops off .com so that data associated with the eamil address is not returned.
The suggestion I tried was adding following content to fooapp.xml.
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
</bean>
Found a solution
With this article: https://www.baeldung.com/spring-mvc-pathvariable-dot
By adding mail/{address:.+} in the controller along with ^ solution together fixed the problem.
I am trying to hack around on a project that requires CORS. When I request the Java Spring Rest API, I receive:
No 'Access-Control-Allow-Origin' header is present on the requested resource
My stack is quite simple. I am using Java Spring with Tomcat. On the front end, I am making the request with jquery.
I do not see any logs from Spring regarding this and haven't seen any action in the threads shown in the debugger for the java spring application (making it really hard to debug where this is being blocked).
As far as my spring resource class, Ive included the cross origin annotation (#CrossOrigin()) on top of the class. Ive also tried putting that same annotation on the methods for the resource as well (without any luck). As a long shot, I also tried putting in some configuration within a new web.xml file to configure a CORS filter the old fashioned way:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The last detail that I would like to add is that when I make a non-CORS request to the previously mentioned APIs (with CORS annotations on them), I do not see any headers returned that are related to allowing all or any specific origin. This makes me wonder if the annotations are being blocked by something.
I realize that without much code and logs, the community cant really help me. I am asking for guidance on how I can debug this. Thank you for helping!
spring version conflict is causing this for you. You may want to check the versions. if versions are not an issue add a class like this.
#Component
public class MyCORSFilter implements Filter {
#Override
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);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
There is a simpler way to verify. You can use the postman or open the F12 developer tool to see the response body of the request(Request with non CORS). If the Response header has access-control-allow-origin:*, it means the setting is successful, and then check if there is an OPTION request, because the browser will not directly request the request, but will Send an OPTION request to see if the site supports CORS. If the OPTION request is indeed sent, if the response code of this request is not 200, it will cause CORS failure, so you only need to respond to this OPTION request correctly.
for some weird reason, Tomcat 8 (on a w2k12 server) is ignoring my CORS filter settings on tomcat8/conf/web.xml which are as follows, according to the Apache Tomcat 8 docs:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
It does work with GET requests, but when I try to do a POST, i get the 403 Forbidden error saying:
Origin http://webapp.mycompany.com is not allowed by Access-Control-Allow-Origin.
Where http://webapp.mycompany.com is my company's hosting provider with standard features you get with a shared hosting with cpanel, my front-end is there and it send the requests to another domain where I have the Tomcat 8 Server installed and the webapp WAR which is a Jersey-based REST Api.
Now, according to the defaults in Apache's official documents, that configuration I'm using is the minimum required for it to work.
I tried then moving the filters to the application's web.xml instead, no luck, tried adding more configurations like methods allowed, tried adding the headers in the responses directly like this:
Response.status(Response.Status.OK)
.entity(relaciona)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD")
.header("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept")
.header("Access-Control-Max-Age", "1728000")
.build();
Didn't work.
Any help on this would be greatly appreciated, and just to confirm, tried the following:
Tried setting the configuration in both the server and the webapp web.xml files individually, no luck
Tried adding the headers to each response in the Jersey REST Api, no luck
The requests to the API are done with an HTML5 frontend with bootstrap and jQuery, tried adding the crossDomain:true to the ajax requests, no difference.
Added the origin domain to the xml in both web and server web.xml files (tested individually) and neither worked
Thanks!
once you are querying a POST with crossdomain, you need to define #OPTION for #POST /#PUT / #DELETE queries.
Have you defined #Option class in order to define your #Post?
here is an example on how to do so:
#OPTIONS
#Compress
#Path("/mypost")
#Consumes({ MediaType.MULTIPART_FORM_DATA })
#Produces({ MediaType.APPLICATION_JSON })
public Response mypost_opts() {
return Response.ok().build();
}
#POST
#Compress
#Path("/mypost")
#Consumes({ MediaType.MULTIPART_FORM_DATA })
#Produces({ MediaType.APPLICATION_JSON })
public Response mypost() {
return Response.ok().build();
}
I am using restful web services using java
#Path("/data")
public class StudentDataService {
StudentInfo st=new StudentInfo();
#GET
#Path("/mydata")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<Student> findAll() {
System.out.println("data returned to the web service");
return st.populateData();
}
}
I am returning a list of data containing student name,id,marks, etc.
trying to call this method with jQuery ajax as follows:
function findAll() {
console.log('findAll');
$.ajax({
type: "GET",
url: "http://localhost:9297/StudentData/rest/data/mydata",
dataType: "json",
crossDomain: true,
success: function(resp){
// we have the response
alert("Data\n '" + resp + "'");
},
error: function(e){
alert('Error: ' + e);
}
});
}
I am getting error
also it is giving error on console like "no elements found"
"getting exception: javax.ws.rs.WebApplicationException: com.sun.jersey.api.MessageException: A message body writer for Java class java.util.ArrayList, and Java type java.util.List<dao.Student>, and MIME media type application/json was not found""
You seem to missing a JSON provider. If you are using Maven, you can add this dependency
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
If you're not using Maven, go look for these jars
You can search for and download all the jars here
Then you can register the provider, by adding the Jackson package to your packages to scan (in your web.xml configuration)
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>
your.packages.to.scan,
com.fasterxml.jackson.jaxrs.json
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Use javax.ws.rs.core.Response object and build the output. Else have your own wrapper class and wrap your output and return the wrapper class back to response.
I recommend you to use gson for working with json on server side, because it's very easy to use. For example:
List<Student> items = new ArrayList<>();
while (...) {
items.add(new Student(...));
}
Gson gson = new Gson();
return gson.toJson(items);
This is just an example, adopt this to your requirements.
You might be running into a cors issue. Since you're trying to get type application/json back from the server and your request is crossDomain. If you wrap your jax-rs method with a Response object like #user1129947 suggested, you can modify the headers of the response to allow a cross-origin request like so:
import javax.ws.rs.core.Response;
#Path("/data")
public class StudentDataService {
StudentInfo st=new StudentInfo();
#GET
#Path("/mydata")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response findAll() {
return Response.ok(st.populateData())
.header("Access-Control-Allow-Origin", "*")
.build();
}
}
The header Access-Control-Allow-Origin: * will now be on the response which will tell the browser that it is allowed to receive application/json data.
Please be aware that the * parameter in the header allows any domain to access this resource
If you want to be sure that only your domains can access this resource then you must set the value of the header to a specific domain.
If you use custom headers or you end up wanting to send cookies to the server then you'll have to deal with preflighted requests which is beyond the scope of this answer.
See Mozilla's documentation on CORS for more information
Bonus Edit:
For anyone using CDI with JAX-RS you can check out this filter-interceptor combo for dealing with CORS
I'd like to intercept the OPTIONS request with my controller using Spring MVC, but it is catched by the DispatcherServlet. How can I manage that?
I added some more detail to the Bozho answer for beginners.
Sometimes it is useful to let the Spring Controller manage the OPTIONS request (for example to set the correct "Access-Control-Allow-*" header to serve an AJAX call).
However, if you try the common practice
#Controller
public class MyController {
#RequestMapping(method = RequestMethod.OPTIONS, value="/**")
public void manageOptions(HttpServletResponse response)
{
//do things
}
}
It won't work since the DispatcherServlet will intercept the client's OPTIONS request.
The workaround is very simple:
You have to... configure the DispatcherServlet from your web.xml file as follows:
...
<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
...
Adding the "dispatchOptionsRequest" parameter and setting it to true.
Now the DispatcherServlet will delegate the OPTIONS handling to your controller and the manageOption() method will execute.
Hope this helps.
PS. to be honest, I see that the DispatcherServlet append the list of allowed method to the response. In my case this wasn't important and I let the thing go. Maybe further examinations are needed.
#RequestMapping(value="/youroptions", method=RequestMethod.OPTIONS)
public View getOptions() {
}
You should configure the dispatcherServlet by setting its dispatchOptionsRequest to true
As a quick supplement to the above 2 answers, here's how to enable dispatchOptionsRequest in a servlet 3 (no web.xml) environment as it took me a while to work out how to apply the answers above in a non-xml setup.
In a spring 3.2 / servlet 3 environment, you will have some variety of DispatcherServlet initializer class which is the java equivalent of web.xml; in my case it's the AbstractAnnotationConfigDispatcherServletInitializer. Adding the following code will enable dispatchOptionsRequest:
#Override
protected void customizeRegistration(Dynamic registration) {
registration.setInitParameter("dispatchOptionsRequest", "true");
}
I took the following approach:
Using Maven (or manually) pull in this dependancy:
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>1.3.2</version>
</dependency>
This has an implementation to capture all the inbound OPTIONS requests. Into the web.xml file add the following config:
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Content-Type,Accept,Origin</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The problem I've seen with the /** approach is a more specific Controller implementation will override this.
For Spring without web.xml file, and based on Paul Adamson answer, I just set the parameter dispatchOptionsRequest to true into the dispatcher, to process the Options method calls.
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(applicationContext));
dispatcher.setInitParameter("dispatchOptionsRequest", "true");
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");