ตามที่ระบุไว้ในคำตอบอื่น ๆ ร่างกายตอบสนองต้องการการดูแลเป็นพิเศษเพื่อให้สามารถอ่านซ้ำ ๆ (โดยค่าเริ่มต้นเนื้อหาที่ได้รับการบริโภคในการอ่านครั้งแรก)
แทนที่จะใช้การBufferingClientHttpRequestFactory
ตั้งค่าเมื่อร้องขอ Interceptor เองสามารถห่อคำตอบและตรวจสอบให้แน่ใจว่าเนื้อหานั้นถูกเก็บไว้และสามารถอ่านซ้ำได้ (โดยคนตัดไม้และผู้บริโภคที่ตอบรับ):
เครื่องดักฟังของฉันซึ่ง
- บัฟเฟอร์ร่างกายการตอบสนองโดยใช้เสื้อคลุม
- บันทึกในวิธีกะทัดรัดมากขึ้น
- บันทึกตัวระบุรหัสสถานะด้วย (เช่นสร้างขึ้น 201 รายการ)
- รวมถึงหมายเลขลำดับการร้องขอที่อนุญาตให้แยกความแตกต่างรายการบันทึกพร้อมกันได้อย่างง่ายดายจากหลายเธรด
รหัส:
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
private final Logger log = LoggerFactory.getLogger(getClass());
private AtomicInteger requestNumberSequence = new AtomicInteger(0);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
int requestNumber = requestNumberSequence.incrementAndGet();
logRequest(requestNumber, request, body);
ClientHttpResponse response = execution.execute(request, body);
response = new BufferedClientHttpResponse(response);
logResponse(requestNumber, response);
return response;
}
private void logRequest(int requestNumber, HttpRequest request, byte[] body) {
if (log.isDebugEnabled()) {
String prefix = requestNumber + " > ";
log.debug("{} Request: {} {}", prefix, request.getMethod(), request.getURI());
log.debug("{} Headers: {}", prefix, request.getHeaders());
if (body.length > 0) {
log.debug("{} Body: \n{}", prefix, new String(body, StandardCharsets.UTF_8));
}
}
}
private void logResponse(int requestNumber, ClientHttpResponse response) throws IOException {
if (log.isDebugEnabled()) {
String prefix = requestNumber + " < ";
log.debug("{} Response: {} {} {}", prefix, response.getStatusCode(), response.getStatusCode().name(), response.getStatusText());
log.debug("{} Headers: {}", prefix, response.getHeaders());
String body = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
if (body.length() > 0) {
log.debug("{} Body: \n{}", prefix, body);
}
}
}
/**
* Wrapper around ClientHttpResponse, buffers the body so it can be read repeatedly (for logging & consuming the result).
*/
private static class BufferedClientHttpResponse implements ClientHttpResponse {
private final ClientHttpResponse response;
private byte[] body;
public BufferedClientHttpResponse(ClientHttpResponse response) {
this.response = response;
}
@Override
public HttpStatus getStatusCode() throws IOException {
return response.getStatusCode();
}
@Override
public int getRawStatusCode() throws IOException {
return response.getRawStatusCode();
}
@Override
public String getStatusText() throws IOException {
return response.getStatusText();
}
@Override
public void close() {
response.close();
}
@Override
public InputStream getBody() throws IOException {
if (body == null) {
body = StreamUtils.copyToByteArray(response.getBody());
}
return new ByteArrayInputStream(body);
}
@Override
public HttpHeaders getHeaders() {
return response.getHeaders();
}
}
}
การกำหนดค่า:
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.additionalInterceptors(Collections.singletonList(new LoggingInterceptor()));
}
ตัวอย่างบันทึกผลลัพธ์:
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 > Request: POST http://localhost:53969/payment/v4/private/payment-lists/10022/templates
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 > Headers: {Accept=[application/json, application/json], Content-Type=[application/json;charset=UTF-8], Content-Length=[986]}
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 > Body:
{"idKey":null, ...}
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 < Response: 200 OK
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 < Headers: {Content-Type=[application/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Mon, 08 Oct 2018 08:58:53 GMT]}
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 < Body:
{ "idKey" : "10022", ... }