Response.End ()가 유해한 것으로 간주됩니까?


198

이 KB 기사 는 ASP.NET이Response.End() 이 스레드를 중단 .

리플렉터는 다음과 같이 보입니다.

public void End()
{
    if (this._context.IsInCancellablePeriod)
    {
        InternalSecurityPermissions.ControlThread.Assert();
        Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
    }
    else if (!this._flushing)
    {
        this.Flush();
        this._ended = true;
        if (this._context.ApplicationInstance != null)
        {
            this._context.ApplicationInstance.CompleteRequest();
        }
    }
}

이것은 나에게 매우 가혹한 것 같습니다. KB 기사에서 알 수 있듯이 다음 앱의 코드는 Response.End()실행되지 않으며 놀랍게도 최소화하는 원칙을 위반합니다. Application.Exit()WinForms 앱 과 거의 같습니다 . 에 의한 스레드 중단 예외 Response.End()는 포착 할 수 없으므로 코드를 둘러싼 try... finally만족하지 않습니다.

항상 피해야하는지 궁금합니다 Response.End().

Response.End()언제 Response.Close(), 언제 , 언제 사용해야하는지 제안 할 수 있습니까 HttpContext.Current.ApplicationInstance.CompleteRequest()?

ref : Rick Strahl의 블로그 항목 .


내가받은 입력을 기반으로 내 대답은 예 Response.End입니다. 유해 하지만 일부 경우에 유용합니다.

  • 예외적 인 상황에서 Response.End()즉시 종료하려면 잡을 수없는 던지기로 사용하십시오 HttpResponse. 디버깅 중에도 유용 할 수 있습니다. 일상적인 반응을 피하십시오Response.End() .
  • Response.Close()클라이언트와의 연결을 즉시 닫는 데 사용 합니다. 당 이 MSDN 블로그 게시물 이 방법은 보통의 HTTP 요청을 처리하기위한 것이 아닙니다. 이 메소드를 호출 할만한 이유가있을 가능성은 거의 없습니다.
  • CompleteRequest()정상적인 요청을 끝내는 데 사용 합니다. 현재 이벤트가 완료된 후 CompleteRequestASP.NET 파이프 라인이 이벤트로 이동합니다. 따라서 호출 한 다음 응답에 더 많은 것을 쓰면 쓰기가 클라이언트로 전송됩니다.EndRequestHttpApplicationCompleteRequest

편집-2011 년 4 월 13 일

또한 선명도는 여기에 있습니다 :
- MSDN 블로그에 유용한 포스트
- 존 리드하여 유용한 분석


2
이 답변 이후로 무엇이 바뀌 었는지 전혀 알지 못하지만 나는 잘하고 Response.End ThreadAbortException있습니다.
— Maslow

1
또한 마음이 베어 Response.Redirect와 Server.Transfer모두 전화 Response.End와도 피해야한다.
— Owen Blacker

답변:


66

앱에서 예외 로거를 사용했다면 ThreadAbortException이 양성 의 s 로 물을 뿌릴 것입니다Response.End() 전화 입니다. 나는 이것이 "노크 오프!"라고 말하는 Microsoft의 방식이라고 생각합니다.

Response.End()예외적 인 조건이 있고 다른 조치가 불가능한 경우 에만 사용 합니다. 아마도이 예외를 기록하면 실제로 경고가 표시 될 수 있습니다.


107

TL; DR

처음에는 [Response.End]에 대한 모든 호출을 [...] CompleteRequest () 호출로 간단히 바꾸어야했지만 포스트 백 처리 및 html 렌더링을 피하려면 [.. .]도 무시됩니다.

Jon Reid , "최종 분석"


MSDN, Jon Reid 및 Alain Renon에 따라 :

ASP.NET 성능-예외 관리-예외를 피하는 코드 작성

Server.Transfer, Response.Redirect, Response.End 메소드는 모두 예외를 발생시킵니다. 이러한 각 메서드는 내부적으로 Response.End를 호출합니다. Response.End를 호출 하면 ThreadAbortException 예외가 발생 합니다.

ThreadAbortException 솔루션

HttpApplication.CompleteRequest ()는 페이지 이벤트 체인이 아니라 애플리케이션 이벤트 체인이 아닌 HttpApplication 이벤트 파이프 라인 [-]에서 스레드가 대부분의 이벤트를 건너 뛰도록하는 변수를 설정합니다.

...

이벤트를 처리하거나 페이지를 렌더링하기 전에 페이지를 종료해야하는지 플래그를 지정하는 클래스 레벨 변수를 작성하십시오. [...] RaisePostBackEvent 및 Render 메소드를 재정의하는 것이 좋습니다.

