ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ASP.NET Core] 미들웨어(Middleware) 다룰때 유의사항
    .NET/ASP.NET Core 2021. 11. 5. 01:18
    반응형

    ASP.NET Core의 미들웨어는 이미지와 같이 파이프라인 개념으로 동작한다.

    이미지 출처 : https://docs.microsoft.com/ko-kr/aspnet/core/fundamentals/middleware/?view=aspnetcore-5.0

     

    따라서 아래와 같은 유의사항이 있다.

     

    1. Request Body Stream을 닫지마라

    일반적으론 Reader/Writer를 이용하여 Stream을 사용하면 닫는 코드를 명시적으로 입력하거나, 자동적으로 Close시킨다. 하지만 ASP.NET Core 미들웨어에선 파이프라인 개념으로 동작하므로 다음 Middleware가 올바른 동작을 하기위해선 Stream을 닫지 말아야 한다.

     

    아래소스코드는 모든 Request를 Log로 남기는 간략한 미들웨어 코드이다.

    app.Use(async (context, next) =>
    {
        context.Request.EnableBuffering(); // 없으면 오류남.
        using var reader = new StreamReader(
            context.Request.Body,
            leaveOpen: true); // 파이프라인이므로 스트림은 계속 열려있어야 한다.
        var body = await reader.ReadToEndAsync();
        logger.LogInformation(body); // logger는 별도 위치에서 선언함.
        context.Request.Body.Position = 0; // 파이프라인의 다음 작업에서도 원할하게 실행되야하므로. 읽었던 Body Stream의 위치를 초기화시킨다.
        await next.Invoke();
    });

    주석의 설명과 같이 leaveOpen을 명시적으로 `true`로 주어 Stream이 닫히는 것을 방지하고, 다음 Middleware에서도 원할한 동작이 가능할 수 있도록 Request.Body 스트림의 Position 설정을 0으로 초기화해줘야 한다.

     

    2. 미들웨어에서 직접 Http 응답을 처리하길 원한다면, next.Invoke는 호출하지마라

    아래코드는 미들웨어로 처리한 간략한 인증확인 코드이다. Authorization 헤더에 지정한 uuid(=guid) 값이 없으면 401 Unauthorized 코드를 응답하고, 코드가 정확하다면 다음 작업을 수행하는 코드이다. 

    app.Use(async (context, next) =>
    {
        context.Request.Headers.TryGetValue("Authorization", out var auth_key);
        if (auth_key == "c3e7c221-895b-4495-93a3-d7228f7ba8a4")
        {
        	// 인증을 위한 Claim/Roles 설정코드 작성
            await next.Invoke();
        }
        else
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
            await context.Response.WriteAsJsonAsync("Unauthorized");
        }
    });

    위와 같이 사용하면 오류가 없는데 종종 아래와 같이 실수할 때가 있다.

    app.Use(async (context, next) =>
    {
        context.Request.Headers.TryGetValue("Authorization", out var auth_key);
        if (auth_key == "c3e7c221-895b-4495-93a3-d7228f7ba8a4")
        {
            // 인증을 위한 Claim/Roles 설정코드 작성
        }
        else
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
            await context.Response.WriteAsJsonAsync("Unauthorized");
        }
        await next.Invoke(); // if 문이 실행되면 이상없지만, else 문이 실행될 경우 오류발생. 이미 WriteAsJsonAsync가 Response를 끝냄.
    });

    이 경우는 이미 WriteAsJsonAsync() 함수를 통해 응답을 처리했기 때문에 다음 작업을 진행하는 건 사실상 무의미하다. ASP.NET Core도 이 부분에 대해선 오류로 처리한다.

     

    ASP.NET Core를 통해 웹 서비스를 개발하면서 위에 나열한 유형의 실수를 종종 범하곤 한다. 다른사람들은 나처럼 똑같은 실수 반복하지 말았으면 한다.

    반응형

    댓글

Designed by Tistory.