記事ディレクトリ
序文
プロジェクト開発中、HTTP プロトコルを使用してサードパーティのインターフェイスを要求する必要があることがよくありますが、サードパーティへのすべての要求については、問題追跡のために要求ログを出力することを強くお勧めします。最も一般的なアプローチは、HTTP リクエスト ツール クラスをカプセル化し、その中でログ出力をカスタマイズすることですが、このアプローチは非常に低レベルであり、この記事では Spring Boot で HTTP リクエスト ログをエレガントに出力する方法を共有します。
1. 実際の Spring-rest-template-logger
まず、github にある一般的なログ出力コンポーネント spring-rest-template-logger の使用方法を示します。
Github アドレス: Spring RestTemplate Logger
1. 依存関係を導入する
<dependency>
<groupId>org.hobsoft.spring</groupId>
<artifactId>spring-rest-template-logger</artifactId>
<version>2.0.0</version>
</dependency>
2、配置RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder()
.customizers(new LoggingCustomizer())
.build();
return restTemplate;
}
}
3. RestTemplate リクエストのログ レベルを設定する
logging.level.org.hobsoft.spring.resttemplatelogger.LoggingCustomizer = DEBUG
4.単体テスト
@SpringBootTest
@Slf4j
class LimitApplicationTests {
@Resource
RestTemplate restTemplate;
@Test
void testHttpLog() throws Exception{
String requestUrl = "https://api.uomg.com/api/icp";
//构建json请求参数
JSONObject params = new JSONObject();
params.put("domain", "www.baidu.com");
//请求头声明请求格式为json
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//创建请求实体
HttpEntity<String> entity = new HttpEntity<>(params.toString(), headers);
//执行post请求,并响应返回字符串
String resText = restTemplate.postForObject(requestUrl, entity, String.class);
System.out.println(resText);
}
}
5. ログの印刷
2023-06-25 10:43:44.780 DEBUG [Sleuth,b6ac76a169b1af33,b6ac76a169b1af33] 63501 --- [ main] o.h.s.r.LoggingCustomizer : Request: POST https://api.uomg.com/api/icp {
"domain":"www.baidu.com"}
2023-06-25 10:43:45.849 DEBUG [Sleuth,b6ac76a169b1af33,b6ac76a169b1af33] 63501 --- [ main] o.h.s.r.LoggingCustomizer : Response: 200 {
"code":200901,"msg":"查询域名不能为空"}
{
"code":200901,"msg":"查询域名不能为空"}
ご覧のとおり、RestTemplate で LoggingCustomizer を設定するだけで、http リクエストのログのユニバーサル出力を実現し、リクエストの入力パラメーターと応答結果がそれぞれ Request と Response に出力されました。
6. ログの印刷形式をカスタマイズする
LogFormatter インターフェイスを継承することで、カスタム ログ出力形式を実装できます。
RestTemplate restTemplate = new RestTemplateBuilder()
.customizers(new LoggingCustomizer(LogFactory.getLog(LoggingCustomizer.class), new MyLogFormatter()))
.build();
デフォルトのログ印刷形式クラス DefaultLogFormatter:
public class DefaultLogFormatter implements LogFormatter {
private static final Charset DEFAULT_CHARSET;
public DefaultLogFormatter() {
}
//格式化请求
public String formatRequest(HttpRequest request, byte[] body) {
String formattedBody = this.formatBody(body, this.getCharset(request));
return String.format("Request: %s %s %s", request.getMethod(), request.getURI(), formattedBody);
}
//格式化响应
public String formatResponse(ClientHttpResponse response) throws IOException {
String formattedBody = this.formatBody(StreamUtils.copyToByteArray(response.getBody()), this.getCharset(response));
return String.format("Response: %s %s", response.getStatusCode().value(), formattedBody);
}
……
}
DefaultLogFormatter の実装を参照して、ログ印刷フォーマット クラス MyLogFormatter をカスタマイズできます。
2. 原理分析
まず、LoggingCustomizer クラスを分析します。ソース コードを見ると、LoggingCustomizer が RestTemplateCustomizer から継承していることがわかりました。RestTemplateCustomizer は、RestTemplate のカスタマイザーを表します。RestTemplateCustomizer は、カスタマイズされた RestTemplate のプロパティを拡張するために使用される、customize という 1 つのメソッドのみを備えた関数インターフェイスです。
@FunctionalInterface
public interface RestTemplateCustomizer {
void customize(RestTemplate restTemplate);
}
LoggingCustomizer のコア メソッドのカスタマイズ:
public class LoggingCustomizer implements RestTemplateCustomizer{
public void customize(RestTemplate restTemplate) {
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(restTemplate.getRequestFactory()));
//向restTemplate中注入了日志拦截器
restTemplate.getInterceptors().add(new LoggingInterceptor(this.log, this.formatter));
}
}
ログインターセプターのコアメソッド:
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
private final Log log;
private final LogFormatter formatter;
public LoggingInterceptor(Log log, LogFormatter formatter) {
this.log = log;
this.formatter = formatter;
}
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
if (this.log.isDebugEnabled()) {
//打印http请求的入参
this.log.debug(this.formatter.formatRequest(request, body));
}
ClientHttpResponse response = execution.execute(request, body);
if (this.log.isDebugEnabled()) {
//打印http请求的响应结果
this.log.debug(this.formatter.formatResponse(response));
}
return response;
}
}
原則の概要:
カスタム ログ インターセプター LoggingInterceptor をrestTemplate オブジェクトに追加することで、カスタム書式設定クラス DefaultLogFormatter を使用して http 要求ログを出力します。
3. 最適化と改善
spring-rest-template-logger の実装から学び、Spring Boot Start 自動構成原則を使用して自動構成クラス RestTemplateAutoConfiguration を宣言し、RestTemplate を自動的に構成できます。
これはアイデアを提供するためのものであり、関連するコンポーネントの原理を理解した後、一般的なログ出力コンポーネントを簡単にカスタマイズできます。
@Configuration
public class RestTemplateAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder()
.customizers(new LoggingCustomizer())
.build();
return restTemplate;
}
}
要約する
ここでのエレガントな印刷は、http リクエストのログ印刷の形式ではなく、RestTemplate にインターセプターを挿入することによる、高い汎用性、低いコード侵入、カスタマイズ性を備えたログ印刷方法です。
在Spring Boot中http请求都推荐采用RestTemplate模板类
、HttpUtil などの http リクエスト用の静的ツール クラスをカスタマイズする必要はありません。- 構成クラスで @Bean を使用して、RestTemplate クラスを統一されたユニバーサル シングルトン オブジェクトに構成し、使用するたびに再宣言するのではなく、それを Spring コンテナーに注入することをお勧めします。
- http リクエスト ログの一般的な出力を実現するには、インターセプタを使用することをお勧めします。