如果專案是執行在 Tomcat 8 及以上,會發現發出的 PUT 請求和 DELETE 請求可以被控制其接收到,但是返回頁面時(forward)會報HTTP 405 的錯誤提示:"訊息 JSP 只允許 GET、POST 或 HEAD。Jasper 還允許 OPTIONS"。
解決方案:
-
使用 Tomcat 8 以下版本。
-
使用
@RestController
或者@Controller + @ResponseBody
標籤,但是這樣就無法跳轉頁面了。 -
避免使用 forward 方式跳轉頁面,改為 重定向
redirect
方式跳轉到另一個控制器方法,再由這個控制器方法跳轉頁面。@RequestMapping(value = "/rest", method = RequestMethod.PUT) public String put() { // 接收表單中的各種資訊 System.out.println("PUT --- 更新資料"); return "redirect:/success"; } @RequestMapping(value = "/success") public String success() { return "success"; }
-
給 Tomcat 新增啟動引數,使Tomcat允許寫操作
<init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param>
-
建立一個新的 Filter 來過濾 FORWARD
// HiddenHttpMethodFilter.java @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) { String paramValue = request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { requestToUse = new HttpMethodRequestWrapper(request, paramValue); } } filterChain.doFilter(requestToUse, response); }
HiddenHttpMethodFilter 中的
doFilterInternal
方法是用來過濾 form 表單中 name 為 _method的請求。可以發現,它把請求作為引數傳進HttpMethodRequestWrapper
中並且返回了一個新的請求,放行的也是新的請求。所以我們可以重寫 HttpMethodRequestWrapper 中的getMethod()
方法,讓它支援 forward 方式的跳轉。// 重寫 getMethod() package com.pudding.conf; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.springframework.web.filter.HiddenHttpMethodFilter; public class MyHttpMethodFilter extends HiddenHttpMethodFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; String method = requestToUse.getMethod(); if (method.equalsIgnoreCase("delete") || method.equalsIgnoreCase("put")) { method = "POST"; } requestToUse = new HttpMethodRequestWrapper(request, method); filterChain.doFilter(requestToUse, 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> <filter-name>myFilter</filter-name> <filter-class>com.pudding.conf.MyHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> </filter-mapping>
-
在 forward 需要跳轉的頁面頭加上
isErrorPage="true"
:<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isErrorPage="true"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>success</h1> </body> </html>