ASP에서 대용량 파일을 전달하는 방법NET 응답?
데이터베이스에서 스트리밍 파일 콘텐츠를 대체할 방법을 찾고 있지 않습니다. 실제로 문제의 근원을 찾고 있습니다. 이 파일은 IIS 6이 클래식 모드로 앱을 실행할 때까지 실행되고 있었습니다. 이제 IIS를 7로 업그레이드하고 파이프라인 모드로 앱 풀을 실행하고 있으며 이 문제가 시작되었습니다.
핸들러가 있는데 거기서 고객 요청에 대용량 파일을 전달해야 합니다.그리고 저는 다음과 같은 문제에 직면해 있습니다.
파일 크기는 평균 4~100MB이므로 80MB 파일 다운로드를 고려해 보겠습니다.
버퍼링 켜기, 느린 시작
Response.BufferOutput = True;
따라서 사용자 다운로드 및 진행률 표시줄도 몇 초, 일반적으로 3~20초까지 나타나지 않으므로 파일 시작 속도가 매우 느립니다. 그 이유는 IIS가 먼저 전체 파일을 읽고 콘텐츠 길이를 결정한 다음 파일 전송을 시작하기 때문입니다.비디오 플레이어에서 파일이 재생되고 실행 속도가 매우 느리지만 아이패드는 파일을 먼저 다운로드하기 때문에 속도가 빠릅니다.
버퍼링 꺼짐, 컨텐츠 길이 없음, 빠른 시작, 진행 없음
Reponse.BufferOutput = False;
그러면 바로 시작되지만, 최종 클라이언트(Chrome과 같은 일반 브라우저)는 IIS도 모르기 때문에 Content-Length를 모르므로 진행 상황을 표시하지 않고 대신 XKB가 다운로드되었다고 표시합니다.
버퍼링 꺼짐, 수동 컨텐츠 길이, 빠른 시작, 진행 및 프로토콜 위반
Response.BufferOutput = False;
Response.AddHeader("Content-Length", file.Length);
이렇게 하면 Chrome 등에서 즉시 파일을 올바르게 다운로드할 수 있지만 경우에 따라 IIS 핸들러가 "원격 클라이언트 폐쇄 연결" 오류를 발생시키고(이 오류는 매우 빈번함) 다른 WebClient가 프로토콜을 위반하게 됩니다.이는 모든 요청이 아니라 전체 요청의 5~10%에서 발생합니다.
우리가 버퍼링을 하지 않을 때 IIS는 100 continue라고 불리는 어떤 것도 보내지 않고 클라이언트는 어떤 출력도 기대하지 않고 연결이 끊길 수 있습니다.그러나 소스에서 파일을 읽는 데는 더 오랜 시간이 걸릴 수 있지만 클라이언트 측에서는 시간 초과가 증가했지만 IIS가 시간 초과되어 제어할 수 없는 것 같습니다.
응답자가 계속 100을 보내도록 강제하고 아무도 연결을 닫지 못하게 할 수 있는 방법이 있습니까?
갱신하다
Firefox/Chrome에서 헤더를 팔로우했는데 프로토콜 위반이나 잘못된 헤더에 대해 특이한 것은 없습니다.
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:POST, GET, OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1728000
Cache-Control:private
Content-Disposition:attachment; filename="24.jpg"
Content-Length:22355
Content-Type:image/pjpeg
Date:Wed, 07 Mar 2012 13:40:26 GMT
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
업데이트 2
재활용을 돌리는 것은 여전히 많은 것을 제공하지 않았지만 MaxWorker Process를 8로 늘렸고 지금은 이전보다 오류 수가 적습니다.
하지만 평균적으로 1초에 200개의 요청 중 2개에서 10개의 요청이 실패하고, 거의 모든 대체 초에 이런 일이 발생합니다.
업데이트 3
"서버가 프로토콜 위반을 저질렀습니다."와 함께 5%의 요청이 계속 실패했습니다.섹션=ResponseStatusLine", WebClient를 사용하는 웹 서버에서 콘텐츠를 다운로드하는 다른 프로그램이 있는데, 이 오류는 1초에 4-5번 발생하는데 평균 5%의 요청이 실패합니다.WebClient 장애를 추적할 방법이 있습니까?
재정의된 문제
0바이트 파일 수신
IIS가 어떤 이유로 연결을 닫습니다. WebConfig의 클라이언트 측에서 파일에 대해 0바이트가 아닌 0바이트가 수신됩니다. SHA1 해시 검사를 수행합니다. 이것은 IIS 웹 서버에서 오류가 기록되지 않는다는 것을 알려주었습니다.
이것은 저의 실수였고, 엔티티 프레임워크를 사용하는 동안 읽기가 트랜잭션 범위에 포함되지 않아 더럽게(커밋되지 않은 행) 읽혀져 트랜잭션 범위에 넣음으로써 이 문제가 해결되었습니다.
프로토콜 위반 예외 발생
WebClient는 "서버가 프로토콜 위반을 저질렀습니다."라고 WebException을 던집니다.섹션 = 응답 상태 라인.
나는 내가 안전하지 않은 헤더 파싱을 활성화할 수 있다는 것을 알지만 그것이 중요한 것이 아닙니다. 적절한 헤더를 보내는 것이 내 HTTP 핸들러일 때, IIS가 왜 추가적인 것을 보내고 있는지 모르겠습니다(파이어폭스와 크롬에서 확인했지만 특이한 것은 없음). 이런 일은 2%만 발생합니다.
업데이트 4
sc-win3264 오류를 찾았는데 어디선가 MinBytesPerSecond에 대한 WebLimits가 240에서 0으로 변경되어야 한다는 것을 읽었지만 모든 것은 동일합니다.그러나 IIS가 64 sc-win32 오류를 기록할 때마다 IIS는 HTTP Status를 200으로 기록하지만 약간의 오류가 있었습니다.이제 200에 대한 실패한 추적 기록을 켤 수 없습니다. 왜냐하면 대량의 파일이 발생하기 때문입니다.
위의 두 문제 모두 MinBytesPerSecond를 증가시키고 Sessions를 비활성화함으로써 해결되었으며, 모든 사항을 요약한 자세한 답변을 추가하였습니다.
bufferOutput을 false로 설정한 경우 실패의 원인은 IIS가 사용자가 보낸 파일을 gzip하려고 하기 때문이며 Content-Length IIS는 압축된 파일로 다시 변경할 수 없으며 오류가 시작됩니다(*).
그렇게keep the BufferOutput to false, and second disable the gzip from iis for the files you send
하지 않도록 부분을 방식으로 않도록 -는에해든고을다밍로을는여에지록을p을g에r다는록지e을-g여pesrdsueplmepfu
같은 이유로 몇 가지 비슷한 질문: ASP.로드 밸런싱된 서버에서 로드하는 동안 NET 사이트가 페이지 상단에 가끔 정지되거나 이상한 텍스트가 표시됨
HTTP 압축:일부 외부 스크립트/CSS가 제대로 압축 해제되지 않음
(*) 헤더를 다시 변경하는 것은 어떨까요? IIS에서 이 옵션을 활성화하고 헤더가 브라우저로 전송할 준비가 되지 않은 경우를 제외하고는 헤더를 설정한 순간부터 다시 가져올 수 없기 때문입니다.
따르다
압축을 풀지 않았다면 다음으로 생각나는 것은 파일이 전송되고 어떤 이유로 연결이 지연되어 타임아웃되어 닫혔다는 것입니다.그러면 "Remote Host Closed The Connection"이 표시됩니다.
이는 원인에 따라 해결할 수 있습니다.
- 클라이언트가 정말로 연결을 닫았습니다.
- 처리기를 사용하는 경우, 시간 초과는 페이지 자체에서 발생합니다(아마도 메시지는 "Page Timeed Out"이어야 함).
- 유휴 대기 상태에서 시간 초과가 발생하고, 페이지가 실행 시간을 초과하여 시간 초과가 발생하고, 연결이 종료됩니다.이 경우 메시지가 Page Timeed Out(페이지 시간 초과)일 수 있습니다.
- 파일을 보내는 순간 풀이 재활용됩니다.모든 풀 재활용을 비활성화합니다!이것은 제가 지금 생각할 수 있는 가장 가능한 경우입니다.
IIS에서 전송되는 경우 웹 사이트 속성으로 이동하여 가장 큰 "연결 시간 초과" 및 "HTTP Keep-Alives 활성화"를 설정했는지 확인합니다.
web.config를 변경하여 페이지 시간 초과(특정 페이지에 대해서만 프로그래밍 방식으로 변경할 수 있음)
<httpRuntime executionTimeout="43200"
또한 http://weblogs.asp.net/aghausman/archive/2009/02/20/prevent-request-timeout-in-asp-net.aspx 을 확인해 보십시오.
세션 잠금
한 가지 더 검토해야 할 사항은 파일을 보낼 때 사용하는 핸들러에서 세션을 사용하지 않는 것입니다. 세션은 작업을 완료할 때까지 잠그고 사용자가 파일을 다운로드하는 데 더 오랜 시간이 걸릴 경우 두 번째 세션에서 시간이 초과될 수 있기 때문입니다.
일부 친척:
이미지를 랜덤하게 느리게 반환하려면 aspx 페이지를 호출합니다.
대답.WriteFile 기능이 실패하고 504 게이트웨이 타임아웃이 발생함
IIS에서 대용량 파일을 전달하는 올바른 방법은 다음과 같은 옵션이 있습니다.
- MinBytesPerSecond를 WebLimits에서 Zero로 설정(크기 전송이 작은 KeepAlive 연결을 보유한 클라이언트를 IIS가 닫기로 선택하므로 성능 향상에 확실히 도움이 됩니다.)
- 애플리케이션 풀에 더 많은 작업자 프로세스 할당. 8로 설정했습니다. 이제 서버에서 더 큰 파일을 배포하는 경우에만 이 작업을 수행해야 합니다.이로 인해 다른 사이트의 성능이 저하되는 것은 확실하지만, 이를 통해 더 나은 제공이 보장됩니다.이 서버는 하나의 웹사이트만 있고 거대한 파일만 전송하기 때문에 우리는 8로 설정했습니다.
- 앱 풀 재활용 끄기
- 세션 끄기
- 버퍼링 사용 상태로 유지
- 다음 각 단계를 수행하기 전에 응답 여부를 확인합니다.IsClientConnected가 참입니다. 그렇지 않으면 포기하고 아무것도 보내지 않습니다.
- 파일을 보내기 전에 내용-길이 설정
- 응답 플러시
- 출력 스트림에 쓰기, 일정 간격으로 플러시
제가 할 일은 잘 알려지지 않은 ASP를 사용하는 것입니다.NET 응답.TransmitFile 메서드는 매우 빠르며(그리고 IIS 커널 캐시를 사용할 가능성도 있습니다) 모든 헤더 작업을 처리합니다.Windows 관리되지 않는 TransmitFile API를 기반으로 합니다.
하지만 이 API를 사용하려면 전송할 물리적인 파일이 필요합니다.여기 가상의 myCacheFilePath 물리적 파일 경로로 이를 수행하는 방법을 설명하는 의사 c# 코드가 있습니다.또한 클라이언트 캐싱 가능성도 지원합니다.물론, 파일을 이미 가지고 있는 경우에는 해당 캐시를 생성할 필요가 없습니다.
if (!File.Exists(myCacheFilePath))
{
LoadMyCache(...); // saves the file to disk. don't do this if your source is already a physical file (not stored in a db for example).
}
// we suppose user-agent (browser) cache is enabled
// check appropriate If-Modified-Since header
DateTime ifModifiedSince = DateTime.MaxValue;
string ifm = context.Request.Headers["If-Modified-Since"];
if (!string.IsNullOrEmpty(ifm))
{
try
{
ifModifiedSince = DateTime.Parse(ifm, DateTimeFormatInfo.InvariantInfo);
}
catch
{
// do nothing
}
// file has not changed, just send this information but truncate milliseconds
if (ifModifiedSince == TruncateMilliseconds(File.GetLastWriteTime(myCacheFilePath)))
{
ResponseWriteNotModified(...); // HTTP 304
return;
}
}
Response.ContentType = contentType; // set your file content type here
Response.AddHeader("Last-Modified", File.GetLastWriteTimeUtc(myCacheFilePath).ToString("r", DateTimeFormatInfo.InvariantInfo)); // tell the client to cache that file
// this API uses windows lower levels directly and is not memory/cpu intensive on Windows platform to send one file. It also caches files in the kernel.
Response.TransmitFile(myCacheFilePath)
이 코드 조각은 저에게 적합합니다.클라이언트에게 데이터 스트림을 즉시 시작합니다.다운로드 중 진행 상황을 보여줍니다.HTTP를 위반하지 않습니다.Content-Length 헤더를 지정하고 청크 전송 인코딩을 사용하지 않습니다.
protected void PrepareResponseStream(string clientFileName, HttpContext context, long sourceStreamLength)
{
context.Response.ClearHeaders();
context.Response.Clear();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-Disposition", string.Format("filename=\"{0}\"", clientFileName));
//set cachebility to private to allow IE to download it via HTTPS. Otherwise it might refuse it
//see reason for HttpCacheability.Private at http://support.microsoft.com/kb/812935
context.Response.Cache.SetCacheability(HttpCacheability.Private);
context.Response.Buffer = false;
context.Response.BufferOutput = false;
context.Response.AddHeader("Content-Length", sourceStreamLength.ToString (System.Globalization.CultureInfo.InvariantCulture));
}
protected void WriteDataToOutputStream(Stream sourceStream, long sourceStreamLength, string clientFileName, HttpContext context)
{
PrepareResponseStream(clientFileName, context, sourceStreamLength);
const int BlockSize = 4 * 1024 * 1024;
byte[] buffer = new byte[BlockSize];
int bytesRead;
Stream outStream = m_Context.Response.OutputStream;
while ((bytesRead = sourceStream.Read(buffer, 0, BlockSize)) > 0)
{
outStream.Write(buffer, 0, bytesRead);
}
outStream.Flush();
}
언급URL : https://stackoverflow.com/questions/9600856/how-to-deliver-big-files-in-asp-net-response
'programing' 카테고리의 다른 글
안드로이드 프로젝트에서 사용하지 않는 문자열을 쉽게 찾을 수 있는 방법이 있습니까? (0) | 2023.09.16 |
---|---|
Swift Xcode 인덱스 동결 또는 느려짐 (0) | 2023.09.16 |
데이터베이스 트리거가 필요합니까? (0) | 2023.09.11 |
Powershell Write-Host를 텍스트 파일에 추가 - 컴퓨터 이름 및 타임 스탬프 (0) | 2023.09.11 |
모듈을 python에 "pythonport"한 다음 가져오기 후 코드를 변경하는 방법 (0) | 2023.09.11 |