Search code examples
ajaxspring-mvccross-domainpreflighthttp-options-method

Handling cross domain preflight AJAX OPTIONS requests with Spring MVC 4


This is probably a simple answer, but I can't seem to get it to work. In a cross-domain, preflight AJAX request, the client first makes an OPTIONS request just get a set of headers back to figure out what the remote server accepts.

Right now, for every Spring controller POST interface that I create, I have to also create an OPTIONS interface, like this:

 @RequestMapping(method = RequestMethod.OPTIONS, value = "/addWebService")
    public ResponseEntity addWebServiceOptions() {
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }

@RequestMapping(method = RequestMethod.POST, value = "/addWebService")
    public AjaxResponse<WebService> addWebService(Principal principal, @RequestBody WebService webService) throws UserServiceException { ... }

I read somewhere that you can just make one simple method that doesn't have a mapping to a specific path to handle all OPTIONS requests, like this:

@RequestMapping(method = RequestMethod.OPTIONS)
    public ResponseEntity handle() {
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }

However, when I add that method, every request I submit states that it can't find a mapping to my requested resource.

Is there a way to handle all OPTIONS requests in a single method without having to create one for every interface I create?


Solution

  • For those interested, it was as simple as adding a request mapping of "/*". I can now remove all other OPTIONS methods from my controllers and handle all preflight OPTIONS requests with this single method:

    @RequestMapping(method = RequestMethod.OPTIONS, value = "/*")
    @ResponseBody
    public ResponseEntity handleOptions() {
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }
    

    Also worth noting, I had to add this to my security config to allow all requests to make the OPTIONS call without receiving a 403 error (and to allow websockets to connect properly):

    http
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/stomp/**").permitAll()
            .antMatchers("/**").hasRole("USER");