ASP.NET Core 응용 오류 처리 의 Exception Handler Middleware 미들웨어 미들웨어 는"맞 춤 형 오류 페이지"를 보 여 줍 니 다.

머리말
Developer ExceptionPageMiddleware 미들웨어 미들웨어 미들웨어 는 보 여 준 오류 페이지 를 이용 하여 이상 과 현재 요청 한 상세 한 정 보 를 던 져 개발 자 들 이 오류 진단 작업 을 잘 하도록 보조 하고 ExceptionHandler Middleware 미들웨어 미들웨어 는 최종 사용 자 를 대상 으로 하 며 우 리 는 이 를 이용 하여 우호 적 인 맞 춤 형 오류 페이지 를 표시 할 수 있 습 니 다.관례 에 따라 Exception Handler Middleware 의 유형 정 의 를 살 펴 보 자.

 public class ExceptionHandlerMiddleware
 { 
 public ExceptionHandlerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions<ExceptionHandlerOptions> options, DiagnosticSource diagnosticSource); 
 public Task Invoke(HttpContext context);
 }
 
 public class ExceptionHandlerOptions
 {
 public RequestDelegate ExceptionHandler { get; set; }
 public PathString  ExceptionHandlingPath { get; set; }
 }
Developer ExceptionPageMiddleware 와 유사 합 니 다.우 리 는 ExceptionHandler Middleware 대상 을 만 들 때 도 설정 옵션 을 가 진 대상 을 제공 해 야 합 니 다.위의 코드 에서 알 수 있 듯 이 이것 은 ExceptionHandler Options 입 니 다.구체 적 으로 말 하면 하나의 ExceptionHandler Options 대상 은 ExceptionHandler 속성 을 통 해 요청 을 처리 하 는 RequestDelegate 대상 을 제공 합 니 다.만약 이상 이 발생 한 후에 지정 한 경로 로 자동 으로 방향 을 바 꾸 기 를 원한 다 면,우 리 는 ExceptionHandlerOptions 대상 의 ExceptionHandlingPath 속성 을 이용 하여 이 경 로 를 지정 할 수 있 습 니 다.저 희 는 보통 ApplicationBuilder 의 확장 방법 인 UseExceptionHandler 를 호출 하여 ExceptionHandler Middleware 미들웨어 미들웨어 를 등록 합 니 다.이 무 거 운 UseExceptionHandler 방법 은 다음 과 같은 방식 으로 미들웨어 의 등록 작업 을 완전 하 게 합 니 다.

 public static class ExceptionHandlerExtensions
 {
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app)=> app.UseMiddleware<ExceptionHandlerMiddleware>();
 
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, ExceptionHandlerOptions options) 
 => app.UseMiddleware<ExceptionHandlerMiddleware>(Options.Create(options));
 
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, string errorHandlingPath)
 { 
  return app.UseExceptionHandler(new  {
  ExceptionHandlingPath = new PathString(errorHandlingPath)
  });
 }
 
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, Action<IApplicationBuilder> configure)
 {
  IApplicationBuilder newBuilder = app.New();
  configure(newBuilder);
 
  return app.UseExceptionHandler(new ExceptionHandlerOptions
  {
  ExceptionHandler = newBuilder.Build()
  });
 } 
 }
이상 프로세서
exception Handler Middleware 미들웨어 처리 요청 의 본질은 후속 요청 처리 과정 에서 이상 이 발생 한 경우 등 록 된 이상 처리 기 를 사용 하여 요청 을 처리 하고 응답 하 는 것 입 니 다.이 이상 처리 기 는 우리 가 더 이상 알 수 없 는 RequestDelegate 대상 입 니 다.이 미들웨어 가 사용 하 는 요청 처리 논 리 는 대체적으로 다음 과 같은 코드 를 통 해 나타 날 수 있다.

 public class ExceptionHandlerMiddleware
 {
 private RequestDelegate  _next;
 private ExceptionHandlerOptions _options;
 
 public ExceptionHandlerMiddleware(RequestDelegate next, IOptions<ExceptionHandlerOptions> options,…)
 {
  _next  = next;
  _options = options.Value;
  …
 }
 
 public async Task Invoke(HttpContext context)
 {
  try
  {
  await _next(context);
  }
  catch 
  {
  context.Response.StatusCode = 500;
  context.Response.Clear();
  if (_options.ExceptionHandlingPath.HasValue)
  {
   context.Request.Path = _options.ExceptionHandlingPath;
  }
  RequestDelegate handler = _options.ExceptionHandler ?? _next;
  await handler(context);
  }
 }
 }
