[英]How to save requests and responses to database in spring boot
我想寫一個方面或類似的東西,每當請求到達 controller 時,它都會將請求和響應保存到數據庫。
第一個問題是我應該在我的實體中使用什么類型來請求和響應(字符串、blob 等)
第二個問題,如何獲取請求、響應及其 controller 名稱來創建實體以保存到數據庫?
最后,是否可以計算 controller 的響應時間(在控制器中花費的時間)?
第一個問題是我應該在我的實體中使用什么類型來請求和響應(字符串、blob 等)
它主要取決於數據庫供應商和請求/響應長度。
某些供應商可能會限制字符串,因此需要 blob。 另一方面,在 blob 上的匹配速度較慢。
另一種選擇是使用 nosql 格式,例如 JSON。
第二個問題,如何獲取請求、響應及其 controller 名稱來創建實體以保存到數據庫?
真的有幾種方法。
您可以利用內置 Spring 引導http 跟蹤功能,但它有一個限制:發布/接收的請求/響應不可用。
5.8. HTTP 跟蹤
HTTP 可以通過在應用程序配置中提供 HttpTraceRepository 類型的 bean 來啟用跟蹤。 為方便起見,Spring Boot 默認提供一個 InMemoryHttpTraceRepository 存儲最近 100 次請求-響應交換的跟蹤。 與其他跟蹤解決方案相比,InMemoryHttpTraceRepository 受到限制,我們建議僅將其用於開發環境。 對於生產環境,建議使用生產就緒跟蹤或可觀察性解決方案,例如 Zipkin 或 Spring Cloud Sleuth。 或者,創建您自己的 HttpTraceRepository 以滿足您的需求。
httptrace 端點可用於獲取有關存儲在 HttpTraceRepository 中的請求-響應交換的信息。
5.8.1. 定制 HTTP 跟蹤
要自定義每個跟蹤中包含的項目,請使用 management.trace.http.include 配置屬性。 對於高級自定義,請考慮注冊您自己的 HttpExchangeTracer 實現。
替代方案正在為請求/響應實施過濾器並登錄。
例如:
@Component
public class RequestResponseStoringFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
long start = System.currentTimeMillis();
try {
chain.doFilter(req, resp);
} finally {
// Measure elapsed time
long elapsed = System.currentTimeMillis() - start;
// store request data and store response data in a DB
.....
}
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig arg0) throws ServletException {}
}
最后,是否可以計算 controller 的響應時間(在控制器中花費的時間)?
實現過濾器的方式可以做到這一點,如上所示。
httptrace 端點方式提供了timeTaken
字段。
FIY,這是HttpTrace實例的內容:
HttpTrace.Principal getPrincipal() HttpTrace.Request getRequest() HttpTrace.Response getResponse() HttpTrace.Session getSession() Instant getTimestamp() Long getTimeTaken()
這有點擴展了其他答案,但我認為它需要一個單獨的答案。
如果您引入了 spring-boot-starter-web,那么您已經在引入 spring-aop。 如果你要去 go 沿着切點路線走,我強烈建議只使用spring-boot-starter-actuator
附帶的 Micrometer @Timed
注釋。 我已經多次編寫了自己的度量切入點,但是如果您只是在計時以及成功和失敗的計數之后, @Timed
效果很好。
我還強烈建議研究使用時間序列數據庫(例如influx )來存儲響應時間和其他性能指標等內容。 將原始有效負載和其他可能的審計問題保存在單獨的數據庫中。 通過 influx 並在其上運行Grafana或Chronograf ,您可以做一些非常強大的事情。 毫無疑問,我目前的公司所做的最好的事情之一就是多年來采用 Influx/Chronograf。
關於請求/響應捕獲,我的工作流程中有一個奇怪的邊緣情況,曾經 http 跟蹤無法滿足一些硬性要求。 您可以使用ContentCachingRequestWrapper
自己直接在鏈過濾器中捕獲內容然后您可以通過以下方式訪問它們:
@Component
class MyPayloadCapturingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request)
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response)
filterChain.doFilter(requestWrapper, responseWrapper)
def requestBody = new String(requestWrapper.contentAsByteArray)
def responseBody = new String(responseWrapper.contentAsByteArray)
//..do something with them
}
}
注意OncePerRequestFilter
,我發現我的過濾器多次觸發同一個請求。 這可以防止這種情況。
添加此依賴項:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后,為控制器的方法執行創建一個Around
方面:
@Around("within(path.to.your.controller.*)")
public Object pointcutWithin(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info(" ###### pointcutWithin() before");
long start = System.nanoTime();
Object result = joinPoint.proceed();
logger.info(" ###### pointcutWithin() after");
long end = System.nanoTime();
long timeElapsedInMillis = (end - start) / 1000000;
logger.info(" ###### elapsed time in millis: "+timeElapsedInMillis);
return result;
}
至於堅持:首先,像這樣獲取 req 和 resp :
MyRequest req = (MyRequest) joinPoint.getArgs()[0];
MyResponse resp = (MyResponse) result;
那么你真正想要堅持什么取決於你。 對於具有簡單字段的類,我將 go 與varchar
一起使用,只需記住覆蓋他們的toString
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.