不知道你们有没有对用户输入的东西进行过敏感校验,如果不进行校验,用户属于一些攻击脚本,那么我们的服务就挂逼啦!所以我们首先需要通过过滤器将用户的数据读出来进行安全校验,这里面涉及到一个动作,就是需要将用户的数据在过滤器中读出来,进行校验,通过之后再放行。

问题

如果我们的数据是get请求倒还好,但是如果是一些数据量比较大,我们需要通过post json的方式来说传递数据的时候,这个时候其实是通过流的方式传递的,如果在过滤器中将参数读取出来之后,然后放行,等到到Servlet的时候,@RequestBody是无法获取到数据的,因为post json使用流传递,流被读取之后就不存在了,所以我们在过滤器中读取之后,@ReqeustBody自然就读不到数据了,同时会报如下一个错误。

在过滤器中读取body中的数据

@WebFilter

@Slf4j

public class CheckUserFilter implements Filter {

@Override

public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

// 在过滤器中读取数据

BufferedReader reader = request.getReader();

StringBuilder sb = new StringBuilder();

String line;

while ((line = reader.readLine()) != null) {

sb.append(line);

}

reader.close();

System.out.println(sb.toString());

filterChain.doFilter(request, res);

}

}

复制代码出现异常,就是说内容已经被读取了,你不能调用了

{"id":"1","username":"bingfeng"}

java.lang.IllegalStateException: UT010003: Cannot call getInputStream(), getReader() already called

at io.undertow.servlet.spec.HttpServletRequestImpl.getInputStream(HttpServletRequestImpl.java:666)

at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:152)

at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:152)

复制代码

解决

HttpServletRequestWrapper

那么出现这种问题怎么办呢?能不能通过一个中间的变量将这些数据保存下来,然后我们就可以一直读取了,这样不就解决了这个问题了吗?那保存在哪里呢?这个时候 HttpServletRequestWrapper 就排上用场了。

这个其实你可以把它理解为Request的包装类,Reqeust中有的方法它都有,我们通过继承这个类,重写该类中的方法,将body中的参数保存一个byte数组中,然后放行的时候将这个包装类传递进去,不就可以一直拿到参数了?

封装Request类

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

private final byte[] body;

/**

* 所有参数的集合

*/

private Map parameterMap;

public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {

super(request);

BufferedReader reader = request.getReader();

body = readBytes(reader);

parameterMap = request.getParameterMap();

}

@Override

public BufferedReader getReader() throws IOException {

ServletInputStream inputStream = getInputStream();

if (null == inputStream) {

return null;

}

return new BufferedReader(new InputStreamReader(inputStream));

}

@Override

public Enumeration getParameterNames() {

Vector vector = new Vector<>(parameterMap.keySet());

return vector.elements();

}

@Override

public ServletInputStream getInputStream() throws IOException {

if (body == null) {

return null;

}

final ByteArrayInputStream bais = new ByteArrayInputStream(body);

return new ServletInputStream() {

@Override

public boolean isFinished() {

return false;

}

@Override

public boolean isReady() {

return false;

}

@Override

public void setReadListener(ReadListener listener) {

}

@Override

public int read() throws IOException {

return bais.read();

}

};

}

/**

* 通过BufferedReader和字符编码集转换成byte数组

*

* @param br

* @return

* @throws IOException

*/

private byte[] readBytes(BufferedReader br) throws IOException {

String str;

StringBuilder retStr = new StringBuilder();

while ((str = br.readLine()) != null) {

retStr.append(str);

}

if (StringUtils.isNotBlank(retStr.toString())) {

return retStr.toString().getBytes(StandardCharsets.UTF_8);

}

return null;

}

}

复制代码将过滤器改造

@WebFilter

@Slf4j

public class CheckUserFilter implements Filter {

@Override

public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request);

// 从Request的包装类中读取数据

BufferedReader reader = requestWrapper.getReader();

StringBuilder sb = new StringBuilder();

String line;

while ((line = reader.readLine()) != null) {

sb.append(line);

}

reader.close();

System.out.println(sb.toString());

filterChain.doFilter(requestWrapper, res);

}

}

复制代码

经过这样的配置之后,我们即使在过滤器中获取了参数,请求也会到达Servlet。

如果基础知识IO那块不是很扎实的话,第一眼看到这个问题确实挺懵逼的。我也是百度之后解决的,确实值得记录一下,有时候我们会对所有请求进来的参数进行保存输出什么的,这个时候如果是post json数据的话,如果不是特别明白,可能也会出现这种问题。

日拱一卒,功不唐捐

