using System.Net.Http.Headers; using Microsoft.Extensions.Logging; namespace Infrastructure.StockData; /// /// 한국수출입은행(koreaexim.go.kr) OpenAPI 호출 공통 — 인증은 URL query param authkey (헤더 아님, OpenDART 와 동일 방식). /// 호출부가 authkey + searchdate + data 를 붙인 완성 URL 을 넘기며, 여기선 Accept json + 간단 3회 재시도(2s/4s 백오프)만 담당. /// internal static class KoreaEximHttp { public const string ClientName = "KoreaExim"; private const int MaxAttempts = 3; public static async Task GetStringWithRetryAsync(HttpClient client, string url, ILogger logger, CancellationToken ct) { for (var attempt = 1; ; attempt++) { try { using var request = new HttpRequestMessage(HttpMethod.Get, url); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // 일부 공공 게이트웨이는 UA 없는 요청을 봇으로 차단(OpenDART 사례) — 방어적으로 UA 부여 request.Headers.UserAgent.ParseAdd("antooza/1.0 (+https://antooza.com)"); using var response = await client.SendAsync(request, ct); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(ct); } catch (Exception ex) when (ex is not OperationCanceledException && attempt < MaxAttempts) { logger.LogWarning(ex, "[KoreaExim] HTTP 실패 — 재시도 {Attempt}/{Max}", attempt, MaxAttempts); await Task.Delay(TimeSpan.FromSeconds(2 * attempt), ct); } } } }