Rambler's Top100
Главная
Новости
Статьи
Форумы
Книги
Коды
Сообщество
Блоги
О нас
 

Логин

Email:
  Пароль:

Войти
Зарегистрироваться
Забыл пароль

Поиск

 Искать :
 
Вперед


Очищаем HTML от лишних знаков

Очищаем HTML от лишних знаков

Автор: Никита Егоров (nikitaegorov@gmail.com)
Опубликовано: 19 June 2006
Уровень: Решение

Версия для печати

Проголосовало 4 читателей
Средняя оценка 3.25

Однажды посмотрев HTML-документ, генерируемый ASP.NET и содержащий GridView, я заметил, что большое количество символов, содержащихся на странице - пробелы и знаки табуляции. Очевидно, ASP.NET щедро расставлял их, где только можно.

Конечно, избавиться от лишних килобайтов HTML-документа можно, воспользовавшись библиотеками, которые сжимают HTML-документы при помощи различных алгоритмов. Но такой метод заставит сервер сначала сжать генерируемый HTML-документ, а браузеру пользователя придется распаковывать пришедший ему документ.

Я же хочу в своей статье предложить способ как избавиться от различных ненужных символов, которые содержатся на страницах. Этот способ основан на использовании сборки HTTPModule.

Так что же такое HTTPModule? Вот что о нем говорится в библиотеке MSDN:

HttpModule — это сборка, реализующая интерфейс IHttpModule и обрабатывающая события. ASP.NET включает набор сборок HttpModule, которые могут использоваться в приложениях пользователей. Например, SessionStateModule предоставляется ASP.NET для поставки в приложение служб состояния сеанса. Пользовательские обработчики HttpModule могут быть созданы в качестве ответа на событие ASP.NET или событие пользователя.

Общая процедура написания обработчика HttpModule следующая:

  • Реализация интерфейса IHttpModule.
  • Обработка метода Init и регистрация необходимых событий.
  • Обработка событий.
  • Реализация (при необходимости) метода Dispose, если требуется выполнить очистку.
  • Регистрация модуля в файле Web.config.

HTTP Module включается в процесс обработки запроса пользователя после создания объекта HTTP Application и перед созданием HTTP Handle, так что HTTP Module позволяет обработать следующие события объекта HTTP Application:

  • BeginRequest
  • AuthenticateRequest
  • PostAuthenticateRequest
  • AuthorizeRequest
  • PostAuthorizeRequest
  • ResolveRequestCache
  • PostResolveRequestCache
  • PostMapRequestHandler
  • AcquireRequestState
  • PostAcquireRequestState
  • PreRequestHandlerExecute
  • PostRequestHandlerExecute
  • ReleaseRequestState
  • PostReleaseRequestState
  • UpdateRequestCache
  • PostUpdateRequestCache
  • EndRequest

Подключение обработчиков событий выполняется в методе Init класса HTTPModule.

В своем примере мне необходимо подключить обработчик на 2 события ReleaseRequestState, как раз после того, как была сгенерирована HTML-версия страницы и объект Response готов к отправке пользователю.

        /// <summary> 
        /// Подключение обработчиков событий 
        /// </summary> 
        public void Init(HttpApplication context) 
        { 
             //Подключаем обработчик на событие ReleaseRequestState 
             context.ReleaseRequestState += new EventHandler(this.context_Clear); 
             //Подключаем обработчик на событие PreSendRequestHeaders 
             context.PreSendRequestHeaders += new EventHandler(this.context_Clear); 
             //Два обработчика необходимы для совместимости с библиотеками сжатия HTML-документов 
        }
  

Сам обработчик будет иметь следующий вид:

        /// <summary> 
        /// Обработчик события PostRequestHandlerExecute 
        /// </summary> 
        void context_Clear(object sender, EventArgs e) 
        { 
             HttpApplication app = (HttpApplication)sender; //Получение HTTP Application 
             //Получаем имя файла который обрабатывается 
             string realPath = app.Request.Path.Remove(0, app.Request.ApplicationPath.Length + 1);  
             //Проверяем не является ли он ссылкой на ресурс сборки             
             if (realPath == "WebResource.axd")  
                  return; 
             //Проверяем тип содержимого 
             if (app.Response.ContentType == "text/html" || app.Response.ContentType == "text/javascript")           
                 //Устанавливаем фильтр-обработчик 
                 app.Context.Response.Filter = new HTMLClearer(app.Context.Response.Filter);  
        }
  