更多内容请关注

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[@RequestBody参数已经被读取,究竟是何原因?]http://www.zyiz.net/tech/detail-137520.html

request java获取参数body_@RequestBody参数已经被读取,究竟是何原因?相关推荐

  1. Java获取请求头、参数、路径、

    request.getReader()和request.getParameter("key") 方法只能读取一次,重复读取会报IO异常 第一种 从  ContainerReques ...

  2. Java获取URL中的参数

    先获取想要的字段 throws Exception {URL url = new URL("http://www.runoob.com/html/html-tutorial.html?id= ...

  3. java获取mosquitto连接数_mosquitto 参数配置

    mosquitto 参数配置 1.retry_interval 当QoS为1或2的消息已经被发送后,mosquitto在一段时间内仍未接收到客户端的反馈消息,将重新发送消息. 默认为20秒 2.sys ...

  4. java获取内容为空_Java使用POI读取Word文档时如果文档内容为空时出现异常

    异常如下: org.apache.poi.EmptyFileException: The supplied file was empty (zero bytes long) at org.apache ...

  5. Java获取文档页数_java准确读取word文件页数

    由于本人在做一个网上打印网站,遇到了一个需求是"准确读取word文件页数,从而实现计费功能",通过很长时间的学习.查资料后,终于解决了这个问题,因此把方法写出来,方便有同样需求的人 ...

  6. java获取专辑封面_从MP3中读取专辑封面图片

    首先判断MP3文件中是否含有ID3V2的标签,关于ID3V2的格式有一堆的说法 我嘛,不怎么关心,因此只攻专辑图片,也就是判断是否包含APIC这个标识 找到这个标识其实也就是和解析普通文件一样,每个像 ...

  7. java 获取 邮箱联系人_在android中读取联系人信息的程序,包括读取联系人姓名、手机号码和邮箱...

    /** 读取联系人的信息*/ public voidtestReadAllContacts() { Cursor cursor= this.getContext().getContentResolve ...

  8. java 正则表达式匹配冒号_java 获取冒号后面的参数(正则)实现代码

    我就废话不多说了,大家还是直接看代码吧~ String regEx=":[\S]+"; String sql=" select * from a where id=:id ...

  9. java中正则获取冒号之后_java 获取冒号后面的参数(正则)实现代码

    java 获取冒号后面的参数(正则)实现代码 我就废话不多说了,大家还是直接看代码吧~ String regEx=":[\\S]+"; String sql=" sele ...

最新文章

  1. 《WCF揭秘》:欢迎大家来找我的茬!
  2. 开始简单项目的第二周
  3. 网站https加载不出css样式_Python Web全栈之旅04--Web前端●走入CSS的世界
  4. webAppbuilder微件使用教程3 地理处理微件
  5. Linux下mysql主从复制配置(CentOS7)
  6. 深度学习TF—3.神经网络全连接层
  7. 再谈内核模块加载(二)—模块加载流程(上)
  8. 1024 科学计数法(C语言)测试点4详解
  9. android课程设计多彩的霓虹,Android-自定义TextView(彩色字体与霓虹灯字体以及TextView的多项字体效果)...
  10. k3 审核流程图_K3Cloud 业务流程图Sql
  11. 应聘总经理的答卷,供大家打分
  12. 商品id- item_id /条形码/skuid
  13. 一个屌丝程序员的青春(二六五)
  14. BZOJ1863 [ZJOI2006]trouble 皇帝的烦恼 [思维题,二分答案,动态规划]
  15. 深度诗歌阅读:你永远是个孩子
  16. w7系统路由器虚拟服务器怎么设置方法,win7路由器怎么重新设置
  17. 2022年内蒙古最新建筑八大员(标准员)模拟考试试题及答案
  18. spring-webflux理解
  19. cocos2d-x自代的Json库解析json(转)
  20. 编程过程中常见的内存开辟和释放问题

热门文章

  1. Google浏览器首页被篡改(非常有效的解决方法)
  2. 【示例】《Java程序设计》第二周博文:第二周 计算圆面积
  3. ACL2022论文分类汇总-Prompt、句子表征、检索排序摘要
  4. 近万字带你了解“c++“STL中的各种容器
  5. 外网如何访问本地项目
  6. python猴子吃桃递归_Python猴子吃桃题源码​:请问第一天摘了多少桃?
  7. 如何能百度到自己的博客
  8. steps_per_epoch 与 epochs 的关系
  9. 使用rewrite规则实现将所有到a域名的访问rewrite到b域名
  10. 千兆交换机网线制作方法