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

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

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

index.jsp页面代码:

<%@ 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>

控制器代码:

@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"; 
    }
}

项目运行起来:
在这里插入图片描述
点GET、POST都没有问题,但你点DELETE和PUT的时候程序就报错了,报错信息如下:
在这里插入图片描述
报错信息提示:jsp只允许GET POST或HEAD。

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

  1. tomcat换到7.0以及以下版本
  2. 在方法上标注@ResponseBody
  3. 请求先转给一个Controller,再返回jsp页面
  4. 在你的success页面头部设置isErrorPage属性为true

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

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请求时才去使用它们,比如通过它们返回一些数据,否则就不要去用它们了,这是多此一举。

老师常常教导我们,要知其然,还要知其所以然。
目录
相关文章
|
11天前
|
前端开发 Java Spring
Spring MVC 是如何对对象参数进行校验的
【6月更文挑战第4天】对象参数校验是使用 SpringMVC 时常用的功能,这篇文章尝试分析了,Spring 是如何实现这一功能的。
26 5
|
1天前
|
前端开发 Java Maven
如何在Spring MVC中实现图片的上传和下载功能
如何在Spring MVC中实现图片的上传和下载功能
|
1天前
|
缓存 NoSQL Java
在 SSM 架构(Spring + SpringMVC + MyBatis)中,可以通过 Spring 的注解式缓存来实现 Redis 缓存功能
【6月更文挑战第18天】在SSM(Spring+SpringMVC+MyBatis)中集成Redis缓存,涉及以下步骤:添加Spring Boot的`spring-boot-starter-data-redis`依赖;配置Redis连接池(如JedisPoolConfig)和连接工厂;在Service层使用`@Cacheable`注解标记缓存方法,指定缓存名和键生成策略;最后,在主配置类启用缓存注解。通过这些步骤,可以利用Spring的注解实现Redis缓存。
17 2
|
5天前
|
前端开发 Java Spring
Spring MVC 请求处理流程
Spring MVC 请求处理流程
6 0
|
8天前
|
小程序
Failed to load local image resource Xx the server responded with a status of of 500 (HTTP/1.1 500)
Failed to load local image resource Xx the server responded with a status of of 500 (HTTP/1.1 500)
|
9天前
|
JSON 前端开发 Java
Spring MVC 级联对象参数校验
【6月更文挑战第6天】在 Spring MVC 的使用过程中,我们会发现很多非常符合直觉的功能特性,但往往我们会习惯这种「被照顾得很好」的开发方式,依靠直觉去判断很多功能特性的用法。
14 1
|
12天前
|
XML 前端开发 Java
Spring3 MVC中使用Swagger生成API文档
Spring3 MVC中使用Swagger生成API文档
14 0
svn: E175002: Commit failed (details follow): svn: E175002: Unexpected HTTP status 502Bad Gateway on
svn: E175002: Commit failed (details follow): svn: E175002: Unexpected HTTP status 502Bad Gateway on
|
12天前
|
JSON 前端开发 API
Apache HttpClient调用Spring3 MVC Restful Web API演示
Apache HttpClient调用Spring3 MVC Restful Web API演示
12 1
|
12天前
|
前端开发 Java 关系型数据库
在Spring3 MVC中五步配置集成注解方式Hibernate3
在Spring3 MVC中五步配置集成注解方式Hibernate3
18 3