Java 修改HttpServletRequest正文
我正在处理遗留代码,需要做一个补丁 问题是:一个古老的应用程序发送错误的HTTP POST请求。其中一个参数不是URL编码的。我知道这个参数总是最后一个,我知道它的名字。我现在尝试在tomcat内部运行的服务器端修复它 无法通过HttpServletRequest的标准getParameter方法访问此参数,因为它的格式不正确。方法只返回null。但是当我通过ServletInputStream手动读取整个请求时,所有其他参数都消失了。看起来基础类无法解析ServletInputStream的内容,因为它已耗尽 到目前为止,我已经成功地制作了一个包装器,它从主体中读取所有参数并覆盖所有参数访问方法。但是,如果在我之前的链中的任何过滤器尝试访问任何参数,那么一切都将中断,因为ServletiInputStream将为空 我能设法回避这个问题吗?可能有不同的方法吗Java 修改HttpServletRequest正文,java,http,request,Java,Http,Request,我正在处理遗留代码,需要做一个补丁 问题是:一个古老的应用程序发送错误的HTTP POST请求。其中一个参数不是URL编码的。我知道这个参数总是最后一个,我知道它的名字。我现在尝试在tomcat内部运行的服务器端修复它 无法通过HttpServletRequest的标准getParameter方法访问此参数,因为它的格式不正确。方法只返回null。但是当我通过ServletInputStream手动读取整个请求时,所有其他参数都消失了。看起来基础类无法解析ServletInputStream的内
总之,如果我在过滤器中读取原始请求体,参数将从请求中消失。如果我读取单个参数,ServletInputStream将变为空,无法手动处理。此外,不可能通过getParameter方法读取格式错误的参数。与其重写方法,不如安装一个重写请求的servlet过滤器
Jason Hunter有一个非常好的方法。您可以编写自己的Servlet过滤器,并希望确保它出现在链的第一位。然后将ServletRequest对象包装成可以在需要时处理重写的东西。请查看的编程自定义请求和响应部分 ------更新------
我一定错过了什么。您说您可以自己读取请求主体和参数。然后你不能确保你的过滤器是第一个,包装ServletRequest对象,读取、处理和存储参数,将你的请求对象传递到链上,并提供你存储的参数而不是原始参数吗?我找到的解决方案: 仅仅重新定义参数访问方法是不够的。必须做几件事
为了澄清,我重新定义了参数访问方法,因为我的请求如问题中所述被破坏了。您可能不需要它。我做了一个更完整的包装,允许您在内容类型为application/x-www-form-urlencoded并且您已经调用了其中一个getParameterXXX方法的情况下仍然访问内容:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* This class implements the Wrapper or Decorator pattern.<br/>
* Methods default to calling through to the wrapped request object,
* except the ones that read the request's content (parameters, stream or reader).
* <p>
* This class provides a buffered content reading that allows the methods
* {@link #getReader()}, {@link #getInputStream()} and any of the getParameterXXX to be called
* safely and repeatedly with the same results.
* <p>
* This class is intended to wrap relatively small HttpServletRequest instances.
*
* @author pgurov
*/
public class HttpServletRequestWrapper implements HttpServletRequest {
private class ServletInputStreamWrapper extends ServletInputStream {
private byte[] data;
private int idx = 0;
ServletInputStreamWrapper(byte[] data) {
if(data == null)
data = new byte[0];
this.data = data;
}
@Override
public int read() throws IOException {
if(idx == data.length)
return -1;
return data[idx++];
}
}
private HttpServletRequest req;
private byte[] contentData;
private HashMap<String, String[]> parameters;
public HttpServletRequestWrapper() {
//a trick for Groovy
throw new IllegalArgumentException("Please use HttpServletRequestWrapper(HttpServletRequest request) constructor!");
}
private HttpServletRequestWrapper(HttpServletRequest request, byte[] contentData, HashMap<String, String[]> parameters) {
req = request;
this.contentData = contentData;
this.parameters = parameters;
}
public HttpServletRequestWrapper(HttpServletRequest request) {
if(request == null)
throw new IllegalArgumentException("The HttpServletRequest is null!");
req = request;
}
/**
* Returns the wrapped HttpServletRequest.
* Using the getParameterXXX(), getInputStream() or getReader() methods may interfere
* with this class operation.
*
* @return
* The wrapped HttpServletRequest.
*/
public HttpServletRequest getRequest() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return new HttpServletRequestWrapper(req, contentData, parameters);
}
/**
* This method is safe to use multiple times.
* Changing the returned array will not interfere with this class operation.
*
* @return
* The cloned content data.
*/
public byte[] getContentData() {
return contentData.clone();
}
/**
* This method is safe to use multiple times.
* Changing the returned map or the array of any of the map's values will not
* interfere with this class operation.
*
* @return
* The clonned parameters map.
*/
public HashMap<String, String[]> getParameters() {
HashMap<String, String[]> map = new HashMap<String, String[]>(parameters.size() * 2);
for(String key : parameters.keySet()) {
map.put(key, parameters.get(key).clone());
}
return map;
}
private void parseRequest() throws IOException {
if(contentData != null)
return; //already parsed
byte[] data = new byte[req.getContentLength()];
int len = 0, totalLen = 0;
InputStream is = req.getInputStream();
while(totalLen < data.length) {
totalLen += (len = is.read(data, totalLen, data.length - totalLen));
if(len < 1)
throw new IOException("Cannot read more than " + totalLen + (totalLen == 1 ? " byte!" : " bytes!"));
}
contentData = data;
String enc = req.getCharacterEncoding();
if(enc == null)
enc = "UTF-8";
String s = new String(data, enc), name, value;
StringTokenizer st = new StringTokenizer(s, "&");
int i;
HashMap<String, LinkedList<String>> mapA = new HashMap<String, LinkedList<String>>(data.length * 2);
LinkedList<String> list;
boolean decode = req.getContentType() != null && req.getContentType().equals("application/x-www-form-urlencoded");
while(st.hasMoreTokens()) {
s = st.nextToken();
i = s.indexOf("=");
if(i > 0 && s.length() > i + 1) {
name = s.substring(0, i);
value = s.substring(i+1);
if(decode) {
try {
name = URLDecoder.decode(name, "UTF-8");
} catch(Exception e) {}
try {
value = URLDecoder.decode(value, "UTF-8");
} catch(Exception e) {}
}
list = mapA.get(name);
if(list == null) {
list = new LinkedList<String>();
mapA.put(name, list);
}
list.add(value);
}
}
HashMap<String, String[]> map = new HashMap<String, String[]>(mapA.size() * 2);
for(String key : mapA.keySet()) {
list = mapA.get(key);
map.put(key, list.toArray(new String[list.size()]));
}
parameters = map;
}
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getReader().
* Every time a new ServletInputStream is returned that reads data from the begining.
*
* @return
* A new ServletInputStream.
*/
public ServletInputStream getInputStream() throws IOException {
parseRequest();
return new ServletInputStreamWrapper(contentData);
}
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getInputStream().
* Every time a new BufferedReader is returned that reads data from the begining.
*
* @return
* A new BufferedReader with the wrapped request's character encoding (or UTF-8 if null).
*/
public BufferedReader getReader() throws IOException {
parseRequest();
String enc = req.getCharacterEncoding();
if(enc == null)
enc = "UTF-8";
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contentData), enc));
}
/**
* This method is safe to execute multiple times.
*
* @see javax.servlet.ServletRequest#getParameter(java.lang.String)
*/
public String getParameter(String name) {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
String[] values = parameters.get(name);
if(values == null || values.length == 0)
return null;
return values[0];
}
/**
* This method is safe.
*
* @see {@link #getParameters()}
* @see javax.servlet.ServletRequest#getParameterMap()
*/
@SuppressWarnings("unchecked")
public Map getParameterMap() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return getParameters();
}
/**
* This method is safe to execute multiple times.
*
* @see javax.servlet.ServletRequest#getParameterNames()
*/
@SuppressWarnings("unchecked")
public Enumeration getParameterNames() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return new Enumeration<String>() {
private String[] arr = getParameters().keySet().toArray(new String[0]);
private int idx = 0;
public boolean hasMoreElements() {
return idx < arr.length;
}
public String nextElement() {
return arr[idx++];
}
};
}
/**
* This method is safe to execute multiple times.
* Changing the returned array will not interfere with this class operation.
*
* @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
*/
public String[] getParameterValues(String name) {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
String[] arr = parameters.get(name);
if(arr == null)
return null;
return arr.clone();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getAuthType()
*/
public String getAuthType() {
return req.getAuthType();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getContextPath()
*/
public String getContextPath() {
return req.getContextPath();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getCookies()
*/
public Cookie[] getCookies() {
return req.getCookies();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String)
*/
public long getDateHeader(String name) {
return req.getDateHeader(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
*/
public String getHeader(String name) {
return req.getHeader(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getHeaderNames()
*/
@SuppressWarnings("unchecked")
public Enumeration getHeaderNames() {
return req.getHeaderNames();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String)
*/
@SuppressWarnings("unchecked")
public Enumeration getHeaders(String name) {
return req.getHeaders(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String)
*/
public int getIntHeader(String name) {
return req.getIntHeader(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getMethod()
*/
public String getMethod() {
return req.getMethod();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getPathInfo()
*/
public String getPathInfo() {
return req.getPathInfo();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getPathTranslated()
*/
public String getPathTranslated() {
return req.getPathTranslated();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getQueryString()
*/
public String getQueryString() {
return req.getQueryString();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getRemoteUser()
*/
public String getRemoteUser() {
return req.getRemoteUser();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getRequestURI()
*/
public String getRequestURI() {
return req.getRequestURI();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getRequestURL()
*/
public StringBuffer getRequestURL() {
return req.getRequestURL();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
*/
public String getRequestedSessionId() {
return req.getRequestedSessionId();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getServletPath()
*/
public String getServletPath() {
return req.getServletPath();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getSession()
*/
public HttpSession getSession() {
return req.getSession();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession(boolean create) {
return req.getSession(create);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
*/
public Principal getUserPrincipal() {
return req.getUserPrincipal();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
*/
public boolean isRequestedSessionIdFromCookie() {
return req.isRequestedSessionIdFromCookie();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
*/
public boolean isRequestedSessionIdFromURL() {
return req.isRequestedSessionIdFromURL();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
*/
@SuppressWarnings("deprecation")
public boolean isRequestedSessionIdFromUrl() {
return req.isRequestedSessionIdFromUrl();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
*/
public boolean isRequestedSessionIdValid() {
return req.isRequestedSessionIdValid();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String role) {
return req.isUserInRole(role);
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
return req.getAttribute(name);
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getAttributeNames()
*/
@SuppressWarnings("unchecked")
public Enumeration getAttributeNames() {
return req.getAttributeNames();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getCharacterEncoding()
*/
public String getCharacterEncoding() {
return req.getCharacterEncoding();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getContentLength()
*/
public int getContentLength() {
return req.getContentLength();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getContentType()
*/
public String getContentType() {
return req.getContentType();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getLocalAddr()
*/
public String getLocalAddr() {
return req.getLocalAddr();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getLocalName()
*/
public String getLocalName() {
return req.getLocalName();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getLocalPort()
*/
public int getLocalPort() {
return req.getLocalPort();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getLocale()
*/
public Locale getLocale() {
return req.getLocale();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getLocales()
*/
@SuppressWarnings("unchecked")
public Enumeration getLocales() {
return req.getLocales();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getProtocol()
*/
public String getProtocol() {
return req.getProtocol();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getRealPath(java.lang.String)
*/
@SuppressWarnings("deprecation")
public String getRealPath(String path) {
return req.getRealPath(path);
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getRemoteAddr()
*/
public String getRemoteAddr() {
return req.getRemoteAddr();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getRemoteHost()
*/
public String getRemoteHost() {
return req.getRemoteHost();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getRemotePort()
*/
public int getRemotePort() {
return req.getRemotePort();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
*/
public RequestDispatcher getRequestDispatcher(String path) {
return req.getRequestDispatcher(path);
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getScheme()
*/
public String getScheme() {
return req.getScheme();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getServerName()
*/
public String getServerName() {
return req.getServerName();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#getServerPort()
*/
public int getServerPort() {
return req.getServerPort();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#isSecure()
*/
public boolean isSecure() {
return req.isSecure();
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
req.removeAttribute(name);
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String name, Object value) {
req.setAttribute(name, value);
}
/* (non-Javadoc)
* @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
*/
public void setCharacterEncoding(String env)
throws UnsupportedEncodingException {
req.setCharacterEncoding(env);
}
}
导入java.io.BufferedReader;
导入java.io.ByteArrayInputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.InputStreamReader;
导入java.io.UnsupportedEncodingException;
导入java.net.url解码器;
导入java.security.Principal;
导入java.util.Enumeration;
导入java.util.HashMap;
导入java.util.LinkedList;
导入java.util.Locale;
导入java.util.Map;
导入java.util.StringTokenizer;
导入javax.servlet.RequestDispatcher;
导入javax.servlet.ServletInputStream;
导入javax.servlet.http.Cookie;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpSession;
/**
*此类实现包装器或装饰器模式。
*方法默认为调用包装的请求对象,
*除了那些读取请求内容的(参数、流或读取器)。
*
*此类提供了一个缓冲内容读取,允许
*{@link#getReader()}、{@link#getInputStream()}和任何要调用的getParameterXXX
*安全且重复,结果相同。
*
*此类用于包装相对较小的HttpServletRequest实例。
*
*@pgurov
*/
公共类HttpServletRequestWrapper实现HttpServletRequest{
私有类ServletInputStreamWrapper扩展了ServletInputStream{
专用字节[]数据;
私有整数idx=0;
ServletInputStreamWrapper(字节[]数据){
如果(数据==null)
数据=新字节[0];
这个数据=数据;
}
@凌驾
public int read()引发IOException{
if(idx==data.length)
返回-1;
返回数据[idx++];
}
}
私有HttpServletRequest请求;
私有字节[]内容数据;
私有HashMap参数;
公共HttpServletRequestWrapper(){
//Groovy的诀窍
抛出新的IllegalArgumentException(“请使用HttpServletRequestWrapper(HttpServletRequest)构造函数!”);
}
私有HttpServletRequestWrapper(HttpServletRequest请求,字节[]contentData,HashMap参数){
req=请求;
this.contentData=contentData;
此参数=参数;
}
公共HttpServletRequestWrapper(HttpServletRequest请求){
if(请求==null)
抛出新的IllegalArgumentException(“HttpServletRequest为null!”);
req=请求;
}
/**
*返回包装的HttpServletRequest。
*使用getParameterXXX()、getInputStream()或getReader()方法可能会产生干扰
*用这个类操作。
*
*@返回
*包装好的HttpServletRequest。
*/
公共HttpServletRequest getRequest(){
public int read() throws IOException {
if (index == data.length) {
return -1;
}
return data[index++] & 0xff;
}