[英]Spring Controllers: Adding a response header parameter called Elapsed-Time
我想在每個API REST請求上添加一個經過時間響應標頭參數,即使那些以錯誤結束的參數也是如此。
例如:
===>
GET /api/customer/123 HTTP/1.1
Accept: application/vnd.company.app.customer-v1+json
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.app.customer-v1+json
Elapsed-Time: 12
{ id: 123, name: Jordi, age: 28 }
作為經過時間參數,計算為@RequestMapping方法完成的瞬間與@RequestMapping方法啟動的瞬間之間的毫秒差。
我一直在研究Spring4 HandlerInterceptorAdapter。 preHandle和postHandle方法似乎非常適合這種情況(盡管執行鏈中每個攔截器的時間開銷)。 但是,不幸的是,在postHandle方法中更改響應頭沒有任何作用,因為響應已經生成。
Spring文檔指出:
請注意,HandlerInterceptor的postHandle方法並不總是非常適合與@ResponseBody和ResponseEntity方法一起使用。 在這種情況下,HttpMessageConverter會在調用postHandle之前寫入並提交響應,這使得無法更改響應,例如添加標頭。 相反,應用程序可以實現ResponseBodyAdvice並將其聲明為@ControllerAdvice bean或直接在RequestMappingHandlerAdapter上對其進行配置。
您是否知道有任何可行的解決方案來處理這種情況?
我不認為這種情況是在復制Spring-處理后(在postHandle中)為每個請求修改標頭,因為我需要捕獲一個值為開始時間的變量(當請求到達應用程序時,並且@RequestMapping方法開始之前) ),然后在@RequestMapping方法完成后使用此變量來計算經過的時間。
您需要使用Handle Interceptor,但不要實現postHandle方法,僅實現preHandle以便將startTime保存為請求中的參數。
public class ExecuterTimeInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
}
當控制器完成並返回響應時,控制器建議(實現ResponseBodyAdvice的類)將獲取服務器請求的http servlet請求部分,恢復startTime並獲取經過的時間,如下所示:
@ControllerAdvice
public class GeneralControllerAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
ServletServerHttpRequest servletServerRequest = (ServletServerHttpRequest) request;
long startTime = (long) servletServerRequest.getServletRequest().getAttribute("startTime");
long timeElapsed = System.currentTimeMillis() - startTime;
response.getHeaders().add("Elapsed-Time", String.valueOf(timeElapsed));
return body;
}
}
最后,將攔截器添加到主應用程序(每個資源所需的/ **路徑)
@SpringBootApplication
@ComponentScan(basePackages = "com.your.package")
@Configuration
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ExecuterTimeInterceptor()).addPathPatterns("/**");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.