SpringMVC报错:HTTP Status 405 - JSPs only permit GET POST or HEAD

最近在写JavaEE系列的文章,在写SpringMVC的REST风格URL的时候出现了一些问题,下面是部分代码。html

index.jsp页面代码:java

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

    <form action="springmvc/testRest/1" method="post">
        <input type="hidden" name="_method" value="PUT"
        <input type="submit" value="TestRest PUT">
    </form>
    <br>

    <form action="springmvc/testRest/1" method="post">
        <input type="hidden" name="_method" value="DELETE"
        <input type="submit" value="TestRest DELETE">
    </form>
    <br>

    <form action="springmvc/testRest" method="post">
        <input type="submit" value="TestRest POST">
    </form>
    <br>

    <form action="springmvc/testRest/1" method="get">
        <input type="submit" value="TestRest GET">
    </form>
    <br>

</body>
</html>

控制器代码:web

@RequestMapping("/springmvc")
@Controller
public class RequestMappingTest {

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.PUT)
    public String testRestPut(@PathVariable("id") Integer id) {
        System.out.println("testRest PUT:" + id);
        return "success"
    }

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.DELETE)
    public String testRestDelete(@PathVariable("id") Integer id) {
        System.out.println("testRest DELETE:" + id);
        return "success"
    }

    @RequestMapping(value = "/testRest",method = RequestMethod.POST)
    public String testRestPost() {
        System.out.println("testRest POST");
        return "success"
    }

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.GET)
    public String testRestGet(@PathVariable("id") Integer id) {
        System.out.println("testRest GET:" + id);
        return "success"
    }
}

项目运行起来:
spring

在这里插入图片描述

点GET、POST都没有问题,但你点DELETE和PUT的时候程序就报错了,报错信息以下:
在这里插入图片描述

报错信息提示:jsp只容许GET POST或HEAD。


这个报错其实很早以前我就遇到了,当时查了一下,总共有四种方式解决:tomcat

  1. tomcat换到7.0以及如下版本微信

  2. 在方法上标注@ResponseBodymvc

  3. 请求先转给一个Controller,再返回jsp页面app

  4. 在你的success页面头部设置isErrorPage属性为truejsp

当时也确实就解决问题了,也没有深究究竟是为何,这几天大概地查了一下,网上写这个错误的人不少,但也只是给出了解决方案,并无说到底为何这样解决。post

tomcat换到7.0以及如下版本

查阅了不少资料后,我得出一些结论,报错的信息其实很明显了,说的是jsp只容许GET、POST或HEAD,而咱们使用了REST风格中的DELETE和PUT,显然就会报错了。

那么为何把tomcat版本切换到7.0或者7.0如下的版本就不会出现这样的问题呢?

Tomcat按照JCP规范(JSP2.3版本)的规定,从Tomcat8.x版本开始,再也不支持以HTTP PUT方式访问JSP页面,仅支持GET、POST和HEAD方式。

而你在控制器方法中编写的返回值是一个字符串,SpringMVC会认为这是一个jsp页面,因此报错了。
这就完美地解释了第一种解决办法为何可以起做用,可是切换tomcat版本显然并很差。

在方法上标注@ResponseBody

刚刚说到SpringMVC会将控制器方法的返回值认为是一个jsp页面致使出错,那么你就能够在处理方法上标注@ResponseBody注解,再运行项目试一试:

在这里插入图片描述

运行成功,可是返回值显示到了页面上。


这就要来了解一下@ResponseBody的做用了:

@ResponseBody注解的做用是将控制器方法的返回值经过适当的转换器转换为指定的格式以后,写入到Response对象的body区,一般用来返回JSON数据或者是XML数据。
注意:在使用此注解以后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于经过Response对象输出指定格式的数据。

看到这,你是否是就明白了,你加上这个注解,它就不走视图处理器,固然也就不会跳转到jsp页面了,不跳转到jsp页面,固然就不报错了。

不过这个注解一般是用来返回数据的,若是你确实是要返回数据,这样写固然没有问题,这也是比较规范的一种写法。

请求先转给一个Controller,再返回jsp页面

而若是你仅仅就是想跳转一个jsp页面,就能够用第三种解决方法。
既然不能直接跳转到jsp页面,你就能够将请求先转给一个控制方法,再经过该控制方法跳转到jsp页面。
修改一下控制类的代码:

@RequestMapping("/springmvc")
@Controller
public class RequestMappingTest {

    @RequestMapping("/toSuccess")
    public String toSuccess() {
        System.out.println("toSuccess");
        return "success";
    }

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.PUT)
    public String testRestPut(@PathVariable("id") Integer id) {
        System.out.println("testRest PUT:" + id);
        return "redirect:/springmvc/toSuccess"
    }

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.DELETE)
    public String testRestDelete(@PathVariable("id") Integer id) {
        System.out.println("testRest DELETE:" + id);
        return "redirect:/springmvc/toSuccess"
    }

    @RequestMapping(value = "/testRest",method = RequestMethod.POST)
    public String testRestPost() {
        System.out.println("testRest POST");
        return "success"
    }
}
......

经过这样的方式,咱们的DELETE和PUT请求就不会直接地去跳转jsp页面,而是先交给了toSuccess控制方法,并由该方法跳转到jsp页面。

在你的success页面头部设置isErrorPage属性为true

至于这种解决方法为何可以成功,相信大家应该能本身知道了吧?

就是由于DELETE和PUT请求直接跳转jsp页面会出错,当你在待跳转的jsp页面中设置isErrorPage属性为true后,在跳转jsp页面时出错,而设置了isErrorPage属性的页面即为错误页面,它就这样显示出来了。

总结

综上所述,这四种解决方法其实都是在解决同一个问题,就是jsp不支持DELETE和PUT,咱们要想办法在这两种请求的方式下不直接去访问jsp就好了。

但这些方法总归是有些违背本身的主观意愿,因此只有当你须要使用DELETE和PUT请求时才去使用它们,好比经过它们返回一些数据,不然就不要去用它们了,这是画蛇添足。

老师经常教导咱们,要知其然,还要知其因此然。


本文分享自微信公众号 - 码视界(otc_18679428729)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索