성능이 중요한 경우 정상적인 요청 처리에 Response.End 및 Response.Close가 사용되지 않습니다. Response.End는 관련 성능 저하로 요청 처리를 종료 할 수있는 편리한 방법입니다. Response.Close는 IIS / 소켓 수준에서 HTTP 응답을 즉시 종료하기위한 것으로 KeepAlive와 같은 문제가 발생합니다.

ASP.NET 요청을 종료하는 데 권장되는 방법은 HttpApplication.CompleteRequest입니다. HttpApplication.CompleteRequest는 ASP.NET 페이지 파이프 라인 (앱 파이프 라인의 한 단계)이 아니라 나머지 IIS / ASP.NET 응용 프로그램 파이프 라인을 건너 뛰므로 ASP.NET 렌더링은 수동으로 건너 뛰어야합니다.


암호

내가 말할 수있는 최선의 방법으로 Copyright © 2001-2007, C6 Software, Inc.


참고

HttpApplication.CompleteRequest

ASP.NET이 HTTP 파이프 라인 실행 체인에서 모든 이벤트와 필터링을 무시하고 EndRequest 이벤트를 직접 실행합니다.

응답. 종료

이 방법은 ASP와의 호환성 , 즉 ASP.NET.preceded ASP.NET보다 선행 된 COM 기반 웹 프로그래밍 기술과의 호환성을 위해서만 제공됩니다 . [엠파 시스 추가]

응답. 닫기

이 메소드는 갑작스러운 방식으로 클라이언트와의 연결을 종료하며 정상적인 HTTP 요청 처리를위한 것은 아닙니다 . [엠파 시스 추가]


4
HttpApplication.CompleteRequest는 ASP.NET 페이지 파이프 라인 (앱 파이프 라인의 한 단계)이 아닌 나머지 IIS / ASP.NET 응용 프로그램 파이프 라인을 건너 뛰므로 ASP.NET 렌더링은 수동으로 건너 뛰어야합니다. 그리고 당신은 이것을 어떻게 성취합니까?
— PilotBob

1
Jon Reid가 플래그를 설정하고 페이지의 RaisePostBackEvent 및 Render 메소드를 대체하여 원하는 경우 일반 구현을 건너 뛰는 방법을 보여주는 코드 링크를 참조하십시오. (당신은 아마 모든 앱의 페이지에서 상속해야 기본 클래스에서이 작업을 수행 할 것입니다.) web.archive.org/web/20101224113858/http://www.c6software.com/...
— user423430

4
다시 말하면 : HttpApplication.CompleteRequest는 Response.End와 같이 응답을 종료하지 않습니다.
— Glen Little

2
HttpApplication.CompleteRequest도 코드 흐름을 중지하지 않으므로 후속 행이 계속 실행됩니다. 브라우저에 표시되는 내용에는 영향을 미치지 않지만 해당 행이 다른 처리를 수행하는 경우 실제로 혼동 될 수 있습니다.
— Joshua Frank

