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