How to handle HTTP OPTIONS requests in Spring Boot?
Asked Answered
T

3

40

First off, I've read "How to handle HTTP OPTIONS with Spring MVC?" but the answers do not seem directly applicable to Spring Boot.

It looks like I should do this:

configure the dispatcherServlet by setting its dispatchOptionsRequest to true

But how to do that, given that I have no XML configs, or any variety of DispatcherServlet initializer class in my code (mentioned by this answer)?

In a @RestController class, I have a method like this, which currently does not get invoked.

@RequestMapping(value = "/foo", method = RequestMethod.OPTIONS)
public ResponseEntity options(HttpServletResponse response) {
    log.info("OPTIONS /foo called");
    response.setHeader("Allow", "HEAD,GET,PUT,OPTIONS");
    return new ResponseEntity(HttpStatus.OK);
}

Spring Boot 1.2.7.RELEASE; a simple setup not very different from that in Spring REST guide.

Trader answered 25/10, 2015 at 14:52 Comment(1)
Added additional approach to this problem to my answer. Also submitted PR to allow configuring this in more "Spring Boot way" (via properties).Flue
F
35

Option 1: Spring Boot properties (Spring Boot 1.3.0+ only)

Starting with Spring Boot 1.3.0 this behavior can be configured using following property:

spring.mvc.dispatch-options-request=true

Option 2: Custom DispatcherServlet

DispatcherServlet in Spring Boot is defined by DispatcherServletAutoConfiguration. You can create your own DispatcherServlet bean somewhere in your configuration classes, which will be used instead of the one in auto configuration:

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

But be aware that defining your DispatcherServlet bean will disable the auto configuration, so you should manually define other beans declared in the autoconfiguration class, namely the ServletRegistrationBean for DispatcherServlet.

Option 3: BeanPostProcessor

You can create BeanPostProcessor implementation which will set the dispatchOptionsRequest attribute to true before the bean is initialized. Yoy can put this somewhere in your configuration classes:

@Bean
public DispatcherServletBeanPostProcessor dispatcherServletBeanPostProcessor() {
    return new DispatcherServletBeanPostProcessor();
}

public static class DispatcherServletBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DispatcherServlet) {
            ((DispatcherServlet) bean).setDispatchOptionsRequest(true);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

Option 4: SpringBootServletInitializer

If you had SpringBootServletInitializer in your application you could do something like this to enable OPTIONS dispatch:

public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.getServletRegistration(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
                .setInitParameter("dispatchOptionsRequest", "true");
    }
}

That would however only work if you deployed your app as a WAR into Servlet container, as the SpringBootServletInitializer code is not executed when running your Spring Boot app using main method.

Flue answered 25/10, 2015 at 16:17 Comment(1)
Important update: OPTIONS requests will be supported by default as of Spring Framework 4.3 (used by default for upcoming Spring Boot 1.4 release), see jira.spring.io/browse/SPR-13130 for more details.Pegboard
D
1

You can easily add custom method OPTIONS to StrictHttpFirewall with Spring Boot 2.2.6 :

@Bean
public StrictHttpFirewall httpFirewall() {

    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST", "OPTIONS", "FOO"));

    return firewall;
}
Drupe answered 25/4, 2020 at 20:54 Comment(0)
A
0

I was running into this issue with a Spring Boot 1.3.x based rest app and while diagnosing the problem I allowed my Spring Tool Suite to update to the latest version.

When I created a new test Spring Boot RestController in the updated STS, it worked as the documentation advertises under Spring 4.3. I noticed that the Maven dependency had jumped to spring boot 1.5.8 in the new test app, so I just changed the dependency for the old app to update it to spring boot 1.5.8 / spring 4.3.12. That fixed the issue and now it's working as advertised with a RequestMapping annotation specifying an interest in handling the OPTIONS requests...

@RequestMapping(value="/account/{id}", method={RequestMethod.OPTIONS,RequestMethod.GET})

... now sends the OPTIONS request to the handler.

So, if you are able to update to a later version of Spring, you should have no need to define any special configurations in order enable OPTIONS request method handling (Spring 4.3.12 / Spring Boot 1.5.8).

Alleenallegation answered 13/11, 2017 at 20:52 Comment(2)
I suppose this is typically not what is wanted. OPTIONS requests are most often CORS pre-flight request and they shouldn't work identically as the "real" request.Zoogloea
I agree. Handling OPTIONS with the controller is not what I actually ended up doing since later versions of Spring take care of preflight requests automatically via the Crossorigin annotation and that's generally what one wants. Getting OPTIONS to be processed by the handler was just a step along the path to eventually using the Crossorigin annotation. As a side note, if you're writing tests for the OPTIONS method and wondering why no CORS headers are being returned, you have to set some request headers for that to happen, minimally Origin and access-control-request-method.Alleenallegation

© 2022 - 2024 — McMap. All rights reserved.