Can Spring autogenerate an 'Allow' header on an OPTIONS method?

checketts picture checketts · Jan 3, 2014 · Viewed 7.2k times · Source

When I configure my RequestMappings in Spring MVC, I'd like to automatically generate the proper Allow header when the OPTIONS method is used.

For example, with this controller:

@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping(method = RequestMethod.GET)
    ResponseEntity<String> getTest() {
        return new ResponseEntity<>("test", HttpStatus.OK);
    }
}

Right now if I do an OPTIONS request to that URL I get a 405, method not allowed. Instead I'd like it to automatically respond with

Allow: GET, OPTIONS and 204 - No content

I've got one idea adding an interceptor like so:

@Override 
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new HandlerInterceptor() {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if("OPTIONS".equalsIgnoreCase(request.getMethod())){
                response.setHeader("Allow", "GET, OPTIONS");
                response.setStatus(204);
                //TODO figure out the @Controller and what possible methods exist
                return false;
            }
            return true;
        }
        //Deleted excess methods for brevity
    });
}

Does this functionality exist without me writing a custom interceptor? If not, how might I solve the TODO and lookup what annotations exist on the same URL the OPTIONS call had happened on?

Answer

checketts picture checketts · Jan 3, 2014

To extend on Sotiros' and jhadesdev's answers. If using Java Config (like in Spring Boot) you can configure the DispatchServlet to enable OPTIONS request by configuring a @Bean like so:

@Bean
public DispatcherServlet dispatcherServlet() {
    DispatcherServlet servlet = new DispatcherServlet();
    servlet.setDispatchOptionsRequest(true);
    return servlet;
}

I then created a static helper that accepts HttpMethods varargs like so:

public static ResponseEntity<Void> allows(HttpMethod... methods) {
    HttpHeaders headers = new HttpHeaders();
    Set<HttpMethod> allow = new HashSet<>();
    for(HttpMethod method: methods){
        allow.add(method);
    }
    headers.setAllow(allow);

    return new ResponseEntity<>(headers, HttpStatus.NO_CONTENT);
}

This makes it simple to create my own OPTIONS mappings like so:

@RequestMapping(method = RequestMethod.OPTIONS)
ResponseEntity<Void> getProposalsOptions() {
    return allows(HttpMethod.GET, HttpMethod.OPTIONS);
}

While I think it makes sense that Spring MVC could provide OPTIONS responses automatically, you can't do it via an Interceptor, but possibly via a custom DispatcherServlet.

The benefit of writing your own OPTIONS response is that it makes sense to customize the OPTIONS in some cases based on the user's roles. For example an unauthenticated user of the API may receive Allow GET, OPTIONS but an admin would get the full API Allow GET, PUT, DELETE, OPTIONS You would customize the response based on examining a user's roles when making the OPTIONS call.