ASP. NET 페이지 최적화, 불 러 오 는 속도 향상

34985 단어 asp.net
ASP. NET 페이지 불 러 오 는 속도 가 향상 되 는 방법: 1. HTTP Module 으로 페이지 의 수명 주 기 를 제어 합 니 다.2. 사용자 정의 Response. Filter 는 출력 스 트림 을 받 아 동적 페이지 의 정적 내용 (디스크 캐 시) 을 생 성 합 니 다.3. 페이지 GZIP 압축.4. OutputCache 프로 그래 밍 방식 으로 페이지 캐 시 를 출력 합 니 다.5. 페이지 공백 문자열 을 삭제 합 니 다.(Google 과 유사) 6. ViewState 를 완전히 삭제 합 니 다.7. 서버 컨트롤 에서 생 성 된 쓰레기 Naming Container 를 삭제 합 니 다.8. 계획 작업 을 사용 하여 페이지 를 제때에 생 성 합 니 다.(본 고 는 이 방법의 실현 을 포함 하지 않 습 니 다) 9. JS, CSS 압축, 통합, 캐 시, 이미지 캐 시.(문장 편폭 에 한 하여 본 고 는 이 방법의 실현 을 포함 하지 않 는 다) 10. 캐 시 파괴.(9 번 째 방법의 실현 은 포함 되 지 않 음)   상기 방법 에 대해 우 리 는 먼저 전체 페이지 프로 세 스 의 입구 와 핵심 인 HTTP 모듈 이 필요 하 다.1. 사용자 정의 Response. Filter 는 출력 스 트림 을 통 해 동적 페이지 의 정적 내용 (디스크 캐 시) 을 생 성 합 니 다. 다음 코드 를 통 해 알 수 있 습 니 다. request. RawUrl 을 캐 시 기반 으로 합 니 다. 임의의 QueryString 변 수 를 포함 할 수 있 기 때 문 입 니 다. 그리고 MD5 에 밀 RawUrl 을 추가 하여 서버 로 컬 파일 이름 의 변 수 를 얻 을 수 있 습 니 다.FileInfo 에서 이 파일 을 실행 합 니 다. 파일 의 마지막 생 성 시간 이 7 일 보다 적 으 면. Net 2.0 에 추 가 된 TransmitFile 방법 으로 파일 의 정적 내용 을 브 라 우 저 에 보 냅 니 다.파일 이 존재 하지 않 으 면 response. Filter 에서 얻 은 Stream 을 CommonFilter 클래스 에 전달 하고 FileStream 을 이용 하여 동적 페이지 의 내용 을 정적 파일 에 기록 합 니 다.
namespace ASPNETCode.HttpModules

{

    public class CommonModule : IHttpModule

    {

        public void Init(HttpApplication application)

        {

            application.BeginRequest += Application_BeginRequest;

        }

        private void Application_BeginRequest(object sender, EventArgs e)

        {

            var context = HttpContext.Current;

            var request = context.Request;

            var url = request.RawUrl;

            var response = context.Response;

            var path = GetPath(url);

            var file = new FileInfo(path);

            if (DateTime.Now.Subtract(file.LastWriteTime).TotalDays < 7)

            {

                response.TransmitFile(path);

                response.End();

                return;

            }

            try

            {

                var stream = file.OpenWrite();

                response.Filter = new CommonFilter(response.Filter, stream);

            }

            catch (Exception)

            {

                //Log.Insert("");

            }

        }

        public void Dispose()

        {

        }

        private static string GetPath(string url)

        {

            var hash = Hash(url);

            string fold = HttpContext.Current.Server.MapPath("~/Temp/");

            return string.Concat(fold, hash);

        }

        private static string Hash(string url)

        {

            url = url.ToUpperInvariant();

            var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();

            var bs = md5.ComputeHash(Encoding.ASCII.GetBytes(url));

            var s = new StringBuilder();

            foreach (var b in bs)

            {

                s.Append(b.ToString("x2").ToLower());

            }

            return s.ToString();

        }

    }

}

