Springboot如何利用拦截器拦截请求信息收集到日志详解
1、需求
最近在工作中遇到的一个需求,将请求中的客户端类型、操作系统类型、ip、port、请求方式、URI以及请求参数值收集到日志中,网上找资料说用拦截器拦截所有请求然后收集信息,于是就开始了操作:
2、问题
试了之后发现当请求方式为POST,前端发送数据json时只能用request.getReader()流获取,自信满满从流中获取之后发现请求之后报错:
getInputStream() has already been called for this request...
于是网上找答案,发现是ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。
然后又开始找解决方法,说既然ServletInputStream不支持重新读写,就把流读出来后用容器存储起来,后面就可以多次利用了。
于是继承 HttpServletRequestWrapper类(http请求包装器,其基于装饰者模式实现了HttpServletRequest界面)并实现想要重新定义的方法以达到包装原生HttpServletRequest对象。还需要在过滤器里将原生的HttpServletRequest对象替换成我们的RequestWrapper对象。
测试发现POST请求参数值可以在拦截器类中获取到了,本以为大功告成,又发现GET请求不好使了,开始报错Stream closed,一顿操作发现需要在过滤器进行判断,如果是POST请求走自己的继承的HttpServletRequestWrapper类请求,否则走普通的请求。终于成功!突然舒服了。
2、获取
1)导入依赖为了获取客户端类型、操作系统类型、ip、port
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
2)封装获取body字符串的工具类
package com.btrc.access.util;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class RequestUtil {
public static String getBodyString(HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
try (
InputStream inputStream = request.getInputStream();
BufferedReader 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();
}
return sb.toString();
}
}
3)拦截器类
package com.btrc.access.filter;
import com.btrc.access.util.RequestUtil;
import eu.bitwalker.useragentutils.UserAgent;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("user-agent"));
//客户端类型
String clientType = userAgent.getOperatingSystem().getDeviceType().getName();
//客户端操作系统类型
String osType = userAgent.getOperatingSystem().getName();
//客户端ip
String clientIp = request.getRemoteAddr();
//客户端port
int clientPort = request.getRemotePort();
//请求方式
String requestMethod = request.getMethod();
//客户端请求URI
String requestURI = request.getRequestURI();
//客户端请求参数值
String requestParam;
//如果请求是POST获取body字符串,否则GET的话用request.getQueryString()获取参数值
if(StringUtils.equalsIgnoreCase(HttpMethod.POST.name(), requestMethod)){
requestParam = RequestUtil.getBodyString(request);
}else{
requestParam = request.getQueryString();
}
//客户端整体请求信息
StringBuilder clientInfo = new StringBuilder();
clientInfo.append("客户端信息:[类型:").append(clientType)
.append(", 操作系统类型:").append(osType)
.append(", ip:").append(clientIp)
.append(", port:").append(clientPort)
.append(", 请求方式:").append(requestMethod)
.append(", URI:").append(requestURI)
.append(", 请求参数值:").append(requestParam.replaceAll("\\s*", ""))
.append("]");
/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean httpServletRequestReplacedFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new AccessFilter());
// /* 是全部的请求拦截,和Interceptor的拦截地址/**区别开
registration.addUrlPatterns("/*");
registration.setName("accessRequestFilter");
registration.setOrder(1);
return registration;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**");
}
}
总结
到此这篇关于Springboot如何利用拦截器拦截请求信息收集到日志的文章就介绍到这了,更多相关Springboot拦截请求信息到日志内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341