關於在Spring過濾器中修改request的引數值遇到的問題(三)
繼上一遍為背景
問題描述:
成功解密了reqeust中的引數後,在控制層Controller中獲取到的引數,是沒有解密的引數。例如:在過濾器中修改 引數名為username 的引數值432895328195783915781(一串加密的密文) 為 xiaomin(解密後的明文),在Cotroller中獲取到的依然是加密後的密文432895328195783915781。問題定位
百度,沒有,心酸,跑不掉,一步一步debugger,終於發現
在SpringMVC框架中,request到controller層的資料bind(繫結)中,用到該類的方法org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@Override protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); MultipartHttpServletRequest multipartRequest = WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class); Object arg; // 將被繫結的值
如上註釋,方法在一定條件下走了String[] paramValues = webRequest.getParameterValues(name);這一段程式碼,debugger發現,
這段程式碼走的的真正實現竟然是web容器Tomcat提供的request包裝類org.apache.catalina.connector.RequestFacade中的方法。(因為這裡的WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class)最後返回了一個Tomcat提供的request包裝類)@Override public String[] getParameterValues(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } String[] ret = null; if (SecurityUtil.isPackageProtectionEnabled()){ ret = AccessController.doPrivileged( new GetParameterValuePrivilegedAction(name)); if (ret != null) { ret = ret.clone(); } } else { ret = request.getParameterValues(name); } return ret; }
而該Tomcat的request包裝類中的引數,確實是沒有解密之前的值。由此猜測(個人猜測,不對的請指點迷津,感激) 1.伺服器在接受請求時,Spring和Tomcat各自都建立了一個request的包裝類(可以發現都實現了HttpServletRequest介面),在沒有修改rquest引數時,這兩個包裝類幾乎一樣(指引數值都是一致的),當我在過濾器中修改了Spring的rquest包裝類引數值,tomcat的request包裝類是沒有修改的。2.在SpringMVC的資料繫結中,應為某些原因,需要從tomcat的request包裝類中獲取引數值。這就導致了上述問題的發生。
4.解決方案
在之前的自定義包裝類中(繼承了ServletRequestWrapper)重寫 getParameterValues(String name)方法import org.apache.catalina.util.ParameterMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.util.Map; public class ParameterRequestWrapper extends HttpServletRequestWrapper { private ParameterMap<String, String[]> params; @SuppressWarnings("all") public ParameterRequestWrapper(HttpServletRequest request) { super(request); params = (ParameterMap) request.getParameterMap(); // TODO Auto-generated constructor stub } @Override public String getParameter(String name) { // TODO Auto-generated method stub String[] values = params.get(name); if (values == null || values.length == 0) { return null; } return values[0]; } @Override public Map<String, String[]> getParameterMap() { // TODO Auto-generated method stub return params; } // 就是該方法 @Override public String[] getParameterValues(String name) { return params.get(name); } public void addParameter(String name, Object value) { if (value != null) { params.setLocked(false); if (value instanceof String[]) { params.put(name, (String[]) value); } else if (value instanceof String) { params.put(name, new String[] { (String) value }); } else { params.put(name, new String[] { String.valueOf(value) }); } params.setLocked(true); } } }
解決問題,如有不對的地方,還請高人路過指點。