SpringBoot 实战,自定义 Filter 优雅获取请求参数和响应结果

本文介绍了如何在SpringBoot中自定义Filter来优雅地获取请求参数和响应结果。通过继承OncePerRequestFilter,关注isAsyncDispatch和isAsyncStarted方法,确保在错误处理和异步调度中正确过滤。核心代码展示了如何处理ContentCachingRequestWrapper和ContentCachingResponseWrapper,以实现多次读取请求和响应内容。最后,文章通过四种不同类型的请求(GET、POST、上传文件、下载文件)验证了自定义Filter的运行效果。
部署运行你感兴趣的模型镜像

Subclasses may use isAsyncDispatch(HttpServletRequest) to determine when a filter is invoked as part of an async dispatch, and use isAsyncStarted(HttpServletRequest) to determine when the request has been placed in async mode and therefore the current dispatch won’t be the last one for the given request.

Yet another dispatch type that also occurs in its own thread is ERROR. Subclasses can override shouldNotFilterErrorDispatch() if they wish to declare statically if they should be invoked once during error dispatches.

也就是说,Spring 是为了兼容不同的 Web 容器,所以定义了只会执行一次的OncePerRequestFilter

接下来开始定义我们的Filter类:

public class AccessLogFilter extends OncePerRequestFilter {

//… 这里有一些必要的属性

@Override

protected void doFilterInternal(final HttpServletRequest request,

final HttpServletResponse response,

final FilterChain filterChain)

throws ServletException, IOException {

// 如果是被排除的 uri,不记录 access_log

if (matchExclude(request.getRequestURI())) {

filterChain.doFilter(request, response);

return;

}

final String requestMethod = request.getMethod();

final boolean shouldWrapMethod = StringUtils.equalsIgnoreCase(requestMethod, HttpMethod.PUT.name())

|| StringUtils.equalsIgnoreCase(requestMethod, HttpMethod.POST.name());

final boolean isFirstRequest = !isAsyncDispatch(request);

final boolean shouldWrapRequest = isFirstRequest && !(request instanceof ContentCachingRequestWrapper) && shouldWrapMethod;

final HttpServletRequest requestToUse = shouldWrapRequest ? new ContentCachingRequestWrapper(request) : request;

final boolean shouldWrapResponse = !(response instanceof ContentCachingResponseWrapper) && shouldWrapMethod;

final HttpServletResponse responseToUse = shouldWrapResponse ? new ContentCachingResponseWrapper(response) : response;

final long startTime = System.currentTimeMillis();

Throwable t = null;

try {

filterChain.doFilter(requestToUse, responseToUse);

} catch (Exception e) {

t = e;

throw e;

} finally {

doSaveAccessLog(requestToUse, responseToUse, System.currentTimeMillis() - startTime, t);

}

}

// … 这里是一些必要的方法

这段代码就是整个逻辑的核心所在,其他的内容从源码中找到。

分析

这个代码中,整体的逻辑没有特别复杂的地方,只需要注意几个关键点就可以了。

  1. 默认的HttpServletRequestHttpServletResponse中的流被读取一次之后,再次读取会失败,所以要使用ContentCachingRequestWrapperContentCachingResponseWrapper进行包装,实现重复读取。

  2. 既然我们可以自定义Filter,那我们依赖的组件中也可能会自定义Filter,更有可能已经对请求和响应对象进行过封装,所以,一定要先进行一步判断。也就是request instanceof ContentCachingRequestWrapperresponse instanceof ContentCachingResponseWrapper

只要注意了这两点,剩下的都是这个逻辑的细化实现。

运行

接下来我们就运行一遍,看看结果。先定义几种不同的请求:普通 get 请求、普通 post 请求、上传文件、下载文件,这四个接口几乎可以覆盖绝大部分场景。(因为都是比较简单的写法,源码就不赘述了,可以从文末的源码中找到)

先启动项目,然后借助 IDEA 的 http 请求工具:

###普通 get 请求

GET http://localhost:8080/index/get?name=howard

###普通 post 请求

POST http://localhost:8080/index/post

Content-Type: application/json

{“name”:“howard”}

###上传文件

POST http://localhost:8080/index/upload

Content-Type: multipart/form-data; boundary=WebAppBoundary

–WebAppBoundary

Content-Disposition: form-data; name=“file”; filename=“history.txt”

Content-Type: multipart/form-data

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值