Подтвердить что ты не робот

Ошибка 405 JSP с методом Put

Я использую эту проблему, поскольку JSP не принимает запрос PUT. Поэтому мне интересно, как это исправить. Я прочитал этот связанный вопрос в переполнении стека, но он не объясняет, как его исправить.

Статус HTTP 405 - JSP разрешают только GET POST или HEAD

Исходя из фона Rails, я пытаюсь сделать это, поэтому я использую REST-стиль REST, например PUT для обновлений, и DELETE для удаления ресурса пользователя.

Но всякий раз, когда в этом контроллере возникает ошибка, он пытается вернуть запрос исходному JSP, но Tomcat 8.0.9 не принимает запрос и дает эту ошибку: "HTTP Status 405 - JSP разрешают только GET POST или HEAD". Я попытался отключить readonly в Tomcat web.xml - это не имело никакого эффекта, и я все еще получаю ошибку. Я переключил его на метод POST, и поток работает нормально.

Есть ли способ заставить форвард быть методом POST, все еще принимая метод PUT для запроса?

/**
     * Edit a user account.
     * @return the edit user view
     */
    @RequestMapping(value = {"/update/{userId}"}, method = RequestMethod.PUT)
    public String updateUser(@Valid @ModelAttribute("user") User user, BindingResult result, final RedirectAttributes redirectAttributes)
    {
        logger.debug(user);

        // we check for duplicate email addresses during the update operation.
        List<User> userCheckList = userRepository.findByEmail(user.getEmail());
        if (userCheckList.size() > 0)
        {
            // size of list should only ever be 1
            User userCheck = userCheckList.get(0);
            if (userCheck.getId() != user.getId())
            {
                result.rejectValue("email", "error.user", "An account already exists for this user email address.");
            }
        }


        if (result.hasErrors())
        {
            return "admin.users.edit";
        }

        // we locate the user and add it to the model
        userRepository.save(user);



        // the save operation was successful so we show the user message.
        redirectAttributes.addFlashAttribute("user", user);
        redirectAttributes.addFlashAttribute("message", "Updated successfully");


        String viewName = "redirect:/admin/users";
        logger.debug(viewName);

        return viewName;
    }
4b9b3361

Ответ 1

Проблема заключается в том, что когда вы возвращаете имя вида из своего метода контроллера, Spring DispatcherServlet выполняет пересылку вперед к данному виду, сохраняя исходный метод PUT.

При попытке обработать этот форвард Tomcat откажется от этого, с обоснованием того, что a PUT для JSP может быть истолковано как означающее "заменить этот JSP файл на сервере содержимым этого запроса".

Действительно, вы хотите, чтобы ваш контроллер обрабатывал ваши запросы PUT, а затем впоследствии отправлял ваши JSP в качестве GET. К счастью, Servlet 3.0 предоставляет средства для фильтрации только на диспетчере FORWARD.

Создайте фильтр:

public class GetMethodConvertingFilter implements Filter {

    @Override
    public void init(FilterConfig config) throws ServletException {
        // do nothing
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

        chain.doFilter(wrapRequest((HttpServletRequest) request), response);
    }

    @Override
    public void destroy() {
        // do nothing
    }

    private static HttpServletRequestWrapper wrapRequest(HttpServletRequest request) {
        return new HttpServletRequestWrapper(request) {
            @Override
            public String getMethod() {
                return "GET";
            }
        };
    }
}

И подключите его к своему web.xml таким образом:

<filter>
    <filter-name>getMethodConvertingFilter</filter-name>
    <filter-class>my.GetMethodConvertingFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>getMethodConvertingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Это преобразует запросы на GET только в режиме forward, оставляя запросы через других диспетчеров без изменений, поэтому PUT будет нормально перехватываться вашими контроллерами.

Мое (возможно неправильное) понимание заключается в том, что Tomcat 8.0.9 представил исправление, где это эффективно выполняется автоматически для диспетчера ERROR - см. ответ в вашем связанный вопрос. Но вы не используете механизм обработки ошибок контейнера для рендеринга вашей страницы ошибки, вы используете Spring MVC для пересылки вручную в представление, поэтому вам нужно это сделать. Лично я столкнулся с этой проблемой в Jetty 9.2.7, где нет такого исправления, и я делегирую обработку ошибок в контейнер, поэтому у меня есть <dispatcher>ERROR</dispatcher>, настроенный в моем отображении фильтра.

Все это кажется немного загадочным, но это единственный способ, с помощью которого я обнаружил, что успешно перешел через этот RESTful- Spring -JSP-web-приложение hoop.

Ответ 2

У меня была одна и та же проблема, и я решил в конце добавить

<%@ page isErrorPage="true" %>

в начале моей страницы JSP.
С apache-jsp-8.0.33, org/apache/jasper/compiler/Generator.java пропускает создание этой проверки для страниц, на которых установлен этот флаг, что позволяет JSP отвечать на любой метод.