405使用Put方法的JSP错误

时间:2014-07-10 09:33:19

标签: spring-mvc

关于JSP不接受PUT请求,我遇到了这个问题。所以我想知道如何解决它。我已经在堆栈溢出中读到了这个相关的问题,但它没有解释如何修复它。

HTTP Status 405 - JSPs only permit GET POST or HEAD

来自Rails的背景,我正在尝试使用它,因此我使用了像PUT的rails REST样式进行更新,并使用DELETE来删除用户资源。

但是当这个控制器出现错误时,它会尝试将请求返回给原始JSP,但是Tomcat 8.0.9不接受请求并给出此错误:“HTTP状态405 - JSP只允许GET POST或HEAD ”。我已经尝试在Tomcat web.xml中禁用readonly - 它没有任何效果,我仍然得到错误。我已将其切换为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;
    }

3 个答案:

答案 0 :(得分:16)

问题是,当您从控制器方法返回视图名称时,Spring DispatcherServlet将转发到给定视图,保留原始PUT方法。

在尝试处理这个问题时,Tomcat会拒绝它,理由是JSP的PUT可以理解为“用服务请求的内容替换服务器上的这个JSP文件。” / p>

您真的希望控制器处理您的PUT请求,然后以GET转发到您的JSP。幸运的是,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,通过其他调度程序保留请求不变,因此PUT将被您的控制器正常拦截。

我的(可能不正确)理解是Tomcat 8.0.9引入了一个修复程序,可以自动为ERROR调度程序自动完成 - 请参阅链接问题中的answer。但是你没有使用容器的错误处理机制来呈现你的错误页面,你正在使用Spring MVC手动转发到视图,因此你需要这样做。我个人在Jetty 9.2.7下遇到了这个问题,没有这样的修复,我将错误处理委托给容器,所以我也在我的过滤器映射中配置了<dispatcher>ERROR</dispatcher>

这一切看起来有点神秘但是我发现成功跳过这个特定的RESTful-Spring-JSP-web-application hoop的唯一方法。

答案 1 :(得分:2)

我有同样的问题,最后通过添加

解决了这个问题
<%@ page isErrorPage="true" %>

在我的JSP页面的开头。
使用apache-jsp-8.0.33,org / apache / jasper / compiler / Generator.java会跳过为已设置此标志的页面创建此检查,从而允许JSP回答任何方法。

答案 2 :(得分:0)

如果web.xml还包含Spring安全配置,例如:

<!--    springSecurityFilterChain-->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

,然后-above@ryanp的描述进行了小幅改进, 处理 Delete PUT 方法:

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() {
            String requestMethod = request.getMethod();
            return HttpMethod.PUT.matches(requestMethod) || HttpMethod.DELETE.matches(requestMethod) ?
                    HttpMethod.GET.toString() : requestMethod;
        }
    };
  }
}

Tomcat 8.5.51

上进行了测试