Ajax POST приводит к ошибке 405 (метод запрещен) - Spring MVC

Я пытаюсь выполнить ajax-вызов моего контроллера / действия Spring с помощью метода POST и вернуть объект с сервера с помощью @ResponseBody. Странная ситуация заключается в том, что он перестает работать после добавления уровня безопасности Spring, раньше все работало нормально. Я постараюсь объяснить свои шаги по решению проблемы, а затем покажу вам код / ​​снимки / и т. Д.

1. После некоторого исследования я нашел ответы о том, что проблема может быть связана с механизмом csrf, поэтому я отключил его, но проблема не исчезла. (ниже spring-security.xml)

2. Я сделал снимок wirehark, чтобы проверить запрос / ответ. Мой запрос ajax в порядке, мое объявление контроллера в порядке, но я не понимаю, почему, в ответе 405 указано> Разрешить: GET (снимок ниже)

3. Я попытался получить доступ к своему действию контроллера через браузер (т. Е. Сделать запрос GET) и получил сообщение об ошибке HTTP-статус 405 - метод запроса «GET» не поддерживается!

4. Я попытался изменить RequestMapping (метод ...) на RequestMethod.GET, и запрос доходит до контроллера и работает нормально, но я не хочу, чтобы он работал с методом GET, мне нужен запрос POST.

5. Изменено RequestMapping (потребляет, производит, заголовки), чтобы принимать все виды данных, но все еще 405 ...

Это сводит меня с ума! Я размещаю свои файлы ниже, так что вы можете проверить это, ребята, любой совет будет оценен. Спасибо! (ВАЖНОЕ ПРИМЕЧАНИЕ: это моя конфигурация отчаяния)

spring -security.xml

<beans:beans 
     xmlns...(all needed declarations)>

<http pattern="/js/**" security="none" />
<http pattern="/css/**" security="none" />

<!-- enable use-expressions -->
<http auto-config="true" >
    <access-denied-handler error-page="/403" />
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
    <intercept-url pattern="/login" access="isAnonymous()" />
    <intercept-url pattern="/403" access="permitAll" />
    <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />

    <form-login  login-page="/login"
                 username-parameter="email"
                 password-parameter="password"
                 authentication-failure-url="/login?failed" />

    <!--
    <csrf/>
    -->
</http>

 ..... (authentication)  

AdminController.java

@Controller
@RequestMapping("/admin**")
public class AdminController {

    ... (all my autowired beans)

    @RequestMapping(
        value = "/events/loadEvents",
        method = RequestMethod.POST,
        consumes = MediaType.ALL_VALUE,
        produces = MediaType.ALL_VALUE,
        headers = "Accept=*/*")
    @ResponseBody
    public Event loadEvents(@RequestParam("parentId") long parentId) {
        ... (my logic)
        return event;
    }
}

Запрос (захват Wirehark)  HTTP-запрос (ссылка нечеткая, потому что я использовал упрощенный вариант ответа на свой вопрос)

Ответ (захват Wirehark)  введите описание изображения здесь

ИЗМЕНИТЬ код вызова jquery ajax

$.ajax({
    type: 'POST',
    cache: false,
    url: /admin/events/loadEvents,
    data: { parentId: 1 },
    dataType = 'json',
    contentType = 'application/json',

    ...
});

person rmpt    schedule 13.12.2015    source источник
comment
Я не вижу, как вы отправляете учетные данные? Как ваш 403 реализован?   -  person holmis83    schedule 15.12.2015
comment
Я достигаю этой области приложения только после аутентификации, т.е. первым шагом является аутентификация, а затем аутентификация сеанса управляется Spring Security. И, как я уже упоминал, если я изменю метод вызова jquery и действия контроллера на GET, он будет работать нормально. Проблема в том, почему я получаю 405 с помощью POST, если все правильно настроено.   -  person rmpt    schedule 15.12.2015
comment
Кто-нибудь может пролить свет на то, почему он должен давать 405 вместо любого другого статуса? 405 должен отображаться, если URI не поддерживает данный метод HTTP, верно?   -  person pinkpanther    schedule 29.02.2016


Ответы (2)


После многих часов исследований и тестов я наконец понял это, и это была (очень-очень) глупая ситуация. Итак, в своем вопросе я сказал

поэтому я отключил его (csrf на spring -security.xml), и проблема все еще не устранена.

Нет, я не отключал. Я пытался отключить его, делая

<!--
<csrf/>
-->

Но я должен делать:

<csrf disabled="true"/>

Комментирование тега csrf НЕ отключает csrf, это потому, что csrf включен по умолчанию! После обнаружения проблемы очень легко сказать, что это глупая ошибка, но когда я добавил тег csrf, чтобы включить ее, я подумал, что комментирование отключит ее. Найдите ответ в Spring Documentation < / а>

А теперь вернемся к моей проблеме. Исправить сообщение об ошибке 405 в вызове POST AJAX С ВКЛЮЧЕННЫМ CSRF было очень просто. Я сохраняю параметры csrf в переменных JS следующим образом:

<script type="text/javascript">
    var csrfParameter = '${_csrf.parameterName}';
    var csrfToken = '${_csrf.token}';
</script>

а затем мой вызов ajax выглядит так:

var jsonParams = {};
jsonParams['parentId'] = 1;
jsonParams[csrfParameter] = csrfToken;
$.ajax({
    type: 'POST',
    cache: false,
    url: /admin/events/loadEvents,
    data: jsonParams,
    dataType = 'json',
    contentType = 'application/json',

    ...
});

Работает как шарм. Надеюсь, что это поможет кому-то в будущем.

person rmpt    schedule 27.12.2015
comment
Спасибо это мне очень помогло - person Kamaraju; 18.05.2017
comment
Спасибо. Это мне помогло. Мне нужно ваше мнение по следующему поводу - у меня есть несколько RestController, которые возвращают ответ JSON, и несколько возвращающих просмотров. Если я включаю csrf, когда я выполняю вызов ajax для контроллеров отдыха, в случае сбоя с ошибкой 405. Что мне делать? Отключить csrf? или отправить токен csrf в вызовах ajax? Какой из них рекомендуется? - person Kuldeep Singh; 21.11.2019
comment
вы должны отправлять свой токен csrf при каждом вызове. просто из соображений безопасности. если вы не против проблем с безопасностью, то можете просто отключить csrf - person rmpt; 21.11.2019

В моем случае с той же проблемой помогает это:

  • добавить taglib:
 <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
  • добавить в тело jsp:
<sec:csrfMetaTags />
  • добавить в ajax
headers: {"X-CSRF-TOKEN": $("meta[name='_csrf']").attr("content")}

P.S. Спасибо Илье Шульгину, классному ответчику, теперь он здесь.

person Андрей    schedule 01.06.2018