HttpRequest中InputStream只能一次性读取问题采坑
2021-02-05 04:15
标签:report har deb 过滤 bool 原理 wrap 数据读取 框架 场景:前端在request body中传了多个参数,为了方便使用@RequestBody映射成相应的参数对象。 问题:部署到测试后对象参数始终是空的,传的参数无法映射。 原因分析:@RequestBody 原理上就是spring在进行请求转发时,通过InputStream读取Request body中的数据,然后分装成指定的对象类型参数。所以怀疑问题出在数据读取上,经过资料查询发现HttpServletRequest的数据流只能被读取一次,读取后就不能再重置。所以排查项目拦截器中使用到Request的InputStream的地方,果然发现:在日志输出时使用InputStream读取了Request中的数据 解决方法:将Request中的数据读取后缓存下来。 1、继承HttpServletRequestWrapper,将Request请求中的数据读取完缓存到封装类中。 2、将包装后的HttpServletRequest传递到后面的请求链路中。 还有一个知识点:因为第一次读取Request中的数据是在拦截器Interceptor中,而缓存Request中的数据是在过滤器Filter中做的,所以就涉及到两者的执行顺讯问题。Filter依赖于Servlet容器,基于函数回调;Interceptor依赖于web框架(如SpringMVC),基于java反射,两者并没有什么关系,而Filter的执行在Interceptor之前,盗用网上一张执行流程图,如下: HttpRequest中InputStream只能一次性读取问题采坑 标签:report har deb 过滤 bool 原理 wrap 数据读取 框架 原文地址:https://www.cnblogs.com/jing-yi/p/14367455.html@PostMapping(value = "/game/sync")
public WebMessage gameMsgReport(UserInfo userInfo,@RequestBody GameMsg msgJson){
gameService.gameMsgReport(userInfo.getUserId(), msgJson);
return WebMessage.DEFAULT;
}
accessLogger.debug("user access,requestURI = {},headers = {},params = {}",request.getRequestURI(),ServletUtils.getHeaderInfo(request),ServletUtils.getParameters(request));
1 public static String getParameters(HttpServletRequest request){
2 String params = request.getQueryString();
3 if (StringUtils.isNotBlank(params)) {
4 return params;
5 }
6 try {
7 StringBuilder stringBuilder = new StringBuilder();
8 BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
9 String inputStr;
10 while ((inputStr = streamReader.readLine()) != null) {
11 stringBuilder.append(inputStr);
12 }
13 return stringBuilder.toString();
14 } catch (Exception e) {
15 return null;
16 }
17 }
1 @Slf4j
2 public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {
3
4 private final byte[] body;
5
6 private static final int BUFFER_START_POSITION = 0;
7
8 private static final int CHAR_BUFFER_LENGTH = 1024;
9
10 public RepeatedlyReadRequestWrapper(HttpServletRequest request) throws IOException
11 {
12 super(request);
13 StringBuilder stringBuilder = new StringBuilder();
14
15 InputStream inputStream = null;
16 try {
17 inputStream = request.getInputStream();
18 } catch (IOException e) {
19 log.error("Error reading the request body…", e);
20 }
21 if (inputStream != null) {
22 try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
23 char[] charBuffer = new char[CHAR_BUFFER_LENGTH];
24 int bytesRead;
25 while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
26 stringBuilder.append(charBuffer, BUFFER_START_POSITION, bytesRead);
27 }
28 } catch (IOException e) {
29 log.error("Fail to read input stream",e);
30 }
31 } else {
32 stringBuilder.append("");
33 }
34 body = stringBuilder.toString().getBytes();
35 }
36
37 @Override
38 public BufferedReader getReader() throws IOException
39 {
40 return new BufferedReader(new InputStreamReader(getInputStream()));
41 }
42
43 @Override
44 public ServletInputStream getInputStream() throws IOException
45 {
46 final ByteArrayInputStream bais = new ByteArrayInputStream(body);
47
48 return new ServletInputStream(){
49
50 @Override
51 public boolean isFinished()
52 {
53 return false;
54 }
55
56 @Override
57 public boolean isReady()
58 {
59 return false;
60 }
61
62 @Override
63 public void setReadListener(ReadListener listener)
64 {
65
66 }
67
68 @Override
69 public int read() throws IOException
70 {
71 return bais.read();
72 }
73
74 };
75
76 }
77
78 @Override
79 public String getHeader(String name)
80 {
81 return super.getHeader(name);
82 }
83
84 @Override
85 public Enumeration
1 @Component
2 @WebFilter
3 public class RepeatlyReadFilter implements Filter {
4
5 @Override
6 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
7 if (request instanceof HttpServletRequest) {
8 request = new RepeatedlyReadRequestWrapper((HttpServletRequest) request);
9 }
10 chain.doFilter(request, response);
11 }
12 }
上一篇:【js效果】下拉菜单
下一篇:js节日
文章标题:HttpRequest中InputStream只能一次性读取问题采坑
文章链接:http://soscw.com/index.php/essay/51165.html