위의 코드 세 션 에서 보 듯 이 후속 요청 처리 과정 에서 이상 이 발생 하면 ExceptionHandler Middleware 미들웨어 미들웨어 는 이상 프로세서 의 RequestDelegate 대상 을 이용 하여 최종 요청 처 리 를 수행 합 니 다.Exception Handler Middleware 를 만 들 때 제공 하 는 Exception Handler Options 가 이러한 Request Delegate 대상 을 가지 고 있다 면 최종 적 으로 사용 하 는 이상 처리 장치 가 될 것 입 니 다.그렇지 않 으 면 이상 처리 장치 로 서 실제 적 으로 후속 미들웨어 입 니 다.다시 말 하면 만약 에 우리 가 Exception Handler Options 를 통 해 이상 프로 세 서 를 지정 하지 않 았 다 면 Exception Handler Middleware 중간 부품 은 후속 파이프 처리 요청 에 이상 을 던 진 상태 에서 요청 을 후속 파이프 에 다시 전달 할 것 이다.
ExceptionHandler Middleware 가 최종 적 으로 이상 처리 장 치 를 이용 하여 요청 을 처리 하기 전에 요청 에 대해 사전 처리 작업 을 합 니 다.예 를 들 어 응답 상태 코드 를 500 으로 설정 합 니 다.예 를 들 어 현재 모든 응답 내용 을 비 우 는 등 입 니 다.ExceptionHandlerOptions 의 ExceptionHandlingPath 속성 을 이용 하여 방향 을 바 꾸 는 경 로 를 설정 하면 이 경 로 를 현재 요청 한 경로 로 설정 합 니 다.이 를 제외 하고 Exception Handler Middleware 미들웨어 미들웨어 는 실제로 위 코드 세 션 에 반응 하지 않 는 작업 을 했다.
2.이상 한 전달 과 요청 경로 의 회복
Exception Handler Middleware 미들웨어 미들웨어 는 항상 이상 프로세서 로 서 의 RequestDelegate 대상 을 이용 하여 최종 이상 처리 작업 을 완성 하기 때문에 후자 가 던 진 이상 을 얻 을 수 있 도록 이 미들웨어 는 어떤 방식 으로 이상 을 전달 해 야 한다.그 밖 에 ExceptionHandler Middleware 미들웨어 미들웨어 가 현재 요청 한 경 로 를 바 꾸 기 때문에 전체 요청 처리 가 끝 난 후에 요청 경 로 를 원래 상태 로 복원 해 야 합 니 다.그렇지 않 으 면 사전 미들웨어 에서 정확 한 요청 경 로 를 가 져 올 수 없습니다.
요청 처리 과정 에서 던 진 이상 과 원본 요청 경로 의 복 구 는 해당 하 는 특성 을 통 해 이 루어 집 니 다.구체 적 으로 이 두 가 지 를 전달 하 는 특성 은 각각 Exception Handler Feature 와 Exception Handler Path Feature 라 고 하 는데 해당 하 는 인 터 페 이 스 는 각각 IException Handler Feature 와 IException Handler Path Feature 이다.아래 의 코드 부분 에서 보 듯 이 후 자 는 전 자 를 계승 한다.기본적으로 사용 되 는 Exception Handler Feature 는 이 두 인 터 페 이 스 를 실현 합 니 다.

 public interface IExceptionHandlerFeature
 {
 Exception Error { get; }
 }
 
 public interface IExceptionHandlerPathFeature : IExceptionHandlerFeature
 {
 string Path { get; }
 }
 
 public class ExceptionHandlerFeature : IExceptionHandlerPathFeature, 
 {
 public Exception Error { get; set; }
 public string Path { get; set; }
 }
