3
I have been trying for a while to configure CORS to work with my Tomcat 8. But whenever I have to submit the POST request, I get the error message:
"Response to preflight request doesn’t pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested Resource. Origin 'http://rafael.etc' is therefore not allowed access."
web.xml
:
<display-name>apirestex</display-name>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>br.com.resource.api</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>/*</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
pom.xml
:
<dependencies>
<!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-server -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>java-property-utils</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
Resource:
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
@Path("/usuarios")
public class UsuarioResource {
@Path("/save")
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void save(String conteudo){
//Usuario usuario = Usuario.jsonToUser(conteudo);
System.out.println(conteudo);
/*return Response.status(200) //200
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia,Authorization")
.build();*/
}
}
Ajax request:
$(document).ready(function (){
$('#command').on('click', function(){
var user = {
name: $('#name').val(),
secondName: $('#secondName').val(),
sex: $('#sex').val(),
acessLevel: $('#acessLevel').val(),
email: $('#email').val(),
telefone: $('#telefone').val(),
login: $('#login').val(),
password: $('#password').val()
}
$.ajax({
url:'http://localhost:8282/apirestex/servlet/usuarios/save',
data:user,
contentType: "application/json; charset=utf-8",
dataType: 'json',
type:'POST',
crossDomain: true,
async:true,
success: function() { console.log("Success!!!"); },
error: function() { console.log('Failed!'); },
});
});
});
UPDATE 1
The class MyApplication
:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
// register resources and features
classes.add(UsuarioResource.class);
return classes;
}
}
In the web.xml
:
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>br.com.resource.api.MyApplication</param-value>
</init-param>
UPDATE 2
Myapplication - I added the annotation "@Applicationpath("/")". I changed the Myapplication of package.
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import br.com.resource.api.UsuarioResource;
@ApplicationPath("/")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
// register resources and features
classes.add(UsuarioResource.class);
return classes;
}
}
web xml.
<!-- Register JAX-RS Application, if needed. -->
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>br.com.app.api.MyApplication</param-value>
</init-param>
<!-- Register resources and providers under my.package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>br.com.resource.api</param-value>
</init-param>
Now the error returned is:
GRAVE: Servlet.service() for Servlet [br.com.app.api.Myapplication] in context with path [/apirestex] threw Exception [Servlet Execution threw an Exception] with root cause java.lang.abstractmethooverthrow: javax.ws.rs.core.Uribuilder.Uri(Ljava/lang/String;)Ljavax/Ws/rs/core/Uribuilder; at javax.ws.rs.core.Uribuilder.fromUri(Uribuilder.java:119) at com.sun.jersey.spi.container.servlet.Servletcontainer.service(Servletcontainer.java:662) at javax.servlet.http.HttpServlet.service(Httpservlet.java:729) at org.apache.Catalina.core.Applicationfilterchain.internalDoFilter(Applicationfilterchain.java:292) at org.apache.Catalina.core.Applicationfilterchain.doFilter(Applicationfilterchain.java:207) at org.apache.Tomcat.websocket.server.WsFilter.doFilter(Wsfilter.java:52) at org.apache.Catalina.core.Applicationfilterchain.internalDoFilter(Applicationfilterchain.java:240) at org.apache.Catalina.core.Applicationfilterchain.doFilter(Applicationfilterchain.java:207) at br.com.web.api.Opencorsfilter.doFilter(Opencorsfilter.java:30) at org.apache.Catalina.core.Applicationfilterchain.internalDoFilter(Applicationfilterchain.java:240) at org.apache.Catalina.core.Applicationfilterchain.doFilter(Applicationfilterchain.java:207) at org.apache.Catalina.core.Standardwrappervalve.invoke(Standardwrappervalve.java:212) at org.apache.Catalina.core.Standardcontextvalve.invoke(Standardcontextvalve.java:106) at org.apache.Catalina.authenticator.Authenticatorbase.invoke(Authenticatorbase.java:502) at org.apache.Catalina.core.Standardhostvalve.invoke(Standardhostvalve.java:141) at org.apache.Catalina.valves.Errorreportvalve.invoke(Errorreportvalve.java:79) at org.apache.Catalina.valves.Abstractaccesslogvalve.invoke(Abstractaccesslogvalve.java:616) at org.apache.Catalina.core.Standardenginevalve.invoke(Standardenginevalve.java:88) at org.apache.Catalina.connector.Coyoteadapter.service(Coyoteadapter.java:528) at org.apache.Coyote.http11.Abstracthttp11processor.process(Abstracthttp11processor.java:1100) at org.apache.Coyote.Abstractprotocol$Abstractconnectionhandler.process(Abstractprotocol.java:687) at org.apache.Tomcat.util.net.Nioendpoint$Socketprocessor.doRun(Nioendpoint.java:1520) at org.apache.Tomcat.util.net.Nioendpoint$Socketprocessor.run(Nioendpoint.java:1476) at java.util.Concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.Concurrent.Threadpoolexecutor$Worker.run(Unknown Source) at org.apache.Tomcat.util.threads.Taskthread$Wrappingrunnable.run(Taskthread.java:61) at java.lang.Thread.run(Unknown Source)
SOLVED
The problem that caused the internal server error (500) was that the version of Jersey (1.9) I was using was not compatible with JAX-RS 2.0.(https://stackoverflow.com/questions/30176811/abstractmethoderror-using-uribuilder-on-jax-rs) The version has been amended.
Myapplication
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import br.com.resource.api.UsuarioResource;
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
// register resources and features
classes.add(UsuarioResource.class);
return classes;
}
}
Corsfilter - Adaptation of the Opencorsfilter class to work with Jersey 2
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
@Provider
public class CORSFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext creq, ContainerResponseContext cres) {
cres.getHeaders().add("Access-Control-Allow-Origin", "*");
cres.getHeaders().add("Access-Control-Allow-Headers", "Authentication, Content-Type, X-Requested-With, X-Codingpedia");
cres.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
cres.getHeaders().add("Access-Control-Allow-Credentials", "true");
cres.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
cres.getHeaders().add("Access-Control-Max-Age", "1209600");
}
}
User resource
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/usuarios")
public class UsuarioResource {
@Path("/save")
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response save(String conteudo){
System.out.println(conteudo);
return Response.status(200)
.build();
}
}
pom.xml - dependences
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.25.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
web.xml - final
<display-name>apirestex</display-name>
<servlet>
<servlet-name>br.com.app.api.MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<!-- Register JAX-RS Application, if needed. -->
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>br.com.app.api.MyApplication</param-value>
</init-param>
<!-- Register resources and providers under my.package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>br.com.resource.api</param-value>
</init-param>
<!-- Register my custom provider (not needed if it's in my.package) AND LoggingFilter. -->
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>br.com.web.api.CORSFilter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>br.com.app.api.MyApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Ajax request
$.ajax({
url:'http://localhost:8282/apirestex/servlet/usuarios/save',
data: JSON.stringify(user),
type:'POST',
crossDomain: true,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
async:true,
success: function() { console.log("Success"); },
error: function() { console.log();('Failed!'); },
});
I made the suggested changes and had a breakthrough. Before my request stopped in OPTIONS that is sent before the POST, now it passes this part. But I get a 404 as a response and the System.out.println I put in my Source does not run. I even changed my Source so that it sends one javax.ws.rs.core.Response.status(200). build() instead of void or String, but I kept getting 404. Which leads me to believe that my Source is actually not being accessed. Did something wrong in URI or Resource?
– Rafael Dias
@Rafaeldias If you put the project having the root in
http://localhost:8282/apirestex
, should work. However, the CORS error message speaks of a different URL:http://rafael.etc
– Victor Stafusa
Good afternoon @Victor Stafusa. Thanks for your help. Yes, I put it in the root. Being "apirestex" the project name, "Servlet" the <Servlet-name> configured in web.xml, "users" the resource path, and "save" the method name within the resource. I think there might be something related to me registering the resource in some way to be recognized by Jersey.
– Rafael Dias
@Rafaeldias You have in your project some class that inherits from
javax.ws.rs.core.Application
? Also, if you try to open the URL in the browserhttp://localhost:8282/apirestex
directly, what happens? If a 4XX error occurs, it means the server is running. If you give "Can’t connect" or something like that, then the server is running in the wrong place.– Victor Stafusa
@Rafaeldias After your question update, it still doesn’t work?
– Victor Stafusa
EDIT @Victorsatafusa Another advance. After a few more modifications (I will update) now returns me an error 500. It seems the problem is that the version of Jersey (1.9) I am using is not compatible with JAX_RS 2.0. I will change the version. http://stackoverflow.com/questions/30176811/abstractmethoderror-using-uribuilder-on-jax-rs
– Rafael Dias