Фильтр-обработчик - это самое главное. Он позволяет изменять содержимое объекта Response. А дополнительные проверки необходимы, чтобы исключить обработку ресурсов сборок и документов, тип которых отличен от text/html и text/javascript (в документах другого типа нет необходимости убирать лишние символы).

 Теперь уделим внимание обработчику содержимого Response.

Это класс, являющийся наследником System.IO.Stream. В его реализации нам интересен только один метод - это метод Write:

        /// <summary> 
        /// Обрабатываем данные поступающие в Response 
        /// </summary> 
        public override void Write(byte[] buffer, int offset, int count) 
            { 
                //Преобразовываем массив байт в строку 
                string s = System.Text.Encoding.UTF8.GetString(buffer); 
                //Используя регулярные выражения убираем все ненужные символы 
                s = Regex.Replace(s, ">(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}(\r\n){0,10} {0,20}(\r\n){0,10} {0,20}<", "><", RegexOptions.Compiled); 
                s = Regex.Replace(s, ";(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", ";", RegexOptions.Compiled); 
                s = Regex.Replace(s, "{(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", "{", RegexOptions.Compiled); 
                s = Regex.Replace(s, ">(\r\n){0,10}\t{0,10}<", "><", RegexOptions.Compiled); 
                s = Regex.Replace(s, ">\r{0,10}\t{0,10}<", "><", RegexOptions.Compiled); 
                //Получивщуюся строку преобразовываем обратно в byte 
                byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s); 
                //Записываем ее в Response 
                _HTML.Write(outdata, 0, outdata.Length); 
            }
  

А также конструктор класса:

	   public HTMLClearer(System.IO.Stream HTML) 
                { _HTML = HTML; }
  