2. 페이지 GZIP 압축    페이지 GZIP 압축 은 거의 모든 편 에서 고성능 WEB 프로그램 을 설명 하 는 몇 가지 방법 중 하나 이다. GZIP 압축 을 사용 하면 서버 가 보 내 는 바이트 수 를 낮 출 수 있 고 고객 에 게 웹 페이지 의 속도 가 빠 르 고 대역 폭 에 대한 사용 상황 도 줄 일 수 있 기 때문이다.물론 클 라 이언 트 의 브 라 우 저가 지원 하 는 지 여부 도 존재 한다.따라서 우리 가 해 야 할 일 은 클 라 이언 트 가 GZIP 을 지원 하면 GZIP 압축 된 내용 을 보 내 고 지원 하지 않 으 면 정적 파일 의 내용 을 직접 보 내 는 것 입 니 다.다행히 현대 브 라 우 저 IE 6.7.8.0, 파이 어 폭 스 등 은 GZIP 을 지원 한다.이 기능 을 실현 하기 위해 서 는 위의 application 을 고 쳐 써 야 합 니 다.BeginRequest 이벤트:
private void Application_BeginRequest(object sender, EventArgs e)

{

    var context = HttpContext.Current;

    var request = context.Request;

    var url = request.RawUrl;

    var response = context.Response;

    var path = GetPath(url);

    var file = new FileInfo(path);

    //       

    ResponseCompressionType compressionType = this.GetCompressionMode(request);

    if (compressionType != ResponseCompressionType.None)

    {

        response.AppendHeader("Content-Encoding", compressionType.ToString().ToLower());

        if (compressionType == ResponseCompressionType.GZip)

        {

            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);

        }

        else

        {

            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);

        }

    }

    if (DateTime.Now.Subtract(file.LastWriteTime).TotalMinutes < 5)

    {

        response.TransmitFile(path);

        response.End();

        return;

    }

    try

    {

        var stream = file.OpenWrite();

        response.Filter = new CommonFilter(response.Filter, stream);

    }

    catch (Exception)

    {

        //Log.Insert("");

    }

}

private ResponseCompressionType GetCompressionMode(HttpRequest request)

{

    string acceptEncoding = request.Headers["Accept-Encoding"];

    if (string.IsNullOrEmpty(acceptEncoding))

        return ResponseCompressionType.None;

    acceptEncoding = acceptEncoding.ToUpperInvariant();

    if (acceptEncoding.Contains("GZIP"))

        return ResponseCompressionType.GZip;

    else if (acceptEncoding.Contains("DEFLATE"))

        return ResponseCompressionType.Deflate;

    else

        return ResponseCompressionType.None;

}

private enum ResponseCompressionType

{

    None,

    GZip,

    Deflate

}

3. OutputCache 프로 그래 밍 방식 으로 페이지 캐 시 를 출력 합 니 다. ASP. 내 장 된 OutputCache 캐 시 는 내용 을 세 곳 에 캐 시 할 수 있 습 니 다. 웹 서버, 프 록 시 서버 와 브 라 우 저 입 니 다.사용자 가 OutputCache 로 설 정 된 페이지 에 접근 할 때 ASP. NET 은 MSIL 이후 에 결 과 를 output cache 캐 시 에 기록 한 다음 브 라 우 저 에 보 냅 니 다. 사용자 가 같은 경로 의 페이지 에 접근 할 때 ASP. NET 은. aspx 컴 파일 및 MSIL 을 실행 하 는 과정 을 거치 지 않 고 Cache 의 내용 을 직접 보 냅 니 다. 따라서 프로그램 자체 의 효율 이 향상 되 지 않 았 지만,하지만 페이지 불 러 오 는 속 도 는 향상 되 었 다.이 기능 을 실현 하기 위해 서, 우 리 는 위의 응용 프로그램 을 계속 고 쳐 씁 니 다BeginRequest 이벤트, TransmitFile 이후 이 경로 의 페이지 를 OutputCache 프로 그래 밍 방식 으로 캐 시 합 니 다.
private void Application_BeginRequest(object sender, EventArgs e)

{

    if (DateTime.Now.Subtract(file.LastWriteTime).TotalMinutes < 5)

    {

        response.TransmitFile(path);

        //    OutputCache    ,       

        response.Cache.SetExpires(DateTime.Now.AddMinutes(5));

        response.Cache.SetCacheability(HttpCacheability.Public);

        response.End();

        return;

    }

}

