解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法
我们来看一下核心代码: 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中读取不到的做法的更多相关文章
- 解决在mysql表中删除自增id数据后,再添加数据时,id不会自增1的问题
https://blog.csdn.net/shaojunbo24/article/details/50036859 问题:mysql表中删除自增id数据后,再添加数据时,id不会紧接.比如:自增id ...
- ASP.NET Core 2.0 中读取 Request.Body 的正确姿势
原文:ASP.NET Core 中读取 Request.Body 的正确姿势 ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream ...
- Spring拦截器中通过request获取到该请求对应Controller中的method对象
背景:项目使用Spring 3.1.0.RELEASE,从dao到Controller层全部是基于注解配置.我的需求是想在自定义的Spring拦截器中通过request获取到该请求对应于Control ...
- SpringMVC中redirect跳转后如何保存Model中的数据?
@RequestMapping(value = "delete-user", method = RequestMethod.POST) public String deleteUs ...
- 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题
首先我们来描述一下在开发中遇到的问题,场景如下: 比如我们要拦截所有请求,获取请求中的某个参数,进行相应的逻辑处理:比如我要获取所有请求中的公共参数 token,clientVersion等等:这个时 ...
- ASP.NET Core 中读取 Request.Body 的正确姿势
ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream —— 不允许 Request.Body.Position=0 ,这就意味着只能 ...
- 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?
原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...
- 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...
- java读取request中的xml
java读取request中的xml 答: // 读取xml InputStream inputStream; StringBuffer sb = new StringBuffer(); inpu ...
随机推荐
- SkyWalking —— 分布式应用监控与链路追踪
SkyWalking 是一个应用性能监控系统,特别为微服务.云原生和基于容器(Docker, Kubernetes, Mesos)体系结构而设计.除了应用指标监控以外,它还能对分布式调用链路进行追踪. ...
- 20200428_在centos7.2上挂载ntfs和备份文件到移动硬盘
[root@localhost ~]# fdisk -l 磁盘 /dev/sda:2000.4 GB, 2000398934016 字节,3907029168 个扇区 - 设备 Boot Start ...
- redis雪崩,击穿,穿透
redis穿透 什么是redis穿透? 1.查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存 2.这将导致这个不存在的数据每次请求都要到存储层 ...
- PyQt(Python+Qt)学习随笔:自定义信号在emit发射信号时报错:AttributeError: object has no attribute
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 如果使用自定义信号,一定要记得信号是类变量,必须在类中定义,不能在实例 ...
- 推荐系统实践 0x0c FM系列
逻辑回归(LR) 在介绍FM系列之前,我想首先简单介绍一下逻辑回归.通常来说,逻辑回归模型能够综合利用更多的信息,如用户.物品.上下文等多种不同的特征,生成更为全面的结果.另外,逻辑回归将推荐问题看成 ...
- 5、Spring Cloud Ribbon
1.Ribbon简介 (1).Ribbon介绍 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具. Ribbon是Netflix发布的开源项目,主 ...
- js- 实现属性名的拼接 obj['name']
obj.name---->obj[name] 这两种调用方式一样,使用obj.name内部转换成 obj['name'], 使用obj['name']更快. obj['name'] 里面必须是 ...
- Photoshop 2020特别版,内置多款实用插件,功能强大
Adobe Photoshop 2020特别21.2.1.265版 组件精简 同时优化软件配置,添加多款实用强大的插件,具体详细修改精简内容如下: -精简运行库及更新组件: -精简创意云Creativ ...
- ip 子网掩码、网络地址、广播地址计算
例:已知ip 16.158.165.91/22子网掩码 根据22 得知子网掩码占22位 即:11111111.11111111.11111100.00000000 == 255.255.252. ...
- 2020中国.NET开发者峰会近50场热点技术专题揭秘
简介 / Summary 2014年微软组织并成立.NET基金会,微软在成为主要的开源参与者的道路上又前进了一步.2014年以来已经有众多知名公司加入.NET基金会,微软,Google,AWS三大云厂 ...