最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot記錄Http請求日志的方法

 更新時間:2019年03月18日 14:53:28   作者:Simeone_xu  
這篇文章主要介紹了SpringBoot記錄Http請求日志的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

在使用Spring Boot開發(fā) web api 的時候希望把 request,request header ,response reponse header , uri, method 等等的信息記錄到我們的日志中,方便我們排查問題,也能對系統(tǒng)的數(shù)據(jù)做一些統(tǒng)計。

Spring 使用了 DispatcherServlet 來攔截并分發(fā)請求,我們只要自己實現(xiàn)一個 DispatcherServlet 并在其中對請求和響應做處理打印到日志中即可。

我們實現(xiàn)一個自己的分發(fā) Servlet ,它繼承于 DispatcherServlet,我們實現(xiàn)自己的 doDispatch(HttpServletRequest request, HttpServletResponse response) 方法。

public class LoggableDispatcherServlet extends DispatcherServlet {

  private static final Logger logger = LoggerFactory.getLogger("HttpLogger");

  private static final ObjectMapper mapper = new ObjectMapper();

  @Override
  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
    ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
    //創(chuàng)建一個 json 對象,用來存放 http 日志信息
    ObjectNode rootNode = mapper.createObjectNode();
    rootNode.put("uri", requestWrapper.getRequestURI());
    rootNode.put("clientIp", requestWrapper.getRemoteAddr());
    rootNode.set("requestHeaders", mapper.valueToTree(getRequestHeaders(requestWrapper)));
    String method = requestWrapper.getMethod();
    rootNode.put("method", method);
    try {
      super.doDispatch(requestWrapper, responseWrapper);
    } finally {
      if(method.equals("GET")) {
        rootNode.set("request", mapper.valueToTree(requestWrapper.getParameterMap()));
      } else {
        JsonNode newNode = mapper.readTree(requestWrapper.getContentAsByteArray());
        rootNode.set("request", newNode);
      }

      rootNode.put("status", responseWrapper.getStatus());
      JsonNode newNode = mapper.readTree(responseWrapper.getContentAsByteArray());
      rootNode.set("response", newNode);

      responseWrapper.copyBodyToResponse();

      rootNode.set("responseHeaders", mapper.valueToTree(getResponsetHeaders(responseWrapper)));
      logger.info(rootNode.toString());
    }
  }

  private Map<String, Object> getRequestHeaders(HttpServletRequest request) {
    Map<String, Object> headers = new HashMap<>();
    Enumeration<String> headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
      String headerName = headerNames.nextElement();
      headers.put(headerName, request.getHeader(headerName));
    }
    return headers;

  }

  private Map<String, Object> getResponsetHeaders(ContentCachingResponseWrapper response) {
    Map<String, Object> headers = new HashMap<>();
    Collection<String> headerNames = response.getHeaderNames();
    for (String headerName : headerNames) {
      headers.put(headerName, response.getHeader(headerName));
    }
    return headers;
  }

在 LoggableDispatcherServlet 中,我們可以通過 HttpServletRequest 中的 InputStream 或 reader 來獲取請求的數(shù)據(jù),但如果我們直接在這里讀取了流或內(nèi)容,到后面的邏輯將無法進行下去,所以需要實現(xiàn)一個可以緩存的 HttpServletRequest。好在 Spring 提供這樣的類,就是 ContentCachingRequestWrapper 和 ContentCachingResponseWrapper, 根據(jù)官方的文檔這兩個類正好是來干這個事情的,我們只要將 HttpServletRequest 和 HttpServletResponse 轉(zhuǎn)化即可。

HttpServletRequest wrapper that caches all content read from the input stream and reader, and allows this content to be retrieved via a byte array.
Used e.g. by AbstractRequestLoggingFilter. Note: As of Spring Framework 5.0, this wrapper is built on the Servlet 3.1 API.

HttpServletResponse wrapper that caches all content written to the output stream and writer, and allows this content to be retrieved via a byte array.
Used e.g. by ShallowEtagHeaderFilter. Note: As of Spring Framework 5.0, this wrapper is built on the Servlet 3.1 API.

實現(xiàn)好我們的 LoggableDispatcherServlet后,接下來就是要指定使用 LoggableDispatcherServlet 來分發(fā)請求。

@SpringBootApplication
public class SbDemoApplication implements ApplicationRunner {

  public static void main(String[] args) {
    SpringApplication.run(SbDemoApplication.class, args);
  }
  @Bean
  public ServletRegistrationBean dispatcherRegistration() {
    return new ServletRegistrationBean(dispatcherServlet());
  }
  @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  public DispatcherServlet dispatcherServlet() {
    return new LoggableDispatcherServlet();
  }
}

