각 ASPNET 핵심 웹 API 프로젝트 요구 사항 - 섹션 5 - Polly
34459 단어 aspnetcoredotnetarchitecturewebapi
HttpClient
에 복구 능력과 순간적인 고장 처리를 추가하는 방법을 보여 드리겠습니다.ASP를 만들면NET 핵심 웹 API 프로젝트 중
WeatherForecastController
이 일기예보 목록으로 돌아왔다.나는 정적 데이터를 되돌려 주는 것이 아니라 외부 날씨 API를 사용하여 실제 일기예보를 얻을 것이다.1단계 - 외부 API
2단계 - 유형 HTTP 클라이언트
프로젝트에서 HttpClient 클래스를 사용하는 방법은 다음과 같습니다.
날씨 외부 API에 대한 유형 클라이언트를 만듭니다.
HttpClients
폴더 Infrastructure
WeatherHttpClient.cs
을 HttpClients
폴더 appsettings.json
파일을 열고 다음 키/값을 추가합니다."WeatherSettings": {
"ApiKey": "YOURKEY"
"BaseUrl": "https://api.weatherapi.com",
"NoDaysForecast": 5
}
WeatherHttpClient.cs
파일을 열고 API 설정의 클래스를 만듭니다.public class WeatherSettings
{
public string ApiKey { get; set; }
public string BaseUrl { get; set; }
public int NoDaysForecast { get; set; }
}
Startup.cs
클래스와 내부 ConfigureServices
방법 귀속 및 날씨 설정 등록:var weatherSettings = new WeatherSettings();
Configuration.GetSection("WeatherSettings").Bind(weatherSettings);
services.AddSingleton(weatherSettings);
WeatherHttpClient.cs
파일 생성 인터페이스:public interface IWeatherHttpClient
{
Task<IEnumerable<WeatherForecast>> GetForecastAsync(string cityName);
}
public class WeatherHttpClient : IWeatherHttpClient
{
private readonly HttpClient _client;
private readonly WeatherSettings _settings;
public WeatherHttpClient(HttpClient client, WeatherSettings settings)
{
_client = client;
_settings = settings;
_client.BaseAddress = new Uri(_settings.BaseUrl);
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<IEnumerable<WeatherForecast>> GetForecastAsync(string cityName)
{
var url = $"v1/forecast.json?key={_settings.ApiKey}&q={cityName}&days={_settings.NoDaysForecast}";
var response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
...
}
}
API의 응답은 매우 상세합니다. 저는 반서열화된 JSON의 대상을 만들지 않고 익명의 대상을 사용하여 제가 필요로 하는 데이터를 추출합니다.public async Task<IEnumerable<WeatherForecast>> GetForecastsAsync(string cityName)
{
...
var days = JsonSerializerExtensions.DeserializeAnonymousType(content, new
{
forecast = new
{
forecastday = new[]
{
new
{
date = DateTime.Now,
day = new { avgtemp_c = 0.0, condition = new { text = "" } }
}
}
}
}).forecast.forecastday;
return days.Select(d => new WeatherForecast
{
Date = d.date,
Summary = d.day.condition.text,
TemperatureC = (int)d.day.avgtemp_c
});
// Other way to deserialize json without creating anonymous object
// To get more information see https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement?view=net-5.0
//dynamic result = JsonSerializer.Deserialize<ExpandoObject>(content);
//var days = result.forecast.GetProperty("forecastday").EnumerateArray();
//foreach (var day in days)
//{
// var date = day.GetProperty("date").GetDateTime();
// var temp = day.GetProperty("day").GetProperty("avgtemp_c").GetDouble();
// var condition = day.GetProperty("day").GetProperty("condition").GetProperty("text").GetString();
//}
}
Startup.cs
열기 및 날씨 HTTP 클라이언트 서비스 등록:services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>();
WeatherForecastController
으로 열고 IWeatherHttpClient
을 주입합니다.namespace CoolWebApi.Apis.V1.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly IWeatherHttpClient _weatherClient;
public WeatherForecastController(IWeatherHttpClient weatherClient)
{
_weatherClient = weatherClient;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IEnumerable<WeatherForecast>> Get(string city = "London")
{
return await _weatherClient.GetForecastsAsync(city);
}
날씨 API를 호출할 때 오류를 모의할 때가 되었다.따라서 외부 API를 제어할 수 없으며 Fiddler Everywhere을 사용하여 HTTP 요청과 응답을 캡처하고 처리합니다.3. 바이올리니스트 사용하기
Download, 바이올리니스트 설치
api/v1/weatherforecast
API 호출Fiddler가 포획한 HTTP 데이터를 볼 수 있지만, 암호화되어 있기 때문에 HTTPS에서 호출된 요청/응답을 볼 수 없습니다. 그러나 Fiddler는 HTTPS 데이터를 복호화하는 메커니즘을 가지고 있습니다.
View->Preferences
을 클릭하거나 ctrl+,
을 클릭하여 Settings
을 엽니다.HTTPS
탭을 클릭한 다음 Trust root certificate
(Remove root certificate
을 클릭하여 언제든지 인증서를 삭제할 수 있음) 포획된 데이터를 필터해서 다른 요청을 제거합시다.
URL
열의 localhost:5001
및 api.weatherapi.com
URL을 입력하고 And
을 Or
으로 변경합니다.이제
api.weatherapi.com
API의 응답을 변경할 때가 되었습니다.Live Traffic
행을 마우스 오른쪽 버튼으로 클릭하고 메뉴에서 api.weatherapi.com
(1)을 클릭합니다.Add new rule
탭에서 스위치 버튼을 클릭하여 활성화(2)하고 편집 아이콘(3)Auto Responder
창의 Rule Editor
입력 및 다음 텍스트를 지우고 저장 버튼을 클릭합니다.HTTP/1.1 503
Service is unavailable
규칙을 테스트해 봅시다.
Raw
행을 다시 마우스 오른쪽 버튼으로 클릭하고 메뉴에서 api.weatherapi.com
을 클릭하면 API 가 Reply->Reissue requests
상태 코드가 아닌 503
으로 돌아갑니다.API를 거들먹거리며 호출해 보면
200
을 받을 수 있다4단계 - Polly 설치
Internal Server Error
nuget 패키지 Microsoft.Extensions.Http.Polly
클래스를 열고 Startup.cs
방법에서 ConfigureServices
등록을 다음과 같이 수정합니다.services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(4)));
이제 WeatherHttpClient
을 3회 재시도하고 재시도 간격을 4초간 기다립니다.WeatherHttpClient
에서 사용할 API 호출 횟수를 다시 한 번 살펴보겠습니다.API가 호출되는 동안 Fiddler Auto Responder를 닫으려면 다시 시도해 보겠습니다.
이번에는 자동 응답기를 끄면 API가 상태 코드 200과 예측 결과를 반환합니다.
마우스를
WeatherHttpClient
메서드에 놓으면 AddTransientHttpErrorPolicy
에서 다음 오류 범주를 처리하는 것을 알 수 있습니다.예를 들어, HTTP 오류 코드 400은 재시도되지 않습니다.
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy =>
policy.WaitAndRetryAsync(2, _ => TimeSpan.FromSeconds(2)))
.AddTransientHttpErrorPolicy(policy =>
policy.CircuitBreakerAsync(2, TimeSpan.FromSeconds(5)));
우리는 재시도를 2초씩 하고 4번의 재시도에 실패한 후 5초간 멈추기를 희망한다.추가 예:
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(6),
TimeSpan.FromSeconds(10)
}));
이 정책은 1차 재시도 전에 2초, 2차 재시도 전에 6초, 3차 재시도 전에 10초 지연됩니다.var policy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(response => (int)response.StatusCode == 417) // RetryAfter
.WaitAndRetryAsync(...);
앞에서 언급한 바와 같이 기본적으로 PolicyBuilder
은 HandleTransientHttpError
, HttpRequestException
과 5XX
오류를 처리한다.상술한 정책도 429 상태 코드를 처리할 수 있다.services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy => policy.RetryAsync(3, onRetry: (exception, retryCount) =>
{
//Add logic to be executed before each retry
}));
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy => policy.RetryForeverAsync());
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy => policy.AdvancedCircuitBreakerAsync(
failureThreshold: 0.5,
samplingDuration: TimeSpan.FromSeconds(10),
minimumThroughput: 8,
durationOfBreak: TimeSpan.FromSeconds(30)
));
수신 요청의 50% 이상이 실패하거나 10초 동안 최소 8번의 장애가 발생하면 30초 동안 회로를 끊습니다.회로는 30초 후에 복원/폐합된다.services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddTransientHttpErrorPolicy(policy =>
policy.FallbackAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout)));
리트랙트 기술은 고장이 계속 발생할 때 리트랙트 값을 되돌려 주는 데 도움이 되며, 이상을 다시 던지는 것이 아니라 리트랙트 값을 되돌려 주는 데 도움이 된다.이는 반환 값이 감지될 때 시스템이 우아하게 시스템 안정을 유지하도록 하는 데 도움이 된다.시간 초과
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddPolicyHandler(timeoutPolicy);
시간 초과 정책은 응답 요청에 필요한 시간을 지정할 수 있습니다. 지정한 시간 내에 응답이 없으면 요청이 취소됩니다.var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
var noOpPolicy = Policy.NoOpAsync().AsAsyncPolicy<HttpResponseMessage>();
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddPolicyHandler(request => request.Method == HttpMethod.Get
? retryPolicy
: noOpPolicy
);
다른 HTTP 용어에는 적용되지 않고 408
요청에만 적용되는 정책을 정의해야 할 수도 있습니다.위의 예에서 시간 초과 정책은 GET
개의 요청에만 사용됩니다.var registry = services.AddPolicyRegistry();
registry.Add("DefaultRetryStrategy", HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(...));
registry.Add("DefaultCircuitBreaker", HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(...));
// Or
var registry = new PolicyRegistry()
{
{ "DefaultRetryStrategy", HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(...) },
{ "DefaultCircuitBreaker", HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(...) }
};
services.AddSingleton<IReadOnlyPolicyRegistry<string>>(registry);
services.AddHttpClient<IWeatherHttpClient, WeatherHttpClient>()
.AddPolicyHandlerFromRegistry("DefaultCircuitBreaker")
.AddPolicyHandlerFromRegistry("DefaultCircuitBreaker");
Polly는 strategy storage center와 같은 정책 레지스트리를 제공합니다. 등록된 정책은 응용 프로그램의 여러 위치에서 다시 사용할 수 있도록 합니다.당신은 Github에서 이 연습의 원본 코드를 찾을 수 있습니다.
Reference
이 문제에 관하여(각 ASPNET 핵심 웹 API 프로젝트 요구 사항 - 섹션 5 - Polly), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/moesmp/what-every-asp-net-core-web-api-project-needs-part-5-polly-1jdf텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)