ExceptionHandler Middleware 미들웨어 가 현재 요청 한 HttpContext 코드 를 요청 프로세서 에 전달 하기 전에 다음 과 같은 방식 으로 이상 한 원본 요청 경로 에 따라 ExceptionHandler Feature 대상 을 만 듭 니 다.이 대상 은 결국 HttpContext 에 추 가 됩 니 다.전체 요청 처리 프로 세 스 가 완전히 끝 난 후에 ExceptionHandler Middleware 미들웨어 미들웨어 는 이 기능 을 통 해 원 초적 인 요청 경 로 를 얻 고 현재 요청 컨 텍스트 에 다시 적용 합 니 다.

 public class ExceptionHandlerMiddleware
 {
  ...
  public async Task Invoke(HttpContext context)
  {
   try
   {
    await _next(context);
   }
   catch(Exception ex)
   {
    context.Response.StatusCode = 500;
 
    var feature = new ExceptionHandlerFeature()
    {
     Error = ex,
     Path = context.Request.Path,
    };
    context.Features.Set<IExceptionHandlerFeature>(feature);
    context.Features.Set<IExceptionHandlerPathFeature>(feature);
 
    if (_options.ExceptionHandlingPath.HasValue)
    {
     context.Request.Path = _options.ExceptionHandlingPath;
    }
    RequestDelegate handler = _options.ExceptionHandler ?? _next;
 
    try
    {
     await handler(context);
    }
    finally
    {
     context.Request.Path = originalPath;
    }
   }
  }
 }
