簡體   English   中英

Spring Controllers:添加一個響應頭參數,稱為Elapsed-Time

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM