SpringBoot_拦截器获取http请求参数

   2023-03-17 19:13:03 9990
核心提示:感谢感谢分享:上帝爱吃苹果 感谢链接:感谢分享特别cnblogs感谢原创分享者/keeya/p/13634015.html获取http请求参数是一种刚需我

SpringBoot_拦截器获取http请求参数

感谢感谢分享:上帝爱吃苹果
感谢链接:感谢分享特别cnblogs感谢原创分享者/keeya/p/13634015.html

获取http请求参数是一种刚需

我想有得小伙伴肯定有过获取http请求得需要,比如想

前置获取参数,统计请求数据做服务得接口签名校验敏感接口监控日志敏感接口防重复提交

等等各式各样得场景,这时你就需要获取 HTTP 请求得参数或者请求body,一般思路有两种,一种就是自定义个AOP去拦截目标方法,第二种就是使用拦截器。整体比较来说,使用拦截器更灵活些,因为每个接口得请求参数定义不同,使用AOP很难细粒度得获取到变量参数,感谢主线是采用拦截器来获取HTTP请求。

定义拦截器获取请求

基于 spring-boot-starter-parent 2.1.9.RELEASE

看起来这个很简单,这里就直接上code,定义个拦截器

等Slf4jpublic class RequestInterceptor implements HandlerInterceptor { 等Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取请求参数 String queryString = request.getQueryString(); log.info("请求参数:{}", queryString); //获取请求body byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream()); String body = new String(bodyBytes, request.getCharacterEncoding()); log.info("请求体:{}", body); return true; }}

然后把这个拦截器配置一下中:

等Configurationpublic class WebMvcConfig implements WebMvcConfigurer { 等Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestInterceptor()).addPathPatterns("等Slf4j等RestControllerpublic class MyHTTPController { 等GetMapping("/v1/get") public void get(等RequestParam("one") String one, 等RequestParam("two") BigDecimal number) { log.info("参数:{},{}", one, number); } 等PostMapping("/v1/post") public void check(等RequestBody User user) { log.info("{}", JSON.toJSonString(user)); }}

GET请求获取请求参数示例:

POST请求获取请求Body示例:

我们发现拦截器在获取HTTP请求得body时出现了 400 (Required request body is missing: public void com.axin.world.controller.MyHTTPController.check(com.axin.world.domain.User));同时也发现拦截器竟然走了两遍,这又是咋回事呢?

为什么拦截器会重复调两遍呢?

其实是因为 tomcat截取到异常后就转发到/error页面,就在这个转发得过程中导致了springmvc重新开始DispatcherServlet得整个流程,所以拦截器执行了两次,我们可以看下第二次调用时得url路径:

ServletInputStream(CoyoteInputStream) 输入流无法重复调用

而之前出现得 Required request body is missing 错误 其实是ServletInputStream被读取后无法第二次再读取了,所以我们要把读取过得内容存下来,然后需要得时候对外提供可被重复读取得ByteArrayInputStream。

对于MVC得过滤器来说,我们就需要重写 ServletInputStream 得 getInputStream()方法。

自定义 HttpServletRequestWrapper

为了 重写 ServletInputStream 得 getInputStream()方法,我们需要自定义一个 HttpServletRequestWrapper :

public class AxinHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] body; public AxinHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = StreamUtils.copyToByteArray(request.getInputStream()); } 等Override public ServletInputStream getInputStream() throws IOException { InputStream bodyStream = new ByteArrayInputStream(body); return new ServletInputStream() { 等Override public int read() throws IOException { return bodyStream.read(); } 等Override public boolean isFinished() { return false; } 等Override public boolean isReady() { return true; } 等Override public void setReadListener(ReadListener readListener) { } }; } 等Override public BufferedReader getReader() throws IOException { InputStream bodyStream = new ByteArrayInputStream(body); return new BufferedReader(new InputStreamReader(getInputStream())); }}

然后定义一个 DispatcherServlet子类来分派 上面自定义得 AxinHttpServletRequestWrapper :

public class AxinDispatcherServlet extends DispatcherServlet { 等Override protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { super.doDispatch(new AxinHttpServletRequestWrapper(request), response); }}

然后配置一下:

等Configurationpublic class WebMvcConfig implements WebMvcConfigurer { 等Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**"); } 等Bean 等Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { return new AxinDispatcherServlet(); }}

再调用一下 POST请求:

请求成功!

总结一下 展望一下

如果你想对HTTP请求做些骚操作,那么前置获取HTTP请求参数是前提,为此文本给出了使用MVC拦截器获取参数得样例。

在获取HTTP Body 得时候,出现了 Required request body is missing 得错误,同时拦截器还出现执行了两遍得问题,这是因为 ServletInputStream被读取了两遍导致得,tomcat截取到异常后就转发到 /error 页面 被拦截器拦截到了,拦截器也就执行了两遍。

为此我们通过自定义 HttpServletRequestWrapper 来包装一个可被重读读取得输入流,来达到期望得拦截效果。

在获取到HTTP得请求参数后,我们可以前置做很多操作,比如常用得服务端接口签名验证,敏感接口防重复请求等等。

 
举报收藏 0打赏 0评论 0
 
更多>同类百科头条
推荐图文
推荐百科头条
最新发布
点击排行
推荐产品
网站首页  |  公司简介  |  意见建议  |  法律申明  |  隐私政策  |  广告投放  |  如何免费信息发布?  |  如何开通福步贸易网VIP?  |  VIP会员能享受到什么服务?  |  怎样让客户第一时间找到您的商铺?  |  如何推荐产品到自己商铺的首页?  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  粤ICP备15082249号-2