구체 적 으로 이상 처 리 를 할 때,우 리 는 현재 HttpContext 에서 이 ExceptionHandlerFeature 대상 을 추출 하여 던 진 이상 과 원본 요청 경 로 를 얻 을 수 있 습 니 다.아래 코드 에서 보 듯 이 저 희 는 HandleError 방법 을 이용 하여 맞 춤 형 오류 페이지 를 보 여 줍 니 다.이 방법 에서 우 리 는 본 격 적 으로 이 Exception Handler Feature 특성 을 통 해 이상 을 던 지고 그 유형,정보 와 스 택 을 추적 하여 보 여 줍 니 다.

 public class Program
 {
  public static void Main()
  {
   new WebHostBuilder()
    .UseKestrel()
    .ConfigureServices(svcs=>svcs.AddRouting())
    .Configure(app => app
     .UseExceptionHandler("/error")
     .UseRouter(builder=>builder.MapRoute("error", HandleError))
     .Run(context=> Task.FromException(new InvalidOperationException("Manually thrown exception"))))
    .Build()
    .Run();
  }
 
  private async static Task HandleError(HttpContext context)
  {
   context.Response.ContentType = "text/html";
   Exception ex = context.Features.Get<IExceptionHandlerPathFeature>().Error;
 
   await context.Response.WriteAsync("<html><head><title>Error</title></head><body>");
   await context.Response.WriteAsync($"<h3>{ex.Message}</h3>");
   await context.Response.WriteAsync($"<p>Type: {ex.GetType().FullName}");
   await context.Response.WriteAsync($"<p>StackTrace: {ex.StackTrace}");
   await context.Response.WriteAsync("</body></html>");
  }
이 앱 에서'error'라 는 템 플 릿 을 등록 한 경로 가 이 HandleError 방법 을 가리 키 고 있 습 니 다.확장 방법 을 호출 하여 UseExceptionHandler 에 등 록 된 ExceptionHandler Middleware 에 대해 서 는 이 경 로 를 이상 처리 경로 로 설정 합 니 다.브 라 우 저 에서 보 내 는 요청 은 다음 그림 과 같은 오류 페이지 를 얻 을 수 있 습 니 다.

3.캐 시 지우 기
자원 을 가 져 오 는 GET 요청 에 있어 서 요청 목표 가 상대 적 으로 안정 적 인 자원 이 라면 클 라 이언 트 캐 시 방식 으로 같은 자원 의 빈번 한 가 져 오기 와 전송 을 피 할 수 있 습 니 다.자원 공급 자로 서 의 웹 응용 에 있어 서 요청 을 처리 할 때 대상 자원 을 응답의 주체 내용 으로 하 는 것 외 에 캐 시 를 제어 하 는 관련 응답 헤 더 를 설정 해 야 한다.캐 시 는 대부분의 경우 성공 적 인 응답 에 만 적용 되 기 때문에 서버 가 요청 을 처리 하 는 과정 에서 이상 이 발생 하면 이전에 설정 한 캐 시 헤더 가 응답 메시지 에 나타 나 지 말 아야 합 니 다.Exception Handler Middleware 미들웨어 미들웨어 에 있어 캐 시 헤더 도 중요 한 업무 입 니 다.
ExceptionHandler Middleware 미들웨어 미들웨어 가 캐 시 응답 헤더 에 대한 제 거 를 간단 한 인 스 턴 스 를 통 해 보 여줄 수 있 습 니 다.다음 응용 프로그램 에서 저 희 는 요청 한 처 리 를 Invoke 방법 에서 50%이상 을 던 질 수 있 습 니 다.정상 적 인 응답 내용 을 되 돌려 주 든 이상 을 던 지 든 이 방법 은 먼저'Cache-Control'의 응답 헤 더 를 설정 하고 캐 시 시간 을 1 시간 으로 설정 합 니 다('Cache-Control:max-age=3600').

 public class Program
 {
  public static void Main()
  {
   new WebHostBuilder()
    .UseKestrel()
    .ConfigureServices(svcs => svcs.AddRouting())
    .Configure(app => app
     .UseExceptionHandler(builder => builder.Run(async context => await context.Response.WriteAsync("Error occurred!")))
     .Run(Invoke))
    .Build()
    .Run();
  }
 
  private static Random _random = new Random();
  private async static Task Invoke(HttpContext context)
  {
   context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue
   {
    MaxAge = TimeSpan.FromHours(1)
   };
 
   if (_random.Next() % 2 == 0)
   {
    throw new InvalidOperationException("Manually thrown exception...");
   }
   await context.Response.WriteAsync("Succeed...");
  }
 }
확장 방법 을 호출 하여 UseExceptionHandler 에 등 록 된 ExceptionHandler Middleware 미들웨어 미들웨어 는 이상 을 처리 할 때"Error occurred!"라 는 내용 에 응답 합 니 다.문자열다음 과 같은 두 응답 메 시 지 는 각각 정상 적 인 응답 과 이상 한 상황 에 대응 합 니 다.프로그램 에 설 치 된 캐 시 헤더 인'Cache-Control:max-age=3600'은 상태 코드 가'200 OK'인 응답 에 만 나타 납 니 다.상태 코드 가'500 Internal Server Error'인 응답 에 서 는 캐 시 와 관련 된 세 개의 헤더 가 나타 납 니 다.캐 시 를 금지 하거나 캐 시 만 료 를 지시 하 는 것 이 목적 입 니 다.

 HTTP/1.1 200 OK
 Date: Sat, 17 Dec 2016 14:39:02 GMT
 Server: Kestrel
 Cache-Control: max-age=3600
 Content-Length: 10
 
 Succeed...
 
 
 HTTP/1.1 500 Internal Server Error
 Date: Sat, 17 Dec 2016 14:38:39 GMT
 Server: Kestrel
 Cache-Control: no-cache
 Pragma: no-cache
 Expires: -1
 Content-Length: 15
 
 Error occurred!
exception Handler Middleware 미들웨어 미들웨어 가 캐 시 응답 헤더 에 대한 제 거 는 다음 과 같은 코드 세 션 에 나타 납 니 다.HttpResponse 를 호출 하 는 OnStarting 방법 으로 리 셋(ClearCacheHeaders)을 등록 한 것 을 알 수 있 습 니 다.상기 세 개의 캐 시 헤더 가 이 리 셋 에 설정 되 어 있 습 니 다.그 밖 에 우 리 는 이 반전 방법 이 ETag 헤더 도 제거 하 는 것 을 보 았 다.이것 은 목표 자원 이 정상 적 인 응답 을 받 지 못 했 기 때문에 자원 의'서명'을 나타 내 는 ETag 헤더 가 응답 메시지 에 나타 나 서 는 안 된다 는 것 을 잘 이해 할 수 있다.

 public class ExceptionHandlerMiddleware
 {
  ...
  public async Task Invoke(HttpContext context)
  {
   try
   {
    await _next(context);
   }
   catch (Exception ex)
   {
    …
    context.Response.OnStarting(ClearCacheHeaders, context.Response);
    RequestDelegate handler = _options.ExceptionHandler ?? _next;
    await handler(context);
   }
  }
 
  private Task ClearCacheHeaders(object state)
  {
   var response = (HttpResponse)state;
   response.Headers[HeaderNames.CacheControl]  = "no-cache";
   response.Headers[HeaderNames.Pragma]   = "no-cache";
   response.Headers[HeaderNames.Expires]   = "-1";
   response.Headers.Remove(HeaderNames.ETag);
   return Task.CompletedTask;
  }
 }
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기