4. CommonFilter 류 필터 ViewState, 필터 Naming Container, 공백 문자열, 그리고 디스크 를 생 성 하 는 캐 시 파일 을 실현 합 니 다. response. Filter 의 Stream 대상 을 CommonFilter 류 에 전달 합 니 다. 우선, 우 리 는 먼저 Stream 의 Write 방법 으로 디스크 의 캐 시 파일 을 생 성 합 니 다. 코드 는 다음 과 같 습 니 다. 이 코드 에서 구조 함수, Write 방법 만 초기 화 합 니 다.Close 방식 은 유용 합 니 다. 그 중에서 FileStream 필드 는 정적 파일 을 만 드 는 작업 대상 입 니 다.
namespace ASPNETCode.HttpModules

{

    public class CommonFilter : Stream

    {

        private readonly Stream _responseStream;

        private readonly FileStream _cacheStream;



        public override bool CanRead

        {

            get

            {

                return false;

            }

        }

        public override bool CanSeek

        {

            get

            {

                return false;

            }

        }

        public override bool CanWrite

        {

            get

            {

                return _responseStream.CanWrite;

            }

        }

        public override long Length

        {

            get

            {

                throw new NotSupportedException();

            }

        }

        public override long Position

        {

            get

            {

                throw new NotSupportedException();

            }

            set

            {

                throw new NotSupportedException();

            }

        }



        public CommonFilter(Stream responseStream, FileStream stream)

        {

            _responseStream = responseStream;

            _cacheStream = stream;

        }



        public override long Seek(long offset, SeekOrigin origin)

        {

            throw new NotSupportedException();

        }

        public override void SetLength(long length)

        {

            throw new NotSupportedException();

        }

        public override int Read(byte[] buffer, int offset, int count)

        {

            throw new NotSupportedException();

        }

        public override void Flush()

        {

            _responseStream.Flush();

            _cacheStream.Flush();

        }

        public override void Write(byte[] buffer, int offset, int count)

        {

            _cacheStream.Write(buffer, offset, count);

            _responseStream.Write(buffer, offset, count);

        }

        public override void Close()

        {

            _responseStream.Close();

            _cacheStream.Close();

        }

        protected override void Dispose(bool disposing)

        {

            if (disposing)

            {

                _responseStream.Dispose();

                _cacheStream.Dispose();

            }

        }

    }

}

그리고 우 리 는 정규 를 이용 하여 ViewState 를 완전히 삭제 합 니 다.
//   ViewState

private string ViewStateFilter(string strHTML)

{

    string matchString1 = "type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\"";

    string matchString2 = "type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\"";

    string matchString3 = "type=\"hidden\" name=\"__EVENTTARGET\" id=\"__EVENTTARGET\"";

    string matchString4 = "type=\"hidden\" name=\"__EVENTARGUMENT\" id=\"__EVENTARGUMENT\"";



    string positiveLookahead1 = "(?=.*(" + Regex.Escape(matchString1) + "))";

    string positiveLookahead2 = "(?=.*(" + Regex.Escape(matchString2) + "))";

    string positiveLookahead3 = "(?=.*(" + Regex.Escape(matchString3) + "))";

    string positiveLookahead4 = "(?=.*(" + Regex.Escape(matchString4) + "))";



    RegexOptions opt = RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.Compiled;



    Regex[] arrRe = new Regex[] {

        new Regex("\\s*<div>" + positiveLookahead1 + "(.*?)</div>\\s*", opt),

        new Regex("\\s*<div>" + positiveLookahead2 + "(.*?)</div>\\s*", opt),

        new Regex("\\s*<div>" + positiveLookahead3 + "(.*?)</div>\\s*", opt),

        new Regex("\\s*<div>" + positiveLookahead3 + "(.*?)</div>\\s*", opt),

        new Regex("\\s*<div>" + positiveLookahead4 + "(.*?)</div>\\s*", opt)

    };



    foreach (Regex re in arrRe)

    {

        strHTML = re.Replace(strHTML, "");

    }

    return strHTML;

}

다음은 페이지 공백 을 삭제 하 는 방법 입 니 다.
//     

private Regex tabsRe = new Regex("\\t", RegexOptions.Compiled | RegexOptions.Multiline);

