多次读取请求request里数据
如果请求是GET方法,可以直接通过getParameter(String param)方法读取指定参数,可读取多次;
而POST方法的参数是存储在输入流中,只能读一次,不能多次读取。
有时需要在filter里打印请求参数,因而在filter里读取post请求里的输入流后,会导致具体的controller里拿不到请求参数。
解决方法:
- 采用ThreadLocal,在filter里把读取到的post参数存入ThreadLocal里,而controller就可以再从ThreadLocal里把请求参数读取出来
- 使用servlet提供的HttpServletRequestWrapper类,重写相关ServletRequest方法,实现多次读取的能力
1.ThreadLocal方法
ThreadLocal实现:
public class ThreadCache {
// ThreadLocal里只存储了简单的String对象,也可以自己定义对象,存储更加复杂的参数
private static ThreadLocal<String> threadLocal = new ThreadLocal<String>(); public static String getPostRequestParams{
return threadLocal.get();
} public static void setPostRequestParams(String postRequestParams){
threadLocal.set(postRequestParams);
} public static void removePostRequestParams(){
threadLocal.remove();
}
}
一个简单的filter:
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; /**
* Created by EndStart on 16/12/19.
*/
@WebFilter(value = {"/test/threadLocal/*"})
public class SimpleFilter implements Filter {
private static Logger log = LoggerFactory.getLogger(SimpleFilter.class); @Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
try {
if ("POST".equals(req.getMethod().toUpperCase())) {
// 获取请求参数
byte[] bytes = IOUtils.toByteArray(request.getInputStream());
String params = new String(bytes, req.getCharacterEncoding());
ThreadCache.setPostRequestParams(params);
log.info("filer-post请求参数:[params={}]", params);
} else {
log.info("非post请求");
} chain.doFilter(request, response);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} @Override
public void destroy() { }
}
简单的测试controller:
import com.sankuai.xm.ems.auth.filter.ThreadCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; /**
* Created by Endstart on 16/12/19.
*/
@Controller
@RequestMapping("/test")
public class TestController {
private static Logger log = LoggerFactory.getLogger(TestController.class); @RequestMapping(value = "/threadLocal/getPostRequestParams",method = RequestMethod.POST)
@ResponseBody
public void getPostRequestParams() {
String params = ThreadCache.getPostRequestParams(); log.info("controller-post请求参数:[params={}]", params);
} }
这里我们只保存了post参数,从ThreadLocal中反复读取,而get方法的还需要从request里获取;
2.HttpServletRequestWrapper方法
实现一个HttpServletRequestWrapper子类:
import org.apache.commons.io.IOUtils; import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*; /**
* Created by Endstart on 16/11/30.
*/
public class WrappedHttpServletRequest extends HttpServletRequestWrapper { private byte[] bytes;
private WrappedServletInputStream wrappedServletInputStream; public WrappedHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
// 读取输入流里的请求参数,并保存到bytes里
bytes = IOUtils.toByteArray(request.getInputStream());
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream); // 很重要,把post参数重新写入请求流
reWriteInputStream(); } /**
* 把参数重新写进请求里
*/
public void reWriteInputStream() {
wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));
} @Override
public ServletInputStream getInputStream() throws IOException {
return wrappedServletInputStream;
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(wrappedServletInputStream));
} /**
* 获取post参数,可以自己再转为相应格式
*/
public String getRequestParams() throws IOException {
return new String(bytes, this.getCharacterEncoding());
} private class WrappedServletInputStream extends ServletInputStream { public void setStream(InputStream stream) {
this.stream = stream;
} private InputStream stream; public WrappedServletInputStream(InputStream stream) {
this.stream = stream;
} @Override
public int read() throws IOException {
return stream.read();
} @Override
public boolean isFinished() {
return true;
} @Override
public boolean isReady() {
return true;
} @Override
public void setReadListener(ReadListener readListener) { }
}
}
实现另一个filter:
import com.sankuai.xm.ems.utils.wrap.WrappedHttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; /**
* Created by EndStart on 16/12/19.
*/
@WebFilter(value = {"/test/wrapped/*"})
public class SimpleWrappedFilter implements Filter {
private static Logger log = LoggerFactory.getLogger(SimpleWrappedFilter.class); @Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try {
WrappedHttpServletRequest requestWrapper = new WrappedHttpServletRequest((HttpServletRequest) request); if ("POST".equals(requestWrapper.getMethod().toUpperCase())) {
// 获取请求参数
String params = requestWrapper.getRequestParams();
log.info("filer-post请求参数:[params={}]", params);
} else {
log.info("非post请求");
} // 这里doFilter传入我们实现的子类
chain.doFilter(requestWrapper, response);
} catch (Exception e) {
log.error(e.getMessage(), e);
} } @Override
public void destroy() { }
}
我们在上面的TestController里加入一个新的处理方法:
@RequestMapping(value = "/wrapped/getPostRequestParams",method = RequestMethod.POST)
@ResponseBody
// public void getPostRequestParams(@RequestBody String params) {
public void getPostRequestParams(HttpServletRequest request) throws Exception{
byte[] bytes = IOUtils.toByteArray(request.getInputStream());
String params = new String(bytes, request.getCharacterEncoding()); log.info("controller-post请求参数:[params={}]", params);
}
这种方法里,我们在SimpleWrappedFilter里一个实现了WrappedHttpServletRequest类,其构造器自动读取了servletRequest里的输入流,并把数据保存了下来,最后又把数据重新写入servletRequest里,使得cotroller可以再次从request里读取到输入参数。
多次读取请求request里数据的更多相关文章
- java读取请求中body数据
java读取请求中body数据 /** * 获取request中body数据 * * @author lifq * * 2017年2月24日 下午2:29:06 * @throws IOExcepti ...
- Response ServletContext 中文乱码 Request 编码 请求行 共享数据 转发重定向
Day35 Response 1.1.1 ServletContext概念 u 项目的管理者(上下文对象),服务器启动时,会为每一个项目创建一个对应的ServletContext对象. 1.1.2 ...
- [原创]java WEB学习笔记59:Struts2学习之路---OGNL,值栈,读取对象栈中的对象的属性,读取 Context Map 里的对象的属性,调用字段和方法,数组,list,map
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式
C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...
- nodejs发起HTTPS请求并获取数据
摘要:在网站中有时候需要跨域请求数据,直接用Ajax无法实现跨域,采用其他方式需要根据不同的浏览器做相应的处理.用Nodejs可以很好的解决这些问题,后台引用HTTPS模块,发送和返回的数据均为JSO ...
- django HTTP请求(Request)和回应(Response)对象
Django使用request和response对象在系统间传递状态.—(阿伦)当一个页面被请示时,Django创建一个包含请求元数据的 HttpRequest 对象. 然后Django调入合适的视图 ...
- Android使用HttpUrlConnection请求服务器发送数据详解
HttpUrlConnection是java内置的api,在java.net包下,那么,它请求网络同样也有get请求和post请求两种方式.最常用的Http请求无非是get和post,get请求可以获 ...
- 爬虫 Http请求,urllib2获取数据,第三方库requests获取数据,BeautifulSoup处理数据,使用Chrome浏览器开发者工具显示检查网页源代码,json模块的dumps,loads,dump,load方法介绍
爬虫 Http请求,urllib2获取数据,第三方库requests获取数据,BeautifulSoup处理数据,使用Chrome浏览器开发者工具显示检查网页源代码,json模块的dumps,load ...
- python的post请求抓取数据
python通过get方式,post方式发送http请求和接收http响应-urllib urllib2 python通过get方式,post方式发送http请求和接收http响应-- import ...
随机推荐
- 5shift shell
echo offcopy %systemroot%\system32\taskmgr.exe %systemroot%\system32\sethc.execopy %systemroot%\syst ...
- 单页应用引擎的写法artTemplate
使用到了ba-haschange.js <script src="../style/js/plugin/template-native-debug.js"></s ...
- 实现 winform 异步跨线程访问UI控件
在开发winform时经常会用到多线程防止界面出现假死现象,比如当你单击某个按钮时,需要执行很多代码,但是在执行过程中想实时的将当前执行的情况报告给用户,类型进度条或文本什么的. 这个时候很显然,如果 ...
- 【小结】有关mysql扩展库和mysqli扩展库的crud操作封装
现阶段php如果要操作mysql数据库 php给我们提供了3套库 1.mysql扩展库 面向过程操作 2.mysqli扩展库 面向对象操作和面向过程操作并存 安全性和效率高于mysql扩展库 ...
- Git中从远程的分支获取最新的版本到本地
Git中从远程的分支获取最新的版本到本地有这样2个命令: 1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge git fetch origin mastergit l ...
- C语言的编译过程和GCC编译参数
C语言的编译一般有三个步骤: 预编译: gcc -E -o a.e a.c 预编译a.c文件,生成的目标文件名为a.e 预编译就是将include包含的头文件内容替换到C文件中,同时删除代码中没用的注 ...
- 简单学C——第四天
数组 在学数组之前,有必要把前面的知识复习一遍,当然我的复习,仅仅只是提一下,而对于你,则应该认真的看一下前面的知识点,不懂可以百度,哈哈. 前面我们大致学了 1.定义变量,2.数据的输入与输出,3. ...
- win7下配置IIS服务器方法
网站爱好初学者必看的win7系统配置自己的IIS,可以在你自己的电脑上配置网站服务器发不到网上,下面就跟着我的步骤一起做吧100%成功. 步骤方法 1.点击开始-------控制面板这个就是打开的控制 ...
- NET Core站点部署到Linux服务器
.NET跨平台之旅:将QPS 100左右的ASP.NET Core站点部署到Linux服务器上 今天下午我们将生产环境中一个单台服务器 QPS(每秒请求数)在100左右的 ASP.NET Core 站 ...
- matlab常用小函数(二)
numel 元素个数 assert 表达式为假时输出某个字符串 int2str 整形转化为字符串型 numel(A) 返回A中的元素个数,A可以是任何的数据结构,如向量.矩阵.元胞.结构体等 asse ...