拦截器如何获取HttpServletRequest里body数据
发表于:2023-03-26 作者:安全数据网编辑
编辑最后更新 2023年03月26日,这篇文章主要讲解了"拦截器如何获取HttpServletRequest里body数据",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"拦截器如何获取Htt
这篇文章主要讲解了"拦截器如何获取HttpServletRequest里body数据",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"拦截器如何获取HttpServletRequest里body数据"吧!
一、问题
通过在拦截器中获取request中的json数据,我们可以实现对参数进行校验和改写。问题是参数只能在拦截器里获取一次,往后在controller层就无法获取数据,提示body为空。
在网上查找资料后发现,request的输入流只能读取一次,那么这是为什么呢?
那是因为流对应的是数据,数据放在内存中,有的是部分放在内存中。read 一次标记一次当前位置(mark position),第二次read就从标记位置继续读(从内存中copy)数据。 所以这就是为什么读了一次第二次是空了。 怎么让它不为空呢?只要inputstream 中的pos 变成0就可以重写读取当前内存中的数据。javaAPI中有一个方法public void reset() 这个方法就是可以重置pos为起始位置,但是不是所有的IO读取流都可以调用该方法!ServletInputStream是不能调用reset方法,这就导致了只能调用一次getInputStream()
二、解决办法
HttpServletRequestWrapper是 httpServletRequest 的包装类
新建一个类继承HttpServletRequestWrapper实现对 httpServletRequest 的装饰,用来获取 body 数据
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; private String bodyStr; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); String bodyString = getBodyString(request); body = bodyString.getBytes(Charset.forName("UTF-8")); bodyStr=bodyString; } public String getBodyStr() { return bodyStr; } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return byteArrayInputStream.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } public String getBodyString(HttpServletRequest request) throws IOException { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = request.getInputStream(); reader = new BufferedReader( new InputStreamReader(inputStream, Charset.forName("UTF-8"))); char[] bodyCharBuffer = new char[1024]; int len = 0; while ((len = reader.read(bodyCharBuffer)) != -1) { sb.append(new String(bodyCharBuffer, 0, len)); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); }}
再新建一个 filter 实现对传入的 httpServletRequest 的转换
@WebFilter(filterName = "httpServletRequestWrapperFilter", urlPatterns = {"/*"})public class HttpServletRequestWrapperFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest) { HttpServletRequest httpRequest = (HttpServletRequest) request; //遇到post方法才对request进行包装 String methodType = httpRequest.getMethod(); if ("POST".equals(methodType)) { requestWrapper = new BodyReaderHttpServletRequestWrapper( (HttpServletRequest) request); } } if (null == requestWrapper) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void destroy() { }}
最后在拦截器就可以获取request中body数据
if(request instanceof BodyReaderHttpServletRequestWrapper ){ System.out.println(((BodyReaderHttpServletRequestWrapper) request).getBodyStr()); }
经测试发现并不影响controller层获取body数据
为什么需要在 filter 里进行对 httpServletRequest 的包装转换,直接在拦截器里进行包装不行嘛?
过滤器(Filter)和拦截器(Interceptor)之间的最大区别就是,过滤器可以包装Request和Response,而拦截器并不能用代码描述拦截器和过滤器的流程大概就是这样的:拦截器:void run () { Request request = new Request(); preHandle(request); service(request);}preHandler(Request request) { request = new RequestWrapper(request); //在这里修改Request的引用,不会影响到service方法的request}过滤器void run () { Request request = new Request(); doFilter(request);}doFilter(Request request) { request = new RequestWrapper(request); //在这里修改Request的引用,会影响到service方法的request service(request);}
感谢各位的阅读,以上就是"拦截器如何获取HttpServletRequest里body数据"的内容了,经过本文的学习后,相信大家对拦截器如何获取HttpServletRequest里body数据这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
c语言网络技术和编程语言总结
c语言对应的三级考试网络技术
网站服务器后台如何加防护密码
c语言软件开发步骤
c语言中网络技术知识点
服务器对权限提升的防护措施
怎么在阿里云租服务器
黑苹果能做web服务器吗
c语言和网络技术哪个好考
云服务器2核4G是什么性能
网络安全工程师在哪里报名
灵点网络技术有限公司
长时间搞软件开发
网络安全 绿色上网主题班会
华游网络技术有限公司怎么样
长宁区网络软件开发销售电话
图片站服务器
实时数据库批发
科技互联网教育是什么
扫码共享浴室软件开发
计算机网络技术日
服务器安全防护系统 猎鹰
网络安全法 烟草
济南红色文化馆软件开发系统
邛崃租房软件开发
保定松影软件开发有限公司
网络安全平台宣传画简笔画
微信注册辅助软件开发
数据库网授
工业控制网络安全系统
机柜级安全和服务器安全
游戏加服务器会导致分区吗
山大网络安全专业考研
实时数据库批发
数据库软件图标
登录光遇显示服务器异常
福州传一科技软件开发
戒烟军团无法连接服务器
智慧交通网络安全解决方案
阿里巴巴软件开发薪水