增加一個簡單的 Controller 來測試一下

@RestController
@RequestMapping("/hello")
public class HelloController {

  @RequestMapping(value = "/word", method = RequestMethod.POST)
  public Object hello(@RequestBody Object object) {
    return object;
  }
}

使用 curl 發(fā)送一個 Post 請求:

$ curl --header "Content-Type: application/json" \
 --request POST \
 --data '{"username":"xyz","password":"xyz"}' \
 http://localhost:8080/hello/word
{"username":"xyz","password":"xyz"}

查看打印的日志:

{
  "uri":"/hello/word",
  "clientIp":"0:0:0:0:0:0:0:1",
  "requestHeaders":{
    "content-length":"35",
    "host":"localhost:8080",
    "content-type":"application/json",
    "user-agent":"curl/7.54.0",
    "accept":"*/*"
  },
  "method":"POST",
  "request":{
    "username":"xyz",
    "password":"xyz"
  },
  "status":200,
  "response":{
    "username":"xyz",
    "password":"xyz"
  },
  "responseHeaders":{
    "Content-Length":"35",
    "Date":"Sun, 17 Mar 2019 08:56:50 GMT",
    "Content-Type":"application/json;charset=UTF-8"
  }
}

當然打印出來是在一行中的,我進行了一下格式化。我們還可以在日志中增加請求的時間,耗費的時間以及異常信息等。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • maven依賴關(guān)系中的<scope>provided</scope>使用詳解

    maven依賴關(guān)系中的<scope>provided</scope>使用詳解

    這篇文章主要介紹了maven依賴關(guān)系中的<scope>provided</scope>使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • Eclipse 使用Maven構(gòu)建SpringMVC項目

    Eclipse 使用Maven構(gòu)建SpringMVC項目

    本文主要介紹在Eclipse下創(chuàng)建Maven項目構(gòu)建SpringMVC框架的過程,講解的比較詳細,需要的朋友可以參考下。
    2016-06-06
  • 一文講透為什么遍歷LinkedList要用增強型for循環(huán)

    一文講透為什么遍歷LinkedList要用增強型for循環(huán)

    這篇文章主要為大家介紹了為什么遍歷LinkedList要用增強型for循環(huán)的透徹詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Spring定時任務@scheduled多線程使用@Async注解示例

    Spring定時任務@scheduled多線程使用@Async注解示例

    這篇文章主要為大家介紹了Spring定時任務@scheduled多線程使用@Async注解示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Spring Boot整合logback一個簡單的日志集成架構(gòu)

    Spring Boot整合logback一個簡單的日志集成架構(gòu)

    今天小編就為大家分享一篇關(guān)于Spring Boot整合logback一個簡單的日志集成架構(gòu),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 詳解Spring注解--@Autowired、@Resource和@Service

    詳解Spring注解--@Autowired、@Resource和@Service

    本篇文章主要介紹最重要的三個Spring注解,也就是@Autowired、@Resource和@Service,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-05-05
  • java實現(xiàn)文件切片和合并的代碼示例

    java實現(xiàn)文件切片和合并的代碼示例

    這篇文章主要介紹了java實現(xiàn)文件切片和合并的代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • 深入IDEA Debug問題透析詳解

    深入IDEA Debug問題透析詳解

    這篇文章主要為大家介紹了深入IDEA Debug問題透析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • 如何查看java進程gc情況

    如何查看java進程gc情況

    這篇文章主要介紹了如何查看java進程gc情況,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-07-07
  • JAVA實現(xiàn)深拷貝的幾種方式代碼

    JAVA實現(xiàn)深拷貝的幾種方式代碼

    這篇文章主要給大家介紹了關(guān)于JAVA實現(xiàn)深拷貝的幾種方式,在Java中深拷貝和淺拷貝是用來復制對象的兩種不同方式,深拷貝會對所有數(shù)據(jù)類型進行拷貝,包括對象所包含的內(nèi)部對象,需要的朋友可以參考下
    2023-09-09

最新評論

琼海市| 盐城市| 麻江县| 平凉市| 宁蒗| 桦南县| 通海县| 卓尼县| 龙里县| 宁武县| 无极县| 潢川县| 延吉市| 神木县| 武宁县| 肃宁县| 霍邱县| 乌恰县| 巴彦淖尔市| 修文县| 黑山县| 长沙市| 新密市| 汉源县| 秀山| 龙口市| 永州市| 健康| 郎溪县| 金溪县| 金华市| 乌兰察布市| 巴中市| 永州市| 台北市| 尼玛县| 昭平县| 临朐县| 永春县| 乌兰浩特市| 大埔区|