摘要: 大家知道, 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. 网络拓扑实例之交换机处于同一网络作为DHCP中继与服务器(八)

    组网图形 DHCP中继简介 DHCP中继用于在DHCP服务器和客户端之间转发DHCP报文.当DHCP服务器与客户端不在同一个网段时,需要配置DHCP中继.对于DHCP客户端来说,DHCP中继就是DHC ...

  2. 利用Postman和Chrome的开发者功能探究项目

    利用Postman和Chrome的开发者功能探究项目 controller层研究 前两天忙着写开题报告,没有来得及做项目,今天继续研究一下这个项目. 上次研究到后端的DAO层,研究了一下后端和数据库交 ...

  3. java中的强引用(Strong reference),软引用(SoftReference),弱引用(WeakReference),虚引用(PhantomReference)

    之前在看深入理解Java虚拟机一书中第一次接触相关名词,但是并不理解,只知道Object obj = new Object()类似这种操作的时候,obj就是强引用.强引用不会被gc回收直到gc roo ...

  4. C中memcpy函数用法

    1.函数原型 void *memcpy(void *destin,void *source,unsigned n); 其中, destin代表用于存储复制内容的目标数组,类型强制转换为void*指针. ...

  5. paddleocr安装笔记

    下载解压安装 wget http://npm.taobao.org/mirrors/python/3.7.6/Python-3.7.6.tgztar xvf Python-3.7.6.tgzcd Py ...

  6. VS Code 调试树莓派上的python程序

    安装pip install ptvsd 在py文件前面加代码 import ptvsd ptvsd.enable_attach() ptvsd.wait_for_attach() ptvsd.brea ...

  7. 庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现

    庐山真面目之六微服务架构Consul集群.Ocelot网关集群和Nginx版本实现 一.简介      在上一篇文章<庐山真面目之五微服务架构Consul集群.Ocelot网关和Nginx版本实 ...

  8. Python中判断一个中文是否中文数字的方法

    Python内置功能非常强大,在字符串内置函数中提供了一个判断字符串是否全数字的方法,而且这个方法不只是简单判断阿拉伯数字,包括中文数字和全角的阿拉伯数字都认识,这个函数就是字符串的isnumeric ...

  9. PyQt(Python+Qt)学习随笔:QTreeWidgetItem项的子项索引、删除子项的方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 树型部件QTreeWidget中的QTreeWidgetItem项: 获取子项索引 可通过index ...

  10. Python接口测试-使用requests模块发送post请求

    本篇主要记录下使用python的requests模块发送post请求的实现代码. #coding=utf-8 import unittest import requests class PostTes ...