3
나는 생각할 수 없지만 Web Forms는 의도적으로 설계되었습니다. Response.End ()를 호출하거나 페이지가 모든 것을로드 한 다음 응답을 억제하도록 성능이 저하되는 것은 무엇입니까? Response.End ()가 "더 많은"곳이 어디인지는 알 수 없습니다. 또한 Microsoft는이 코드에서 알 수 있듯이`ThreadAbortedException '을 일반 이벤트로 취급합니다. referencesource.microsoft.com/#System.Web/UI/Page.cs,4875 Response.End ()에 반하는 것은 실패 할 수 있다는 것 응답이 중단되어 응답이 때때로 표시 될 수 있습니다.
— 가산

99

이 질문은 모든 Google 검색의 상단 근처에 response.end에 대한 정보를 표시하므로 전체 ASPX 페이지를 렌더링하지 않고 이벤트에 대한 응답으로 CSV / XML / PDF 등을 게시하려는 저와 같은 다른 검색의 경우이 방법입니다. . (렌더 메소드를 재정의하는 것은 그러한 간단한 작업 IMO에 대해 지나치게 복잡합니다)

// Add headers for a csv file or whatever
Response.ContentType = "text/csv"
Response.AddHeader("Content-Disposition", "attachment;filename=report.csv")
Response.AddHeader("Pragma", "no-cache")
Response.AddHeader("Cache-Control", "no-cache")

// Write the data as binary from a unicode string
Dim buffer As Byte()
buffer = System.Text.Encoding.Unicode.GetBytes(csv)
Response.BinaryWrite(buffer)

// Sends the response buffer
Response.Flush()

// Prevents any other content from being sent to the browser
Response.SuppressContent = True

// Directs the thread to finish, bypassing additional processing
HttpContext.Current.ApplicationInstance.CompleteRequest()

1
이렇게하려면 APSX 페이지를 사용하지 않아야합니다. 많은 노력이 낭비됩니다. ASPX 페이지 이외의 다른 ASMX 또는 웹 서비스를 사용해야합니다.
— mattmanser

19
이것은 가장 쉬운 구현의 해답 인 것 같습니다. 키는 Response.SuppressContent = True입니다.
— Chris Weber

3
@mattmanser-동일한 자원을 다르게 표현하기 위해 별도의 페이지를 갖는 것이 항상 쉬운 / 최상의 / 권장되는 것은 아닙니다. REST 등을 생각해보십시오. 클라이언트가 헤더 또는 매개 변수를 통해 csv, xml을 원한다고 표시하면이 방법이 가장 적합하지만 asp.net의 일반 렌더링 기능을 통해 HTML 지원을 제공합니다.
— Chris Weber

1
이것은 나를 위해 작동하지 않았습니다. Response.End ()와 함께 작동하지만 Response.Close (), Response.Flush ()의 모든 조합을 사용하는 페이지가 있습니다. 응답에 GzipStream 필터가 있으면 HttpContext.Current.ApplicationInstance.CompleteRequest () 및 기타 다양한 기능이 작동하지 않았습니다. 일어나고있는 것처럼 보이는 것은 페이지가 여전히 내 파일과 함께 출력되고 있다는 것입니다. 마지막으로 Render () 함수 (공백)를 무시하고 해결했습니다.
— Aerik

1
CompleteRequest는 응용 프로그램 파이프 라인의 일부를 건너 뛰지 만 response.end와 같은 즉각적인 중지가 아닌 나머지 페이지 렌더링 프로세스를 통해 계속 실행됩니다. 이 페이지의 다른 답변에 대한 자세한 설명이 있습니다.
— Jay Zelos

11

"여전히 Response.Close와 CompleteRequest ()의 차이점을 모르겠습니다"라는 질문에 대해 다음과 같이 말합니다.

CompleteRequest ()를 선호하고 Response.Close ()를 사용하지 마십시오.

참고 항목 다음 문서를이 사례를 잘 요약 한 를 .

CompleteRequest ()를 호출 한 후에도 일부 텍스트 (예 : ASPX 코드에서 다시 작성)가 응답 출력 스트림에 추가됩니다. 다음 문서에 설명 된대로 Render 및 RaisePostBackEvent 메서드를 재정 의하여이를 방지 할 수 있습니다. .

BTW : 특히 파일 다운로드를 에뮬레이트하기 위해 http 스트림에 데이터를 쓸 때 Response.End () 사용을 방지하는 데 동의합니다. 로그 파일이 ThreadAbortExceptions로 가득 찰 때까지 과거에 Response.End ()를 사용했습니다.


설명에 따라 Render를 덮어 쓰는 데 관심이 있지만 "다음 기사"링크가 종료되었습니다. 항목을 업데이트 할 수 있습니까?
— paqogomez

답변이 늦어서 죄송합니다. 나는 그 기사에 무엇이 있는지 정확히 기억하지 못한다. 그러나, 나는 webarchive.org에 그것을 발견했습니다 web.archive.org/web/20101224113858/http://www.c6software.com/...
— 월 Šotola

9

" Response.End는 유해합니다 "라는 문구에 동의하지 않습니다 . 확실히 해롭지 않습니다. Response.End는 말하는 것을 수행합니다. 페이지 실행을 종료합니다. 리플렉터를 사용하여 구현 방식을 확인하는 것은 유익한 것으로 간주해야합니다.


제어 흐름으로 사용 하는 2cent Recommendation
AVOIDResponse.End() .
DO의 사용은 Response.End()당신이 요청 실행을 중지하고 (일반적으로) * 어떤 코드가 그 지점을지나 실행되지된다는 점에 유의해야합니다.


* Response.End()와 ThreadAbortException이 의.

Response.End() 현재 구현의 일부로 ThreadAbortException을 throw합니다 (OP에서 명시한대로).

ThreadAbortException은 catch 할 수있는 특수 예외이지만 catch 블록 끝에서 자동으로 다시 발생합니다.

ThreadAbortExceptions를 처리해야하는 코드를 작성하는 방법을 보려면 @Mehrdad의 SO에 대한 응답을 참조하십시오. RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup 메소드 를 참조 하는 finally 블록 에서 threadabortexception을 감지하는 방법 및 제한된 실행 영역


릭 Strahl 기사 언급은 유익하고, 확인뿐만 아니라 주석을 읽을 수 있도록. Strahl의 문제는 구체적입니다. 그는 데이터를 클라이언트 (이미지)로 가져 와서 이미지 제공 속도를 늦추지 않는 적중 추적 데이터베이스 업데이트를 처리하려고했기 때문에 Response.End가 호출 된 후 무언가를 수행하는 데 문제가있었습니다.


우리는이 게시물에보고 stackoverflow.com/questions/16731745/... 대신으로 Response.End ()의 Response.SuppressContent를 사용하여 제안 = 진정한 HttpContext.Current.ApplicationInstance.CompleteRequest ()
— jazzBox

3

프로그램 흐름을 제어하기 위해 Response.End () 사용을 고려한 적이 없습니다.

그러나 Response.End ()는 예를 들어 파일을 사용자에게 제공 할 때 유용 할 수 있습니다.

응답에 파일을 작성했으며 파일이 손상 될 수 있으므로 응답에 다른 항목을 추가하지 않으려 고합니다.


1
"응답이 완료되었습니다"라고 말하는 API의 필요성을 이해합니다. 그러나 Response.End ()도 스레드 중단을 수행합니다. 이것이 문제의 핵심입니다. 이 두 가지를 결합하는 것이 좋은 생각은 언제입니까?
— Cheeso

2

.NET과 Classic ASP에서 Response.End ()를 사용하여 이전에 강제로 종료했습니다. 예를 들어, certian에 많은 로그인 시도가있을 때 사용합니다. 또는 인증되지 않은 로그인으로 보안 페이지에 액세스하는 경우 (예 :)

    if (userName == "")
    {
        Response.Redirect("......");
        Response.End();
    }
    else
    {
      .....

사용자에게 파일을 제공 할 때 Flush를 사용하면 End로 인해 문제가 발생할 수 있습니다.


Flush ()는 "이것이 끝이 아닙니다"라는 것을 명심하십시오. "지금까지 모든 것을 플러시"합니다. "이것이 끝났습니다"를 원하는 이유는 클라이언트가 모든 내용을 가지고 있음을 클라이언트에게 알리고 서버가 다른 작업을 수행 할 수 있도록하는 것입니다. 로그 파일 업데이트, 데이터베이스 카운터 쿼리 등. Response.Flush를 호출 한 다음 그 중 하나를 수행하면 클라이언트가 계속 더 기다릴 수 있습니다. Response.End ()를 호출하면 컨트롤이 점프하고 DB가 쿼리 등을 얻지 못합니다.
— Cheeso

bool이 'endResponse : 페이지의 현재 실행을 종료해야하는지 여부를 나타냅니다.'– Override Response.Redirect ( "....", true)를 대신 사용할 수도 있습니다.
— Robert Paulson

로그인 자격 증명으로 보호하려는 페이지를 보호하려면 항상 양식 인증 프레임 워크를 사용하는 것이 좋습니다.
— Robert Paulson

3
실제로, 나 자신을 바로 잡기 위해 기본 Response.Redirect 및 Server.Transfer는 재정의를 호출하고 'false'를 전달하지 않는 한 내부적으로 Response.End를 호출하는 것으로 생각합니다. 코드가 작성된 방식은 Response.End입니다. ,
— 로버트 폴슨

1
Response.end는 .net에서 기존 ASP와는 다르게 작동합니다. .net에서는 threadabortexception이 발생하여 상당히 불쾌 할 수 있습니다.
— Andy

2

Response.End ()를 테스트 / 디버깅 메커니즘으로 만 사용했습니다.

<snip>
Response.Write("myVariable: " + myVariable.ToString());
Response.End();
<snip>

연구 측면에서 게시 한 내용을 보면 Response.End가 필요한 경우 디자인이 잘못 될 것이라고 말합니다.


0

클래식 ASP에서는 일부 Ajax 호출에서 TTFB (Time To First Byte)가 3-10 초로 나타 났으며 SQL 호출이 더 많은 일반 페이지의 TTFB보다 훨씬 큽니다.

리턴 된 ajax는 페이지에 삽입 될 HTML 세그먼트입니다.

TTFB는 렌더링 시간보다 몇 초 더 길었습니다.

렌더링 후에 response.end를 추가하면 TTFB가 크게 줄었습니다.

"</ body> </ html>"을 방출하여 동일한 효과를 얻을 수 있지만 json 또는 xml을 출력 할 때 작동하지 않을 수 있습니다. 여기 response.end가 필요합니다.


나는 이것이 오래된 대답이라는 것을 알고 있지만 다시 고전적인 ASP는 오래되었습니다. 나는 그것이 유용하다는 것을 알았다 ;-)
— Leif Neland
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.