private Regex carriageReturnRe = new Regex(">\\r\
<
", RegexOptions.Compiled | RegexOptions.Multiline); private Regex carriageReturnSafeRe = new Regex("\\r\
", RegexOptions.Compiled | RegexOptions.Multiline); private Regex multipleSpaces = new Regex(" ", RegexOptions.Compiled | RegexOptions.Multiline); private Regex spaceBetweenTags = new Regex(">\\s<", RegexOptions.Compiled | RegexOptions.Multiline); private string WhitespaceFilter(string html) { html = tabsRe.Replace(html, string.Empty); html = carriageReturnRe.Replace(html, "><"); html = carriageReturnSafeRe.Replace(html, " "); while (multipleSpaces.IsMatch(html)) html = multipleSpaces.Replace(html, " "); html = spaceBetweenTags.Replace(html, "><"); html = html.Replace("//<![CDATA[", ""); html = html.Replace("//]]>", ""); return html; }

다음은 ASP. NET 컨트롤 의 쓰레기 UniqueID 이름 을 삭제 하 는 방법 입 니 다.
//   NamingContainer

private string NamingContainerFilter(string html)

{

    RegexOptions opt =

        RegexOptions.IgnoreCase |

        RegexOptions.Singleline |

        RegexOptions.CultureInvariant |

        RegexOptions.Compiled;

    Regex re = new Regex("( name=\")(?=.*(" + Regex.Escape("$") + "))([^\"]+?)(\")", opt);

    html = re.Replace(html, new MatchEvaluator(delegate(Match m)

    {

        int lastDollarSignIndex = m.Value.LastIndexOf('$');

        if (lastDollarSignIndex >= 0)

        {

            return m.Groups[1].Value + m.Value.Substring(lastDollarSignIndex + 1);

        }

        else

        {

            return m.Value;

        }

    }));

    return html;

}

마지막 으로, 우 리 는 상기 여과 방법 을 CommonFilter 류 의 Write 방법 에 통합 시 켰 다.
public override void Write(byte[] buffer, int offset, int count)

{

    //   buffer    

    byte[] data = new byte[count];

    Buffer.BlockCopy(buffer, offset, data, 0, count);

    string html = System.Text.Encoding.UTF8.GetString(buffer);



    //         

    html = NamingContainerFilter(html);

    html = ViewStateFilter(html);

    html = WhitespaceFilter(html);

    byte[] outdata = System.Text.Encoding.UTF8.GetBytes(html);



    //     

    _cacheStream.Write(outdata, 0, outdata.GetLength(0));

    _responseStream.Write(outdata, 0, outdata.GetLength(0));

}

5. 캐 시 파 괴 는 상기 프로그램의 실현 을 거 쳐 웹 페이지 는 클 라 이언 트 에 고속 캐 시 되 었 습 니 다. 만약 에 사용자 가 사이트 가 캐 시 된 페이지 를 방문 하면 페이지 는 0 요청 속도 로 페이지 를 불 러 옵 니 다.그러나 배경 에 일부 데 이 터 를 업데이트 하면 프론트 사용 자 는 최신 데 이 터 를 제때에 볼 수 없 기 때문에 이러한 상황 을 바 꾸 려 면 캐 시 를 파괴 해 야 합 니 다.위의 프로그램 에 따 르 면 캐 시 를 파괴 하려 면 2 단계 만 해 야 합 니 다. 서버 에 있 는 임시 파일 을 업데이트 하고 OutputCache 가 지나 간 페이지 를 삭제 합 니 다.서버 에 있 는 파일 을 업데이트 하려 면 이 파일 만 삭제 하면 됩 니 다. 사용자 가 이 페이지 를 처음 방문 할 때 자동 으로 생 성 됩 니 다. 물론 프로그램 으로 먼저 삭제 한 후에 생 성 할 수도 있 습 니 다.
//     

foreach ( var file in Directory.GetFiles( HttpRuntime.AppDomainAppPath + "Temp" ) ) {

    File.Delete( file );

}

OutputCache 와 연 결 된 캐 시 항목 을 삭제 하려 면 코드 는 다음 과 같 습 니 다. 우 리 는 이 방법의 매개 변수 만 확보 해 야 합 니 다. 페이지 의 절대 경로 가 정확 하고 경 로 는 사용 할 수 없습니다.. / 이러한 상대 경 로 를 말 합 니 다.
//     

HttpResponse.RemoveOutputCacheItem( "/Default.aspx" );

최적화 가 끝나 지 않 았 습 니 다. 전 투 는 계속 되 고 있 습 니 다.

좋은 웹페이지 즐겨찾기