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.RedirectServer.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.