Главная

URL rewriting в ASP.NET для поисковой оптимизации (часть 3)


  1. Итак, IIS передает ход ISAPI Application aspnet_isapi.dll, а тот, в свою очередь, перенаправляет запрос процессу w3wp.exe (для Windows 2003) или aspnet_wp.exe (если у вас Windows XP), которые и являются движками, для выполнения ASP.NET прилолжений.

  2. Здесь картина опять повторяется. Сначала ASP.NET по очереди вызывает все модули (HttpModules), зарегистрированные для web-приложения. Для этого просматриваются секции <httpModules> всех конфигурационных файлов, начиная от корневого machine.config и заканчивая web.config файлом, ближе всех расположенным к вызываемой странице. Именно таким образом вызываются системные модули типа Session (поддерживающий понятие "сессия") или FormsAuthentication (выполняющий аутентификацию пользователей).

    Вот пример из корневого web.config файла, расположенного в каталоге "<windows>\Microsoft.NET\Framework\<version>\config\":

    <configuration>
      <system.web>
        <httpModules>
            <add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
            <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
           &nbsp. . .
        </httpModules>
      </system.web>
    </configuration>

  3. И, наконец-то, ASP.NET ищет тот HttpHandler, который, собственно, и обработает запрос. Для этого опять прсматриваются все конфигурационные файлы, в которых можно сопоставлять модули с запрашиваемыми типами файлов, а так же с типами запросов. Например, можно указать, что HttpHandler "MyAssembly.MyHandler" нужно вызывать, если идет обращение типа "GET" к файлам с расширением .aspx:

    <configuration>
      <system.web>
        <httpHandlers>
          <add path=".aspx" verb="GET" type="MyAssembly.MyHandler"/>
          . . .
        </httpHandlers>
      </system.web>
    </configuration>

    Если пользовательских обработчиков не найдено, в корневом web.config прописаны обработчики по умолчанию, например для .aspx страниц вызывается System.Web.DefaultHttpHandler.

  4. Стандартный ASP.NET обработчик передает управление вашей странице, унаследованной от класса Page. Сформированный страницей ответ (объект HttpResponse) передается по цепочке обратно и, в конце концов, отсылается браузеру, приславшему запрос.
Web Optimization Уф, мои поздравления тем, кто набрался терпения и таки добрался до этого места. Теперь мы знаем вполне достаточно, чтобы легко понять все остальные способы перенаправления urls.

Если вы еще помните :), мы собирались разобраться, как реализовать url rewriting своими руками. Все сводится к использованию метода HttpContext.RewritePath. При помощи параметра string filePath можно указать, какая страница нашего веб-приложения будет выполнятся на самом деле. RewritePath содержит несколько переопределенных вариантов, которые позволяют изменить такие параметры запроса как query string или path info.
Прим. Для ASP.NET, Path info - это та часть url, которая может находиться после расширения страницы до query string. Например в Url:
http://www.sport.news.ru/tennis/news.aspx/topnews?type=12&page=2
path info - "/topnews". С точки зрения поисковиков path info - это просто часть Url, так что для них Urls:
  • http://www.sport.news.ru/tennis/news.aspx/topnews
  • http://www.sport.news.ru/tennis/news.aspx/raiting
  • http://www.sport.news.ru/tennis/news.aspx/comments
являются разными страницами. Для ASP.NET это будет одна и та же страница с разными значениями свойства PathInfo в объекте HttpRequest.
Итак, что для того чтобы перенаправить один url на другой, мы должны:
  1. Создать и зарегистрировать в нашем приложении HttpModule.

  2. Добавить в этом модуле свой обработчик к событию приложения, в котором мы будем выполнять перенаправление (если вы используете Forms Authentication, лучше выбрать AuthorizeRequest, если Windows Authentication - подойдет и BeginRequest).

  3. В обработчике выполнить перенаправление Url при помощи вызова RewritePath.

  4. Разобраться с проблемой, связанная с аттрибутом "action" тега <form>. В нем сохраняется url текущей страницы, именно его вызовет браузер во время post-back. Уже догадались, что произойдет? Допустим, мы вызвали страницу http://news.ru/tennis/raiting/ и перенаправили его на raiting.aspx?section=12. Во время отработки страницы, в аттрибут "action" будет занесено именно "raiting.aspx". После того как страница отдастся браузеру и пользователь нажмет какую-нибудь кнопку, post-back пойдет именно на "raiting.aspx" (и этот url высветится в строке запроса браузера), а вовсе не http://news.ru/tennis/raiting/, как мы хотели.

    Так что нам прийдется подменять значение этого аттрибута.
