Конечная точка Springboot 403 ОПЦИИ при выполнении запроса POST

Я запускаю службу с использованием Spring, и мой интерфейс Angular получает 403 с методом запроса: OPTIONS, когда он пытается сделать запрос POST.

И служба Spring, и приложение Angular работают на моей машине локально. Я попытался переключить CORS с помощью плагина Chrome, но, похоже, это не помогло.

Все мои запросы GET к службе работают нормально. Я могу выполнить запрос POST в Postman, поэтому я не уверен, почему приложение angular не может сделать запрос, но Postman может.

****РЕДАКТИРОВАТЬ****

Заголовки ответа

Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Content-Length: 20
Date: Sat, 31 Mar 2018 19:15:01 GMT

Заголовки запроса

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:9901
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36

почтовый запрос используется с почтовыми данными.

Roman C 25.03.2018 00:58

@RomanC Да, мое приложение angular использует httpClient для выполнения почтового вызова с объектом json.

Nickknack 25.03.2018 01:29

Но не работает

Roman C 25.03.2018 11:45
7
3
12 638
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Ваш интерфейс делает запрос CORS, чтобы узнать, какие методы (HTTP Verbs) разрешены при вашей поддержке. Обычно это требуется для денежных операций, например, POST или PUT, которые предназначены для изменения данных.

Следовательно, ваш Frontend сначала сделает этот вызов, а ваш backend должен ответить разрешенными методами, вы также можете ограничить определенные URI, а затем после успешной проверки будет выполнен целевой вызов.

Это совершенно нормально, и angular делает это внутренне, чтобы не делать ненужных запросов данных, не зная, разрешит ли сервер.

Вот как вы настроите это в Spring.

    //Change/Customize as necessary
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("<your origin>");
        corsConfiguration.setAllowedMethods(Arrays.asList(
                HttpMethod.GET.name(),
                HttpMethod.HEAD.name(),
                HttpMethod.POST.name(),
                HttpMethod.PUT.name(),
                HttpMethod.DELETE.name()));
        corsConfiguration.setMaxAge(1800L);
        source.registerCorsConfiguration("/**", corsConfiguration); // you restrict your path here
        return source;
    }

Если вы также используете какой-либо пользовательский response headers из вашего бэкэнда, вам необходимо разрешить это также в конфигурации CORS. В качестве примера

    corsConfiguration.addAllowedHeader("*");
    corsConfiguration.addExposedHeader("header1");
    corsConfiguration.addExposedHeader("header2");

Поэтому я добавил это объявление Bean в свой класс приложения чуть ниже основного. Я все еще, кажется, получаю ошибку 403 OPTIONS Invalid CORS request, когда пытаюсь выполнить операцию POST. Есть ли что-нибудь, что мне нужно сделать на стороне Angular?

Nickknack 28.03.2018 18:44

Какие заголовки вы получаете в запросе параметров? Прочтение об этом может помочь вам в дальнейшем github.com/spring-projects/spring-security-oauth/issues/938

bitscanbyte 29.03.2018 13:28

Добавил в пост заголовки из неудавшегося запроса :)

Nickknack 31.03.2018 21:18

Если вы хотите добавить это к отправленному вами коду ответа, я отмечу это галочкой! :)

Nickknack 31.03.2018 23:30

В классе corsConfiguration доступны опции maxAge и origins, я добавил эти сеттеры выше.

bitscanbyte 01.04.2018 04:46

Чтобы исправить все проблемы CORS в проекте Angular (передняя часть) и Spring boot (бэкэнд), добавьте следующий компонент Spring:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ConfigCtrl implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        final HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
        response.setHeader("Access-Control-Max-Age", "3600");
        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }
    @Override
        public void destroy() {
    }
    @Override
        public void init(FilterConfig config) throws ServletException {
    }
}

PS для новичков: имя класса и его расположение в приложении Spring значения не имеют.
Кредит Аджитешу Кумару.

Если мы говорим о SpringBoot, предположительно последней или, по крайней мере, последней версии, то мы можем просто использовать аннотацию @CrossOrigin рядом с аннотацией @RestController в наших классах контроллеров. Доступен с версии Spring ver. 4.2

Например:

@RestController
@CrossOrigin
@RequestMapping("/api")
public class MyObjectsController {
    private final MyObjectsService service;

    @Autowired
    public MyObjectsController(MyObjectsService service) {
        this.service = service;
    }

    @GetMapping("/version")
    public Version getVersion() {
        return service.getVersion();
    }

    @PostMapping("/objects")
    public ObjectResource createObject(@RequestBody @Valid ObjectData data) {
        return service.createObject(data);
    }

    @GetMapping("/objects/{id}")
    public ObjectResource getObject(@PathVariable String id) {
        return service.getObjectById(id);
    }
}

Преимущества:

  • аннотированный контроллер ведет себя лучше (и умнее), чем любые самописные фильтры
  • он также более гибок, чем фиксированная конфигурация CORS для всего проекта, поскольку вы можете контролировать, какая часть вашего API должна поддерживать заголовки CORS, а какая должна быть доступна только для межсерверной связи.
  • только методы, поддерживаемые контроллером, будут объявлены и разрешены в ответе на запрос OPTIONS
  • Заголовки CORS будут присутствовать только в ответе на запросы CORS (т.е. анализируется наличие заголовка Referer)
  • и т.п.

Смотрите также:

Другие вопросы по теме