(Java版本8)
我需要在过滤器中处理请求正文。使用下面的代码,我读取了正文。
private static String convertInputStreamToString(InputStream is) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 50];
int length;
while ((length = is.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString("UTF-8");
}
问题是如果请求正文发布的参数的内容类型为“Application/x-www-form-urlencoded”,那么这些参数在读取正文后将不可用。如果我不读取正文,它们可以使用request.getParameter()获取。
此外,我尝试使用以下代码包装请求并提供正文,这样解决方案的其余部分(例如servlet)就可以使用它,但丢失参数的问题仍然存在。代码是从这篇文章中复制/采用的
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = convertInputStreamToString(request.getInputStream());
}
private static String convertInputStreamToString(InputStream is) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 50];
int length;
while ((length = is.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString("UTF-8");
}
@Override
public ServletInputStream getInputStream() throws IOException {
final byte[] myBytes = body.getBytes("UTF-8");
ServletInputStream servletInputStream = new ServletInputStream() {
private int lastIndexRetrieved = -1;
private ReadListener readListener = null;
@Override
public boolean isFinished() {
return (lastIndexRetrieved == myBytes.length - 1);
}
@Override
public boolean isReady() {
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved + 1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
}
return i;
} else {
return -1;
}
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
奇怪的是,HttpServletRequest内容只能读取一次。它以流的形式出现,所以一旦您读取流,它就消失了。所以您需要一些允许您多次读取的包装器。Spring实际上提供了这样的包装器。类的名称是ContentCachingRequest estWrapper
。这是它的Javadoc。这是解释如何在使用Spring Boot时使用它的答案:如何在Spring过滤器中获取请求正文参数?
感谢zaerymoghaddam的帮助。
我担心我是否会隐式地影响请求对象,因此解决方案的其余部分缺少一些内容。
此外,我发现参数映射=super.get参数映射();
没有从正文中提取参数(如果帖子的内容类型为“Application/x-www-form-urlencoded”)
通过对您的代码进行一点更改,我提出了以下解决方案:
public class MyRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedBytes;
private String body;
private Map<String, String[]> parameterMap;
private static int bufferLength = 1024 * 50;
public MyRequestWrapper(final HttpServletRequest request) throws IOException {
super(request);
cacheBodyAsString();
parameterMap = new HashMap<>(super.getParameterMap());
addParametersFromBody();
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new CachedServletInputStream(cachedBytes.toByteArray());
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String GetRequestBodyAsString() {
return this.body;
}
@Override
public String getParameter(String key) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(key);
return values != null && values.length > 0 ? values[0] : null;
}
@Override
public String[] getParameterValues(String key) {
Map<String, String[]> parameterMap = getParameterMap();
return parameterMap.get(key);
}
@Override
public Map<String, String[]> getParameterMap() {
return parameterMap;
}
private void cacheInputStream() throws IOException {
cachedBytes = new ByteArrayOutputStream();
byte[] buffer = new byte[bufferLength];
int length;
InputStream is = super.getInputStream();
while ((length = is.read(buffer)) != -1) {
cachedBytes.write(buffer, 0, length);
}
}
private void cacheBodyAsString() throws IOException {
if (cachedBytes == null)
cacheInputStream();
this.body = cachedBytes.toString("UTF-8");
}
private void addParametersFromBody() {
if(this.body == null || this.body.isEmpty())
return;
String[] params = this.body.split("&");
String[] value = new String[1];
for (String param : params) {
String key = param.split("=")[0];
value[0] = param.split("=")[1];
parameterMap.putIfAbsent(key, value);
}
}
class CachedServletInputStream extends ServletInputStream {
private final ByteArrayInputStream buffer;
public CachedServletInputStream(byte[] contents) {
this.buffer = new ByteArrayInputStream(contents);
}
@Override
public int read() {
return buffer.read();
}
@Override
public boolean isFinished() {
return buffer.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new RuntimeException("Not implemented");
}
}
}
我尝试运行您提到的您正在使用的代码,我认为已接受的答案可能无法解决您的问题,因为它很旧。似乎您还需要覆盖getParameter
、getParameterMap
和getParameterValures
方法。我试图根据同一帖子中的这个答案来做到这一点,似乎它是有效的。这是代码:
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedBytes;
private String body;
private Map<String, String[]> parameterMap;
public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
parameterMap = super.getParameterMap();
cacheBodyAsString();
System.out.println("The Body read into a String is: " + body);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (cachedBytes == null)
cacheInputStream();
return new CachedServletInputStream(cachedBytes.toByteArray());
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public String getParameter(String key) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(key);
return values != null && values.length > 0 ? values[0] : null;
}
@Override
public String[] getParameterValues(String key) {
Map<String, String[]> parameterMap = getParameterMap();
return parameterMap.get(key);
}
@Override
public Map<String, String[]> getParameterMap() {
return parameterMap;
}
private void cacheInputStream() throws IOException {
// Cache the inputstream in order to read it multiple times
cachedBytes = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 50];
int length;
InputStream is = super.getInputStream();
while ((length = is.read(buffer)) != -1) {
cachedBytes.write(buffer, 0, length);
}
}
private void cacheBodyAsString() throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 50];
int length;
InputStream is = getInputStream();
while ((length = is.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
body = result.toString("UTF-8");
}
}
public class CachedServletInputStream extends ServletInputStream {
private final ByteArrayInputStream buffer;
public CachedServletInputStream(byte[] contents) {
this.buffer = new ByteArrayInputStream(contents);
}
@Override
public int read() {
return buffer.read();
}
@Override
public boolean isFinished() {
return buffer.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new RuntimeException("Not implemented");
}
}
这只是一个示例实现。我强烈建议遵循上面提到的答案中指定的步骤,因为它看起来比较新,而且还可以确保从正文和查询字符串中读取参数。我的代码只是一个示例草图,看看它是否按预期工作。
我正在基于Tomcat servlet和NIO创建服务。输入时有大的XML请求(约100 MB),通过HTML POST方法发送。我只想流前8千磅,然后立即发送响应到客户端。 当我尝试发送小请求(内容中只有几行)时,套接字工作正常。 2016-02-01 10:44:52 Http11NioProtocol[DEBUG]套接字:[org.apache.tomcat.util.net.NioEndp
我如何解析JSON请求之类的东西? 示例代码: 带有_名称的位置_为无
我正在使用名为“更新人员”的Jmete对HTTP补丁方法请求进行性能测试。这里的情况是更新人员依赖于另一个名为“创建人员”的请求。创建人员将返回一个“人员ID”作为响应,我将使用该ID发送更新请求。所以我不能仅使用更新人员请求进行性能测试。这是我的Jmete测试计划布局: 测试仪测试计划 当我运行测试计划时,两个请求的性能都比单独测试Create Person慢得多。我的问题是: 测试两个超文本传
谢谢你,Mahadev S
问题内容: 我有一个实现接口的类型,该接口在其方法中检查传入的HTTP请求,采取某些措施,然后将请求转发到反向代理处理程序()。 只要我仅检查基本的请求属性(例如URL或标头),此方法就可以正常工作。 当我想检查传入的POST请求的主体(例如,通过调用然后使用属性)时,将请求传递到反向代理后,就会遇到错误: 我认为发生这种情况是因为查看HTTP请求的正文会导致流被耗尽,这意味着代理处理程序无法再次
我想通过Spring过滤器或方面记录超文本传输协议请求中的请求参数。我尝试了不同的方法,但请求参数为空或未调用方法。我使用的是POSTMAN,它是一个POST请求。 http://localhost:8080/available data 请求正文示例: {“keyUserAgent”:“CFNetwork/1209 Darwin/20.2.0”,“locale”:“en_US”,“eid”:“8