Для демонстрации примера использования HTTP Module и обработчика содержимого объекта HTTP Response создадим проект Class Library и назовем его - HTMLClearer. В этом проекте следует создать файл HTMLClearer.cs, содержащей следующий текст:

	    using System; 
        using System.Collections.Generic; 
        using System.Text; 
        using System.Web; 
        using System.Text.RegularExpressions; 
        namespace HTMLClearer 
        { 
            public class HTMLClearer : System.IO.Stream 
            { 
                System.IO.Stream _HTML; 
                public HTMLClearer(System.IO.Stream HTML) 
                { _HTML = HTML; } 
                #region Стандартные методы и свойства 
                public override bool CanRead 
                { get { return false; } } 
                public override bool CanSeek 
                { get { return false; } } 
                public override bool CanWrite 
                { get { return true; } } 
                public override long Length 
                { get { return _HTML.Length; } } 
                public override long Position 
                { 
                    get { return _HTML.Position ; } 
                    set { _HTML.Position  = value; } 
                } 
                public override long Seek(long offset, System.IO.SeekOrigin origin) 
                { return _HTML.Seek(offset, origin); } 
                public override void SetLength(long value) 
                { _HTML.SetLength(value); } 
                public override void Flush() 
                { _HTML.Flush(); } 
                public override int Read(byte[] buffer, int offset, int count) 
                { return _HTML.Read(buffer, offset, count); } 
                #endregion 
                /// <summary> 
                /// Обрабатываем данные поступающие в Response 
                /// </summary> 
                public override void Write(byte[] buffer, int offset, int count) 
                { 
                    //Преобразовываем массив байт в строку 
                    string s = System.Text.Encoding.UTF8.GetString(buffer); 
                    //Используя регулярные выражения убираем все ненужные символы 
                    s = Regex.Replace(s, ">(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}(\r\n){0,10} {0,20}(\r\n){0,10} {0,20}<", "><", RegexOptions.Compiled); 
                    s = Regex.Replace(s, ";(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", ";", RegexOptions.Compiled); 
                    s = Regex.Replace(s, "{(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", "{", RegexOptions.Compiled); 
                    s = Regex.Replace(s, ">(\r\n){0,10}\t{0,10}<", "><", RegexOptions.Compiled); 
                    s = Regex.Replace(s, ">\r{0,10}\t{0,10}<", "><", RegexOptions.Compiled); 
                    //Получивщуюся строку преобразовываем обратно в byte 
                    byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s); 
                    //Записываем ее в Response 
                    _HTML.Write(outdata, 0, outdata.Length); 
                } 
            } 
            public class HTTPModule_Clearer : IHttpModule 
            { 
                #region IHttpModule Members 
                public void Dispose() 
                {           
                } 
                /// <summary> 
                /// Подключение обработчиков событий 
                /// </summary> 
                public void Init(HttpApplication context) 
                { 
                   //Подключаем обработчик на событие ReleaseRequestState 
                   context.ReleaseRequestState += new EventHandler(this.context_Clear); 
                   //Подключаем обработчик на событие PreSendRequestHeaders 
                   context.PreSendRequestHeaders += new EventHandler(this.context_Clear); 
                   //Два обработчика необходимы для совместимости с библиотеками сжатия HTML-документов 
                } 
                /// <summary> 
                /// Обработчик события PostRequestHandlerExecute 
                /// </summary> 
                void context_Clear(object sender, EventArgs e) 
                { 
                    HttpApplication app = (HttpApplication)sender; //Получение HTTP Application 
                    string realPath = app.Request.Path.Remove(0, app.Request.ApplicationPath.Length + 1); //Получаем имя файла который обрабатывается 
                    if (realPath == "WebResource.axd") //Проверяем не является ли он ссылкой на ресурс сборки 
                        return; 
                    if (app.Response.ContentType == "text/html" || app.Response.ContentType == "text/javascript") //Проверяем тип содержимого 
                        app.Context.Response.Filter = new HTMLClearer(app.Context.Response.Filter); //Устанавливаем фильтр обработчик 
                } 
                #endregion 
            } 
        }
  

После всех этих манипуляций компилируем проект, и получившуюся библиотеку через Add Reference подключаем к Веб-сайту.

Теперь нам необходимо подключить HTTP Module к общему потоку обработки запросов. Для этого в файле web.config необходимо сделать некоторые изменения, а именно в раздел system.web добавить ссылку на модуль:

	     <httpModules>
              <add name="HTTPModule_Clearer"  type="HTMLClearer.HTTPModule_Clearer, HTMLClearer"/> 
         </httpModules>
  

Общий вид тега <httpModules> взятый из MSDN выглядит так:

    <httpModules> 
       <add type="classname,assemblyname" name="modulename"/> 
       <remove name="modulename"/> 
       <clear/> 
    </httpModules> 
  

Подтег

Описание

<add>

Добавляет в приложение класс HttpModule.

Обратите внимание, что в случае сочетания команда-путь, идентичного уже указанному ранее (например, в файле Web.config родительской папки), второй вызов <add> переопределяет предыдущее значение.

<remove>

Удаляет из приложения класс HttpModule.

<clear>

Удаляет из приложения все сопоставления HttpModule.

При использовании данного модуля размер HTML-страничек, отправляемых пользователю, уменьшается примерно на 10%, что не может не сказаться на трафике, как пользователя, так и сервера.

P.S.

Использование HTTP Module позволяет также вносить изменения в отправляемый пользователю ответ (например, если есть необходимость добавить к странице Header или Footer).

Также, дописав метод Write, можно сохранять определенные части страницы или страницы целиком в базу данных или  в файл.




Вернуться к статьям в категории Общие вопросы программирования на ASP.NET
Вернуться к списку категорий
Перейти к форуму Общие вопросы программирования на ASP.NET
 
Apartments for Rent

Rambler's Top100
Рейтинг@Mail.ru
Идея: Dimon aka Manowar Программирование: Dimon aka Manowar Дизайн: Dan Lebedev
Хостинг от компании Parking.ru
Карта сайта