软件编程
位置:首页>> 软件编程>> java编程>> Springboot如何利用 * 拦截请求信息收集到日志详解

Springboot如何利用 * 拦截请求信息收集到日志详解

作者:Leil_blogs  发布时间:2023-03-09 02:30:57 

标签:springboot, , ,请求
目录
  • 1、需求

  • 2、问题

  • 2、获取

    • 1)导入依赖为了获取客户端类型、操作系统类型、ip、port

    • 2)封装获取body字符串的工具类

    • 3) * 类

    • 4)继承 HttpServletRequestWrapper类

    • 5)过滤器类

    • 6) * 过滤器配置类

  • 总结

    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("]");

    //***这里的clientInfo就是所有信息了,请根据自己的日志框架进行收集***
           System.out.println(clientInfo);

    //返回ture才会继续执行,否则一直拦截住
           return true;
       }
    }

    4)继承 HttpServletRequestWrapper类


    package com.btrc.access.filter;

    import com.btrc.access.util.RequestUtil;

    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.*;
    import java.nio.charset.Charset;

    public class AccessRequestWrapper extends HttpServletRequestWrapper {
       private final byte[] body;

    public AccessRequestWrapper(HttpServletRequest request) {
           super(request);
           body = RequestUtil.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) {

    }
           };
       }
    }

    5)过滤器类


    package com.btrc.access.filter;

    import org.apache.commons.lang.StringUtils;
    import org.springframework.http.HttpMethod;

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;

    public class AccessFilter implements Filter {
       @Override
       public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
       public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
           HttpServletRequest request = (HttpServletRequest) servletRequest;
           //如果是POST走自己的继承的HttpServletRequestWrapper类请求,否则走正常的请求
           if(StringUtils.equalsIgnoreCase(HttpMethod.POST.name(), request.getMethod())){
               //一定要在判断中new对象,否则还会出现Stream closed问题
               filterChain.doFilter(new AccessRequestWrapper(request),servletResponse);
           }else{
               filterChain.doFilter(servletRequest,servletResponse);
           }
       }

    @Override
       public void destroy() {

    }
    }

    6) * 过滤器配置类


    package com.btrc.access.config;

    import com.btrc.access.filter.AccessFilter;
    import com.btrc.access.filter.RequestInterceptor;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    import javax.servlet.Filter;

    /**
    * * 过滤器配置类
    */
    @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("/**");
       }
    }

    来源:https://www.cnblogs.com/leilcoding/p/15131470.html

    0
    投稿

    猜你喜欢

    手机版 软件编程 asp之家 www.aspxhome.com