No resource method found for options, return OK with Allow header: org.jboss.resteasy.spi.DefaultOptionsMethodException

Viewed 6869

I am trying to make a post request from my Ionic 3 application to a Java resource but it bursts that error that is in the title, below is the method for which I am making the request:

@POST
@Path("/loginCpf")
@Produces(MediaType.APPLICATION_JSON)
public Integer validarBeneficiarioCpf(BeneficiarioLoginTO beneficiario) throws Exception, TypeWarnWebException {
    HttpSession session = (HttpSession) request.getSession(true);
    Integer numOpcoes = beneficiarioLoginNegocio.validarCpfLogin(beneficiario);
    if(session.getAttribute("beneficiario") == null && numOpcoes == null){
        return -1;
    }
    return numOpcoes;
}

and the error that throws:

09:32:0 3,649 ERROR [br.gov.transportes.spl.web.exception.provider.ExceptionResourceMapper] (http--0.0.0.0-443-3) No resource method found for options, return OK with Allow header: org.jboss.resteasy.spi.DefaultOptionsMethodException: No resource method found for options, return OK with Allow header
        at org.jboss.resteasy.core.registry.Segment.match(Segment.java:107) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.registry.SimpleSegment.matchSimple(SimpleSegment.java:33) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.registry.RootSegment.matchChildren(RootSegment.java:327) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.registry.SimpleSegment.matchSimple(SimpleSegment.java:44) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.registry.RootSegment.matchChildren(RootSegment.java:327) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.registry.RootSegment.matchRoot(RootSegment.java:374) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.registry.RootSegment.matchRoot(RootSegment.java:367) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.ResourceMethodRegistry.getResourceInvoker(ResourceMethodRegistry.java:307) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.getInvoker(SynchronousDispatcher.java:173) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:118) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:208) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55) [resteasy-jaxrs-2.3.2.Final.jar:]
        at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:50) [resteasy-jaxrs-2.3.2.Final.jar:]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
        at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
        at br.gov.transportes.spl.web.filter.CacheFilter.doFilter(CacheFilter.java:36) [classes:]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
        at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
        at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_79]

This is my Ionic 2 request method:

  getUser() {
     return new Promise((resolve, reject) => {
       const body = {
        'nrCpf': '00000000000',
        'dtNascimento': ''
      };

      let headers = new Headers({
        'Content-Type': 'application/json'
      });

      let options = new RequestOptions({
        headers: headers
      });

      this.http.post(this.API_URL, body, options)
          .subscribe((data: any) => {
            resolve(data);
          }, (err: any) => {
            reject(err);
          });
    }); 
  } 

When I debug my application the request falls into this filter:

@WebFilter("*")
public class CacheFilter implements Filter {


    @Override
    public void init(FilterConfig fConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String page = httpRequest.getRequestURI();


        httpResponse.setHeader("Access-Control-Allow-Origin","*");
        httpResponse.setHeader("Access-Control-Allow-Methods","GET,POST");
        httpResponse.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept");

        if (!page.contains("fontawesome-webfont.eot") && !page.contains("/js/lib/") && !page.contains("/css/")) {
            httpResponse.setHeader("Expires", "-1");
            httpResponse.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
            httpResponse.setHeader("Pragma", "no-cache");
        } else {
            httpResponse.setHeader("Cache-Control", "max-age=" + 604800);
            httpResponse.setDateHeader("Last-Modified", new Date().getTime());
        }
       chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

The error is thrown when the chain.doFilter(request, response); when I make the same requisition with postman the function works, but I make the requisition with the raw data and the content-type with application/json, in my Ionic application I have made the header content-tyoe application/json and thrown the same error.

2 Answers

Well the actual problem occurs because the JavaScript runtime performs a so called "preflight" request using the HTTP OPTIONS method in case of CORS. More details can be found here. If you don't provide an OPTIONS method in your server, this results in the described exception. Thus, you have 2 alternatives to solve this problem:

  1. You create a method annotated with "@OPTIONS" in your REST service like this:

    @OPTIONS
    @Path("/loginCpf")
    public Response optionsBeneficiarioCpf() {
       return Response.ok().header(HttpHeaders.ALLOW, HttpMethod.POST).build();
    }
    
  2. You handle the OPTIONS requests in a generic fashion, for instance within the CORS filter as described here.

Related