Вот как это может выглядеть:

// UrlRewriterModule.cs file
public class UrlRewriterModule : IHttpModule
{
  public void Init(HttpApplication context)
  {
    context.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
  }
  public void Dispose()
  {
  }
  void OnAuthorizeRequest(object sender, EventArgs e)
  {
    HttpApplication app = (HttpApplication)sender;
    String oldUrl = app.Request.RawUrl;
    String newUrl = ...;
    HttpContext.Current.RewritePath(newUrl);
  }
}

// web.config file
<configuration>
  <system.web>
    <httpModules>
        <add name="UrlRewriter" type="MyAssembly.UrlRewriterModule"/>
       &nbsp. . .

Осталось корректно обработать аттрибут "action". Раньше, в ASP.NET 1.1, разработчикам приходилось переопределять элемент управления Form, а это значит - менять код всех страниц, заменяя на них стандартный <asp:form>. Кроме того, иногда это приводило к проблемам в Visual Studio WYSIWYG designer.

PostBack Rewriting В ASP.NET 2.0 все можно сделать проще, благодаря использованию ASP.NET 2.0 CSS Control Adapters. Эта технология позволяет связывать ваши классы с какими-то типами элементов управления. Связанные классы могут изменять html, генерируемый элементами управления в процессе рендеринга. Более подробно я описывал эту технологию в предыдущей статье "Как совместить заказной дизайн и ASP.NET web-сайты".

То есть, мы создаем control adapter для класса HtmlForm, переопределяем в нем метод Render и выполняем rendering используя собственный класс, унаследованный от HtmlTextWriter и отличающися от него только алгоритмом добавления аттрибута "action".

Чтобы упростить себе жизнь, воспользуемся одним малоизвестным трюком - если аттрибут "action" вообще не указан - браузер будет использовать для post-back url, указанный в строке запроса, что нас вполне устраивает. Итак, пишем код для form control adapter:

// HtmlFormControlAdapter.cs file
public class HtmlFormControlAdapter : ControlAdapter
{
  protected override void Render(HtmlTextWriter writer)
  {
    base.Render(new RewriteFormHtmlTextWriter(writer));
  }
}

// RewriteFormHtmlTextWriter.cs file
public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
  public RewriteFormHtmlTextWriter(HtmlTextWriter writer) : base(writer)
  {
    this.InnerWriter = writer.InnerWriter;
  }
  public RewriteFormHtmlTextWriter(System.IO.TextWriter writer) : base(writer)
  {
    this.InnerWriter = writer;
  }
  public override void WriteAttribute(string name, string value, bool fEncode)
  {
    if (name == "action")
    {
      value = String.Empty;
    }

    base.WriteAttribute(name, value, fEncode);
  }
}

Теперь осталось связать наш control adapter с элементом HtmlForm. Создаем класс Form.browser с таким вот содержимым:

<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter adapterType="MyAssembly.HtmlFormControlAdapter, MyAssembly" controlType="System.Web.UI.HtmlControls.HtmlForm" />
    </controlAdapters>
  </browser>
</browsers>

и помещаем его в служебную папку App_Browsers нашего приложения.

Вуаля! Теперь значение аттрибута "action" всегда пустое и post-back страниц при любой реализации rewriting должен работать нормально.



Комментарии

Добавить комментарий


(Отображает Gravatar)  

biuquote
  • Комментарий
  • Предпросмотр
Loading



.NET: Записки программиста
.NET Записки программистаГлавная МастерскаяМастерская ИзбранноеИзбранное За кофеЗа кофе Об автореОб авторе