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

~wangweijun 2020-11-13 07:25:03
http springmvc status 报错 jsps


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

老师常常教导我们,要知其然,还要知其所以然。

版权声明
本文为[~wangweijun]所创,转载请带上原文链接,感谢
https://blizzawang.blog.csdn.net/article/details/104869401

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple