Как обрабатывать запросы HTTP OPTIONS в Spring Boot?

Во-первых, я прочитал «Как обрабатывать ОПЦИИ HTTP с помощью Spring MVC?», но ответы не кажутся применимыми напрямую в Spring Boot.

Похоже, я должен сделать это:

настройте dispatcherServlet, установив его dispatchOptionsRequest на true

Но как это сделать, учитывая, что у меня нет конфигураций XML или каких-либо классов инициализатора DispatcherServlet в моем коде (упомянутый в этом ответе)?

В классе @RestController у меня есть такой метод, который в настоящее время не вызывается.

@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; простая настройка, не сильно отличающаяся от той, что в руководстве по Spring REST.


person Jonik    schedule 25.10.2015    source источник
comment
К моему ответу добавлен дополнительный подход к этой проблеме. Также отправлено PR, чтобы можно было настроить это в более Spring Boot путь (через свойства).   -  person Bohuslav Burghardt    schedule 26.10.2015


Ответы (3)


Вариант 1. Свойства Spring Boot (только Spring Boot 1.3.0+)

Начиная с Spring Boot 1.3.0 это поведение можно настроить с помощью следующего свойства:

spring.mvc.dispatch-options-request=true

Вариант 2: Пользовательский DispatcherServlet

DispatcherServlet в Spring Boot определяется DispatcherServletAutoConfiguration. Вы можете создать свой собственный DispatcherServlet bean-компонент где-нибудь в ваших классах конфигурации, который будет использоваться вместо того, который используется в автоконфигурации:

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

Но имейте в виду, что определение вашего DispatcherServlet bean-компонента отключит автоконфигурацию, поэтому вам следует вручную определить другие bean-компоненты, объявленные в классе автоконфигурации, а именно ServletRegistrationBean для DispatcherServlet.

Вариант 3: BeanPostProcessor

Вы можете создать BeanPostProcessor реализацию, которая установит для атрибута dispatchOptionsRequest значение true перед инициализацией компонента. Йой, можете поместить это где-нибудь в свои классы конфигурации:

@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;
    }
}

Вариант 4: SpringBootServletInitializer

Если бы в вашем приложении было SpringBootServletInitializer, вы могли бы сделать что-то вроде этого, чтобы включить отправку OPTIONS:

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");
    }
}

Однако это будет работать только в том случае, если вы развернете свое приложение как WAR в контейнере сервлетов, поскольку код SpringBootServletInitializer не выполняется при запуске приложения Spring Boot с использованием метода main.

person Bohuslav Burghardt    schedule 25.10.2015
comment
Важное обновление: запросы OPTIONS будут поддерживаться по умолчанию, начиная с Spring Framework 4.3 (используется по умолчанию для предстоящего выпуска Spring Boot 1.4), см. jira.spring.io/browse/SPR-13130 ​​ для получения дополнительных сведений. - person Sébastien Deleuze; 27.04.2016

Я столкнулся с этой проблемой с приложением для отдыха на основе Spring Boot 1.3.x, и при диагностике проблемы я разрешил моему Spring Tool Suite обновиться до последней версии.

Когда я создал новый тестовый Spring Boot RestController в обновленной STS, он работал так, как рекламируется в документации в Spring 4.3. Я заметил, что зависимость Maven перешла на весеннюю загрузку 1.5.8 в новом тестовом приложении, поэтому я просто изменил зависимость для старого приложения, чтобы обновить его до весенней загрузки 1.5.8 / spring 4.3.12. Это устранило проблему, и теперь она работает, как было объявлено, с аннотацией RequestMapping, указывающей интерес в обработке запросов OPTIONS ...

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

... теперь отправляет обработчику запрос OPTIONS.

Итак, если вы можете выполнить обновление до более поздней версии Spring, вам не нужно определять какие-либо специальные конфигурации, чтобы включить обработку метода запроса OPTIONS (Spring 4.3.12 / Spring Boot 1.5.8).

person beaudet    schedule 13.11.2017
comment
Я полагаю, что это обычно не то, что нужно. Запросы OPTIONS чаще всего являются предполетными запросами CORS, и они не должны работать так же, как реальный запрос. - person hgoebl; 21.11.2017
comment
Я согласен. Обработка OPTIONS с помощью контроллера - это не то, чем я на самом деле закончил, поскольку более поздние версии Spring автоматически обрабатывают предполетные запросы через аннотацию Crossorigin, и это обычно то, что нужно. Получение OPTIONS для обработки обработчиком было всего лишь шагом на пути к использованию аннотации Crossorigin. В качестве побочного примечания, если вы пишете тесты для метода OPTIONS и задаетесь вопросом, почему не возвращаются заголовки CORS, вам необходимо установить некоторые заголовки запросов, чтобы это произошло, как минимум Origin и метод-запроса-контроля доступа. - person beaudet; 24.11.2017

Вы можете легко добавить собственный метод OPTIONS в StrictHttpFirewall с помощью Spring Boot 2.2.6:

@Bean
public StrictHttpFirewall httpFirewall() {

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

    return firewall;
}
person ron190    schedule 25.04.2020