JSPs only permit GET POST or HEAD

(1)RESTful架构:
RESTful架构,就是目前最流行的一种互联网软件架构,它结构清晰、符合标准、易于理解、扩展方便;so正得到越来越多的网站采用; RESTful(Representational State Transfer),其实是一个开发理念,是对http的很好的诠释;

(2)REST风格的URL请求:

请求路径 请求方法 作用
-/user/1 HTTP GET 得到id为1的user
-/user/1 HTTP DELETE 删除id为1的user
-/user/1 HTTP PUT 更新id为1的user
-/user HTTP POST 新增user

(3)浏览器只支持GET和POST请求:
由于浏览器表单只支持 GET 和 POST 请求,为了实现 DELETE 和 PUT 请求,Spring 为我们提供了一个过滤器org.springframework.web.filter.HiddenHttpMethodFilter,可以为我们将 GET 和 POST 请求通过过滤器转化成 DELETE 和 PUT 请求:

在web.xml文件中配置过滤器:


<filter>
    <filter-name>hiddenHttpMethodFilterfilter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>    
<filter-mapping>
    <filter-name>hiddenHttpMethodFilterfilter-name>
    
    <url-pattern>/*url-pattern>
filter-mapping>

(4)在表单中添加隐藏域:
由于浏览器表单无法发送 DELETE 和 PUT 请求,所以为了让 HiddenHttpMethodFilter 识别请求的方法,需要在表单中添加一个隐藏域,name = _methodvalue = DELETE/POST /PUT,修改后 index.jsp 页面代码如下:

<form action="user" method="post">  // 提交方法必须为post
	<input type="hidden" name="_method" value="PUT"/>  // 隐藏域
	<input type="submit" value="Test Rest PUT"/>
form>

(5)HTTP 405的错误提示:
如果web项目是运行在Tomcat 8及以上,会发现被过滤成DELETE和PUT请求,到达控制器时能顺利执行,但是返回时(forward)会报HTTP 405的错误提示:消息 JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS

(6)解决方法:
1、使用Tomcat7;

2、在Controller当中添加 @ResponseBody 或者 @RestController注解,但是最后执行的结果 , 是在页面当中输出方法 return 的内容;
JSPs only permit GET POST or HEAD_第1张图片
JSPs only permit GET POST or HEAD_第2张图片

3、将请求转发(forward)改为请求重定向(redirect):重定向到一个Handler,由Handler转发到页面:

@RequestMapping(value = "/testMethod/{id}" , method = RequestMethod.DELETE)  
public String testMethodDELETE(@PathVariable(value = "id") Integer id) {  
        System.out.println("testMethod: DELETE: "+ id);  
        return "redirect:/springmvc/success"; //重定向到一个没有指定 method的 Handler方法   
}
@RequestMapping(value = "/success")  
public String successGenecal() {  
        return "success";  //由该方法 转发到success.jsp页面
} 

4、创建一个Filter来包装HttpRequest中的getMethod()方法:

JSPs only permit GET POST or HEAD_第3张图片

  • 客户端发送请求至服务器,这时如果发送的是POST请求且带有以_method为名的参数,会被Spring的HiddenHttpMethodFilter给拦截;
  • HiddenHttpMethodFilter内有一个静态内部类通过继承HttpServletRequestWrapper类并重写getMethod()方法,将该方法返回值设为_method隐藏域的值;
  • HiddenHttpMethodFilter在包装好Request后,将请求发往服务器的控制器中对应的方法处理器,这时的请求变成了图中的WrapperRequest by SpringFilter
  • 服务器处理完请求后,产生了一个forward请求,产生相应的请求处理信息发往客户端,注意这时的request的getMethod()方法仍然是HiddenHttpMethodFilter包装过的;
  • 我们需要在服务器的响应请求到达客户端前进行拦截,这也是最关键的一步,通过自定义过滤器MyHttpMethodFilter进一步包装请求,将getMethod()方法返回值改成POST或GET即可;
    (用HttpRequestWrapper将原始请求包装成一个假的请求并告诉它返回POST来delete和put请求所以Jsp认为这是一个POST请求)
public class MyHttpMethodFilter extends HiddenHttpMethodFilter {
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		String method = httpServletRequest.getMethod();
		if (method.equalsIgnoreCase("delete") || method.equalsIgnoreCase("put")) { method = "POST"; }
		httpServletRequest = new HttpMethodRequestWrapper(request, method);
		filterChain.doFilter(httpServletRequest, response);
	}
	private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
		private final String method;
		public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
			super(request);    this.method = method;
		} 
		public String getMethod() { return this.method; }
	}
}
  • 在web.xml中配置该filter,注意dispatcher结点值必须为FORWARD:
<filter-mapping>
	<filter-name>myFilterfilter-name>
	<url-pattern>/*url-pattern>
	<dispatcher>FORWARDdispatcher>
filter-mapping>

你可能感兴趣的:(笔记)