摘要: 大家知道, StringMVC中@RequestBody是读取的流的方式, 如果在之前有读取过流后, 发现就没有了.

我们来看一下核心代码: filter中主要做的事情, 就是来校验请求是否合法, 是否有篡改过值.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (Boolean.valueOf(authentication)) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (BasicdataCommonsConstant.POST.equalsIgnoreCase(httpServletRequest.getMethod())) {
// 防止流读取一次后就没有了, 所以需要将流继续写出去
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
String body = HttpHelper.getBodyString(requestWrapper);
if (StringUtils.isBlank(body)) {
LOGGER.error("非法请求, 没有APP_KEY, APP_SECRET");
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_FROMTYPE)));
return;
}
Map<String, String> parameters = gson.fromJson(body, new TypeToken<Map<String, String>>() {
}.getType()); String APP_KEY = parameters.get("appKey");
String APP_SECRET = parameters.get("appSecret"); TAuthUser authUser = authUserMap.get(APP_KEY);
if (authUser == null) {
LOGGER.error("非法请求, 没有APP_KEY, APP_SECRET");
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_FROMTYPE)));
return;
} else if (StringUtils.isBlank(APP_SECRET)) {
LOGGER.error("非法请求, APP_SECRET为空, user={}", gson.toJson(authUser));
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_FROMTYPE_AND_KEY_CANNT_BE_NULL)));
return;
} else if (!APP_SECRET.equals(authUser.getAppSecret())) {
LOGGER.error("非法请求: 没有APP_KEY, APP_SECRET不匹配. user={}, password={}, name={}", APP_KEY, APP_SECRET, authUser.getName());
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_KEY)));
return;
}
String SIGNATURE = parameters.get("signature");
// 对参数进行签名
String md5 = SignatureUtil.decryptSignature(parameters);
if (!md5.equals(SIGNATURE)) {
LOGGER.error("非法请求, signature ={}", SIGNATURE);
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_SIGNATURE_ERROR)));
return;
}
threadLocalUser.setAuthUser(authUser);
chain.doFilter(requestWrapper, response);
}
}
chain.doFilter(request, response);
}

大家都知道, 流只能读一次, 读了就没有了, 为了后面的代码还能够取得流, 我们应该还需要将其写出去才行.

所以, 我新建立了一个类. 看代码:

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset; /**
* Created with antnest-platform
* User: chenyuan
* Date: 12/31/14
* Time: 8:49 PM
*/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
} @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();
} @Override
public boolean isFinished() {
return false;
} @Override
public boolean isReady() {
return false;
} @Override
public void setReadListener(ReadListener readListener) { }
};
}
} import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream; /**
* Created with antnest-platform
* User: chenyuan
* Date: 12/24/14
* Time: 10:39 AM
*/
public class HttpHelper { /**
* 获取请求Body
*
* @param request
* @return
*/
public static String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} 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();
} }

请注意这里的编码, 最好将其转换成UTF-8的编码格式, 不然你获取到的中文则会使乱码的. 我自己也习惯于UTF-8的编码.

这样子就应该差不多了哦~

解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法的更多相关文章

  1. 解决在mysql表中删除自增id数据后,再添加数据时,id不会自增1的问题

    https://blog.csdn.net/shaojunbo24/article/details/50036859 问题:mysql表中删除自增id数据后,再添加数据时,id不会紧接.比如:自增id ...

  2. ASP.NET Core 2.0 中读取 Request.Body 的正确姿势

    原文:ASP.NET Core 中读取 Request.Body 的正确姿势 ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream ...

  3. Spring拦截器中通过request获取到该请求对应Controller中的method对象

    背景:项目使用Spring 3.1.0.RELEASE,从dao到Controller层全部是基于注解配置.我的需求是想在自定义的Spring拦截器中通过request获取到该请求对应于Control ...

  4. SpringMVC中redirect跳转后如何保存Model中的数据?

    @RequestMapping(value = "delete-user", method = RequestMethod.POST) public String deleteUs ...

  5. 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题

    首先我们来描述一下在开发中遇到的问题,场景如下: 比如我们要拦截所有请求,获取请求中的某个参数,进行相应的逻辑处理:比如我要获取所有请求中的公共参数 token,clientVersion等等:这个时 ...

  6. ASP.NET Core 中读取 Request.Body 的正确姿势

    ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream —— 不允许 Request.Body.Position=0 ,这就意味着只能 ...

  7. 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?

    原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...

  8. 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.

    由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...

  9. java读取request中的xml

    java读取request中的xml   答: // 读取xml InputStream inputStream; StringBuffer sb = new StringBuffer(); inpu ...

随机推荐

  1. C# Winform TCP发消息

    服务端: 代码: using System; using System.Collections.Generic; using System.IO; using System.Net; using Sy ...

  2. centOs7.5.64以上版本的操作系统搭建GitLab记录

    一. 安装并配置必要的依赖关系在CentOS系统上安装所需的依赖:ssh,防火墙,postfix(用于邮件通知) ,wget,以下这些命令也会打开系统防火墙中的HTTP和SSH端口访问. 1.安装ss ...

  3. JZOJ8月15日提高组反思——2020年暑假终结篇

    JZOJ8月15日提高组反思--2020年暑假终结篇 T1 仙人掌最短路 抱歉我只会最短路 仙人掌是啥? 听说是缩点+\(LCA\) 最短路30 T2 直接暴力计算 正解\(DP\) \(amazin ...

  4. PyQt(Python+Qt)学习随笔:QSlider滑动条部件功能简介

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 Designer输入部件中的Horizo ...

  5. PyQt(Python+Qt)学习随笔:QCommandLinkButton的特征及用途

    CommandLinkButton是Windows Vista引入的新控件,,它的预期用途与单选按钮类似,用于在一组互斥选项之间进行选择.命令链接按钮不应单独使用,而应作为向导和对话框中单选按钮的替代 ...

  6. MapReduce简单执行过程及Wordcount案例

    MapReducer运行过程 以单词统计为案例. 假如现在文件中存在如下内容: aa bb aa cc dd aa 当然,这是小文件,如果文件大小较大时会将文件进行 "切片" ,此 ...

  7. Shiro remeberMe反序列化漏洞复现(Shiro-550)

    Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能.Shiro框架直观.易用,同时也能提供健壮的安全性.在Apache Shiro编号为550的 issu ...

  8. tensorflow 小记——如何对张量做任意行求和,得到新tensor(一种方法:列表生成式)

    希望实现图片上的功能 import tensorflow as tfa = tf.range(10,dtype=float)b = aa = tf.reshape(a,[-1,1])a = tf.ti ...

  9. AcWing 180. 排书

    AStar 最坏情况\(O(log_2560 ^ 4)\) 用\(AStar\)算法做了这题,程序跑了\(408ms\). 相比于\(IDA*\)的\(100ms\)左右要慢上不少. 且\(A*\)由 ...

  10. GitLab的基本了解和使用

    使用前提 GitLab账号 安装好git VSCODE && 配置GitPath 在vscode里配置GitPath file-preferences-setting 在search ...