客户过滤器
使用 Filters 的一个很好的理由是用于记录。使用此技术可以轻松记录和调整 REST 调用。
public class RestLogger implements ClientRequestFilter, ClientResponseFilter {
private static final Logger log = LoggerFactory.getLogger(RestLogger.class);
// Used for timing this call.
private static final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
private boolean logRequestEntity;
private boolean logResponseEntity;
private static Gson GSON = new GsonBuilder().create();
public RestLogger(boolean logRequestEntity, boolean logResponseEntity) {
this.logRequestEntity = logRequestEntity;
this.logResponseEntity = logResponseEntity;
}
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
startTime.set(System.currentTimeMillis());
}
@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("HTTP:").append(responseContext.getStatus());
sb.append(" - Time:[").append(System.currentTimeMillis() - startTime.get().longValue()).append("ms]");
sb.append(" - Path:").append(requestContext.getUri());
sb.append(" - Content-type:").append(requestContext.getStringHeaders().getFirst(HttpHeaders.CONTENT_TYPE.toString()));
sb.append(" - Accept:").append(requestContext.getStringHeaders().getFirst(HttpHeaders.ACCEPT.toString()));
if (logRequestEntity) {
sb.append(" - RequestBody:").append(requestContext.getEntity() != null ? GSON.toJson(requestContext.getEntity()) : "none");
}
if (logResponseEntity) {
sb.append(" - ResponseBody:").append(this.logResponse(responseContext));
}
log.info(sb.toString());
}
private String logResponse(ClientResponseContext response) {
StringBuilder b = new StringBuilder();
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = response.getEntityStream();
try {
ReaderWriter.writeTo(in, out);
byte[] requestEntity = out.toByteArray();
b.append(new String(requestEntity));
response.setEntityStream(new ByteArrayInputStream(requestEntity));
}
catch (IOException ex) {
throw new ClientHandlerException(ex);
}
return b.toString();
}
}
上面你可以看到在发送响应并设置了 ThreadLocal Long 之前拦截了请求。当返回响应时,我们可以记录请求和响应以及各种相关数据。当然这仅适用于 Gson 响应等,但可以轻松修改。这是这样设置的:
List<Object> providers = new ArrayList<Object>();
providers.add(new GsonMessageBodyProvider());
providers.add(new RestLogger(true, true)); <------right here!
WebClient webClient = WebClient.create(PORTAL_URL, providers);
提供的日志应如下所示:
7278 [main] INFO blah.RestLogger - HTTP:200 - Time:[1391ms] - User:unknown - Path:https://blah.com/tmet/moduleDescriptions/desc?languageCode=en&moduleId=142 - Content-type:null - Accept:application/json - RequestBody:none - ResponseBody:{"languageCode":"EN","moduleId":142,"moduleDescription":"ECAP"}