環(huán)境:SpringBoot2.7.18
項目中監(jiān)控記錄接口請求的相關(guān)信息是一個至關(guān)重要的環(huán)節(jié),它對于提升系統(tǒng)穩(wěn)定性、優(yōu)化性能、快速定位問題以及保障數(shù)據(jù)安全等方面都起著至關(guān)重要的作用。大致可概況如下幾方面:
問題追蹤與定位:當(dāng)系統(tǒng)出現(xiàn)錯誤或異常時,通過查看接口調(diào)用的請求信息,可以快速定位問題發(fā)生的源頭。比如,通過查看請求參數(shù)、響應(yīng)狀態(tài)碼、執(zhí)行時間等
性能優(yōu)化:監(jiān)控接口請求的處理時間、響應(yīng)時間性能指標(biāo),可以幫助開發(fā)團隊了解系統(tǒng)的瓶頸所在,從而進(jìn)行相應(yīng)的優(yōu)化。
用戶行為分析:通過記錄用戶的請求信息,包括請求頻率、請求時間、請求參數(shù)等,可以對用戶行為進(jìn)行分析,了解用戶的使用習(xí)慣和需求,從而優(yōu)化產(chǎn)品功能和用戶體驗。
安全審計:記錄接口請求信息也是安全審計的一部分。通過監(jiān)控和分析請求數(shù)據(jù),可以發(fā)現(xiàn)潛在的安全威脅,如惡意請求、SQL注入、跨站腳本攻擊等
在SpringBoot中我們可通過Actuator來實現(xiàn)對Http接口進(jìn)行監(jiān)控記錄,接下來我們通過實操來演示如何通過Actuator來監(jiān)控記錄我們的即可。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency>
要使用Actuator的http接口監(jiān)控功能,你還需要注冊一個HttpTraceRepository類型的Bean,Actuator默認(rèn)提供的是基于內(nèi)存的實現(xiàn)
@Configurationpublic class HttpActuatorConfig { @Bean InMemoryHttpTraceRepository inMemoryHttpTraceRepository() { return new InMemoryHttpTraceRepository() ; }}
默認(rèn)情況下,Actuator只開啟了health接口(健康檢查),我們還需要手動開啟httptrace接口。
management: endpoints: web: exposure: include: httptrace
以上配置后,可以通過/actuator接口查看是否開啟了httptrace接口
成功開啟
@RestController@RequestMapping("/users")public class UserController { private static List<User> DATAS = new ArrayList<>() ; static { DATAS.add(new User(1L, "張三", 22)) ; DATAS.add(new User(2L, "李四", 32)) ; DATAS.add(new User(3L, "王五", 33)) ; DATAS.add(new User(4L, "趙六", 26)) ; DATAS.add(new User(5L, "田七", 29)) ; DATAS.add(new User(6L, "嘿哈", 44)) ; } @PostMapping("") public ResponseEntity<Void> save(@RequestBody User user) { DATAS.add(user) ; return ResponseEntity.created(URI.create(String.format("/users/%s", user.getId()))).build() ; } @DeleteMapping("/{id}") public ResponseEntity<Void> delete(@PathVariable("id") Long id) { DATAS.removeIf(user -> user.getId() == id) ; return ResponseEntity.noContent().build() ; } @PutMapping("") public ResponseEntity<Void> update(@RequestBody User user) { DATAS.stream() .filter(u -> u.getId() == user.getId()) .findFirst() .ifPresent(u -> { u.setAge(user.getAge()) ; u.setName(u.getName()) ; }); return ResponseEntity.noContent().build() ; } @GetMapping("") public ResponseEntity<List<User>> list() { return ResponseEntity.ok(DATAS) ; } @GetMapping("/{id}") public ResponseEntity<User> get(@PathVariable("id") Long id) { return ResponseEntity.ok(DATAS.stream() .filter(u -> u.getId() == id) .findFirst().orElse(null) ) ; } // 測試異常情況 @GetMapping("/exception") public ResponseEntity<Void> exce() { System.out.println(1 / 0) ; return ResponseEntity.noContent().build() ; }}
為了簡單,上面操作都是基于內(nèi)存數(shù)據(jù)進(jìn)行。包括了CRUD及異常情況。
訪問上面定義的任意接口之后通過/actuator/httptrace接口查看訪問情況
圖片
每個接口會詳細(xì)的記錄請求的URL,header,響應(yīng)狀態(tài)碼及header信息。上圖中的timeTaken屬性記錄的是該接口請求的耗時情況(單位:毫秒)。
通過以上的示例演示,使用Actuator監(jiān)控接口還是非常簡單的,你只需要做簡單的配置即可,接下來繼續(xù)介紹更多的配置及使用。
要自定義記錄的信息,可以通過如下配置
management: trace: http: include: - time-taken - response-headers
注:在SpringBoot3以上的版本這里的配置發(fā)生了變化使用的是如下配置:
management: httpexchanges: recording: include: - time-taken
通過上面的配置后,再次訪問接口
圖片
此時,將不再包含請求headers。還支持如下的配置:
圖片
在項目中你可以通過 HttpTraceRepository 獲取所有請求中的請求-響應(yīng)交換信息。如下示例,獲取所有錯誤的請求(狀態(tài)碼為500)。
private final HttpTraceRepository httpTraceRepository ;public HttpController(HttpTraceRepository httpTraceRepository) { this.httpTraceRepository = httpTraceRepository ;}@GetMapping("/{status}")public Object info(@PathVariable("status") Integer status) { return httpTraceRepository.findAll() .stream() .filter(trace -> trace.getResponse().getStatus() == status) .collect(Collectors.toList()) ;}
通過上面的接口,我們可以過濾指定狀態(tài)碼的請求信息。
InMemoryHttpExchangeRepository,默認(rèn)情況下,它會存儲最近 100 次請求-響應(yīng)信息,并且是內(nèi)存級的。所以如果你需要在生產(chǎn)環(huán)境下使用還是建議你自定義HttpTraceRepository實現(xiàn),將信息存入到Redis或者是ES中。如下存入Redis示例
@Componentpublic class PackHttpTraceRepository implements HttpTraceRepository { private static final String HTTP_TRACE_KEY = "http_request_response" ; private final StringRedisTemplate stringRedisTemplate ; public PackHttpTraceRepository(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate = stringRedisTemplate ; } @Override public List<HttpTrace> findAll() { return this.stringRedisTemplate.opsForList().range(HTTP_TRACE_KEY, 0, -1).stream().map(json -> { try { return objectMapper.readValue(json, HttpTrace.class); } }).collect(Collectors.toList()) ; } @Override public void add(HttpTrace trace) { String json = null ; try { json = objectMapper.writeValueAsString(trace) ; } this.stringRedisTemplate.opsForList().leftPush(HTTP_TRACE_KEY, json) ; }}
這樣我們就可以持久化存儲數(shù)據(jù)了,你還可以根據(jù)當(dāng)前日期來進(jìn)行存儲。
本文鏈接:http://www.tebozhan.com/showinfo-26-98864-0.htmlSpringBoot自帶Controller接口監(jiān)控,趕緊用起來
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com