ServletRequest中getReader()和getInputStream()只能调用一次的解决办法(转)
原文地址:http://liwx2000.iteye.com/blog/1542431
原文作者:liwx2000
为了提高项目安全性,拦截非法访问,要给项目增加了一个过滤器,拦截所有的请求,校验是否有不安全因素。
这个过程就遇到了一个问题:ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。没办法,就去网上搜罗了一通,发现了一个超赞的解决方法。为了记录备案,无耻的转了过来,原文地址在上,内容在下。
1. 查看了下ServletRequest的说明,如下:
/**
* Retrieves the body of the request as binary data using
* a {@link ServletInputStream}. Either this method or
* {@link #getReader} may be called to read the body, not both.
*
* @return a {@link ServletInputStream} object containing
* the body of the request
*
* @exception IllegalStateException if the {@link #getReader} method
* has already been called for this request
*
* @exception IOException if an input or output exception occurred
*
*/ public ServletInputStream getInputStream() throws IOException; /**
* Retrieves the body of the request as character data using
* a <code>BufferedReader</code>. The reader translates the character
* data according to the character encoding used on the body.
* Either this method or {@link #getInputStream} may be called to read the
* body, not both.
*
*
* @return a <code>BufferedReader</code>
* containing the body of the request
*
* @exception UnsupportedEncodingException if the character set encoding
* used is not supported and the
* text cannot be decoded
*
* @exception IllegalStateException if {@link #getInputStream} method
* has been called on this request
*
* @exception IOException if an input or output exception occurred
*
* @see #getInputStream
*
*/ public BufferedReader getReader() throws IOException;
两个方法都注明方法只能被调用一次,由于RequestBody是流的形式读取,那么流读了一次就没有了,所以只能被调用一次。既然是因为流只能读一次的原因,那么只要将流的内容保存下来,就可以实现反复读取了。byte数组允许被多次读取,而不会丢失内容。下面使用byte数组将流的内容保存下来。
2. 工具方法:
先将RequestBody保存为一个byte数组,然后通过Servlet自带的HttpServletRequestWrapper类覆盖getReader()和getInputStream()方法,使流从保存的byte数组读取。然后再Filter中将ServletRequest替换为ServletRequestWrapper。
代码如下:
BodyReaderHttpServletRequestWrapper类包装ServletRequest,将流保存为byte[],然后将getReader()和getInputStream()方法的流的读取指向byte[]。
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader; import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import jodd.JoddDefault;
import jodd.io.StreamUtil; public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
throws IOException {
super(request);
// body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
// 因为http协议默认传输的编码就是iso-8859-1,如果使用utf-8转码乱码的话,可以尝试使用iso-8859-1
body = StreamUtil.readBytes(request.getReader(), "iso-8859-1");
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
} @Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() { @Override
public int read() throws IOException {
return bais.read();
}
};
} }
3. 在Filter中的使用:
在Filter中将ServletRequest替换为ServletRequestWrapper
public class HttpServletRequestReplacedFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//Do nothing
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(request instanceof HttpServletRequest) {
requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
}
if(null == requestWrapper) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
//Do nothing
}
}
ServletRequest中getReader()和getInputStream()只能调用一次的解决办法(转)的更多相关文章
- ServletRequest中getReader()和getInputStream()只能调用一次的解决办法
转载:http://blog.sina.com.cn/s/blog_870cd7b90101fg58.html 最近使用spring mvc做项目,数据格式是json,有一个功能是实现记录请求的参数, ...
- 关于springmvc时request的getReader()和getInputStream()只能调用一次的解决办法
最近准备在原有的SSM项目的基础上添加完善的日志分析,由于是APP的后台系统,之前在规划APP的时候,并没有在APP上做埋点的处理,而如果想要进行埋点处理的话,对于未能新升级的APP用户来说,就是去了 ...
- 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...
- es6 Object.assign ECMAScript 6 笔记(六) ECMAScript 6 笔记(一) react入门——慕课网笔记 jquery中动态新增的元素节点无法触发事件解决办法 响应式图像 弹窗细节 微信浏览器——返回操作 Float 的那些事 Flex布局 HTML5 data-* 自定义属性 参数传递的四种形式
es6 Object.assign 目录 一.基本用法 二.用途 1. 为对象添加属性 2. 为对象添加方法 3. 克隆对象 4. 合并多个对象 5. 为属性指定默认值 三.浏览器支持 ES6 O ...
- c++调用动态库失败解决办法
c++调用动态库失败解决办法 之前写好的程序今天早上过来发现在服务器上出错了,于是就各种查问题,整整一个早上外加下午两个小时都在查这个问题,最终被我找到了问题: 在程序中我发现LoadLibrary( ...
- Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法
Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法 如下面所示,同时导入这两个,会提示其中一个与另一个产生冲突. 1i ...
- .NET在IE9中页面间URL传递中文变成乱码的解决办法
在.Net的项目中,鼠标点击查询按钮,转到查询页面,但URL中包含中文时,传到服务器端后,中文变成了乱码(只有IE9出现该问题). 尝试使用Server.UrlEncode()进行编码, ...
- Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法
Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法 先上个图.语法提示支持到 Microsoft Dynamics xRM API 8.2 也就是cr ...
- electron-vue中使用iview 报错this. is readonly的解决办法
title: electron-vue中使用iview 报错this. is readonly的解决办法 toc: false date: 2019-02-12 19:33:28 categories ...
随机推荐
- 获得HttpServletResponse及其他对象
下面只列出获得 HttpServletResponse 对象的方法,获得 HttpServletRequest 对象方法类似. 在struts1.x Action类的execute方法中,有四个参数, ...
- (转)Eclipse/Myeclipse 注释注释模板
Window -->preferences --> Java --> Code Style --> Code Templates --> Comments --> ...
- 大学生程序猿IT情书“2014爱的告白挑战赛”获奖名单及优秀情书展示系列之 - 【IT术语】情书+【搞笑另类】情书
经过专家评委们的层层精心评选和认真讨论,恭喜下面同学终于入选CSDN高校俱乐部"大学生程序猿IT情书2014爱的告白挑战赛活动"优胜者名单.获奖者将在本周内收到邮件通知.请依照邮件 ...
- SqlServer 笔记
问题一:这标红色的符号 取掉 一直没有见过标红色的符号,尝试把这些符号粘贴出来到 notepad 发现它是乱码,尝试将它粘贴到sql查询分析器里,发现它显示空白.对于这种数据,一直想着找到这个acsi ...
- Socket tips: UDP Echo service - Server code
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/soc ...
- FoxOne---一个快速高效的BS框架
FoxOne---一个快速高效的BS框架--(1) FoxOne---一个快速高效的BS框架--(2) FoxOne---一个快速高效的BS框架--(3) FoxOne---一个快速高效的BS框架-- ...
- js实现数字分页
///js数字分页 返回数组function page(pageCount, sideNum, pageNum) { //其实页 var startNum = 0; //结束页 ...
- redis cluster 集群搭建步骤和注意事项
1.安装Ubuntu ,修改root的密码. sudo passwd (apt-get update 更新系统) 2.安装 Gcc 和G++ sudo apt-get install build- ...
- 《大话移动 APP 测试》
<大话移动 APP 测试> wiki: Software testing 第5章 常用工具介绍和实践 Android.iOS Monkey Android SDK 提供的一个工具:发送伪随 ...
- Swift--控制流与oc不同的地方
1.For-in循环中... for index in 1...5 { print("\(index) times 5 is \(index * 5)") } for _ in 1 ...