MVC以前的那點事兒系列(8):UrlRouting的理解

文章內容

根據對Http Runtime和Http Pipeline的分析,咱們知道一個ASP.NET應用程序能夠有多個HttpModuel,可是隻能有一個HttpHandler,而且經過這個HttpHandler的BeginProcessRequest(或ProcessRequest)來處理並返回請求,前面的章節將到了再MapHttpHandler這個週期將會根據請求的URL來查詢對應的HttpHandler,那麼它是如何查找的呢?html

一塊兒咱們在作自定義HttpHandler的時候,須要執行URL以及擴展名匹配規則,而後查找HttpHandler的時候就是根據相應的規則來查找哪一個HttpHandler可使用。另外一方面咱們本系列教材講的MVC就是經過註冊路由(Route)來匹配到對應的Controller和Action上的,例如Global.asax裏的代碼:web

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }

可是在匹配這個以前,MVC首先要接管請求才能處理,也就是說咱們要有對應MVC的HttpHandler(後面知道它的名字叫MvcHandler)被MapRequestHandler週期的處理引擎查找到而且應用上才行,而後後面才能由 Controller/Action執行。另一方面,因爲該URL地址沒有擴展名,因此沒法進入ASP.NET的RunTime,MVC2的實現方式是:註冊通配符(*.*)映射到aspnet_ISPAI.dll,而後經過一個自定義的UrlRoutingModuel來匹配Route規則,再繼續處理,可是MVC3的時候,匹配Route規則的處理機制集成到ASP.NET4.0裏了,也就是今天咱們這篇文章所要講的主角(UrlRoutingModule)的處理機制。正則表達式

 

先來看UrlRoutingModule的源碼,無容置疑地這個類是繼承於IHttpModule,首先看一下Init方法的代碼:瀏覽器

protected virtual void Init(HttpApplication application) {

    ////////////////////////////////////////////////////////////////// 
    // Check if this module has been already addded
    if (application.Context.Items[_contextKey] != null) { 
        return; // already added to the pipeline 
    }
    application.Context.Items[_contextKey] = _contextKey; 

    // Ideally we would use the MapRequestHandler event.  However, MapRequestHandler is not available
    // in II6 or IIS7 ISAPI Mode.  Instead, we use PostResolveRequestCache, which is the event immediately
    // before MapRequestHandler.  This allows use to use one common codepath for all versions of IIS. 
    application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
}

該代碼在PostResolveRequestCache週期事件上添加了咱們須要執行的方法,用於URL匹配規則的設置,可是爲何要在這個週期點上添加事件呢?看了註釋,再結合咱們前面對Pipeline的瞭解,釋然了,要像動態註冊本身的HttpHandler,那就須要在MapRequestHandler以前進行註冊本身的規則(由於這個週期點就是作這個事情的),但因爲IIS6不支持這個事件,因此爲了能讓IIS6也能運行MVC3,因此咱們須要在這個週期以前的PostResolveRequestCache的事件點上去註冊咱們的規則,也許若是IIS6被微軟廢棄之後,就會將這個事件添加到真正的開始點MapRequestHandler上哦。緩存

 

咱們繼續來看註冊該事件的OnApplicationPostResolveRequestCache方法的代碼:服務器

public virtual void PostResolveRequestCache(HttpContextBase context) { 
    // Match the incoming URL against the route table
    RouteData routeData = RouteCollection.GetRouteData(context);

    // Do nothing if no route found 
    if (routeData == null) {
        return; 
    } 

    // If a route was found, get an IHttpHandler from the route's RouteHandler 
    IRouteHandler routeHandler = routeData.RouteHandler;
    if (routeHandler == null) {
        throw new InvalidOperationException(
            String.Format( 
                CultureInfo.CurrentUICulture,
                SR.GetString(SR.UrlRoutingModule_NoRouteHandler))); 
    } 

    // This is a special IRouteHandler that tells the routing module to stop processing 
    // routes and to let the fallback handler handle the request.
    if (routeHandler is StopRoutingHandler) {
        return;
    } 

    RequestContext requestContext = new RequestContext(context, routeData); 
 
    // Dev10 766875    Adding RouteData to HttpContext
    context.Request.RequestContext = requestContext; 

    IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
    if (httpHandler == null) {
        throw new InvalidOperationException( 
            String.Format(
                CultureInfo.CurrentUICulture, 
                SR.GetString(SR.UrlRoutingModule_NoHttpHandler), 
                routeHandler.GetType()));
    } 

    if (httpHandler is UrlAuthFailureHandler) {
        if (FormsAuthenticationModule.FormsAuthRequired) {
            UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); 
            return;
        } 
        else { 
            throw new HttpException(401, SR.GetString(SR.Assess_Denied_Description3));
        } 
    }

    // Remap IIS7 to our handler
    context.RemapHandler(httpHandler); 
}

我已經加粗了4行重要的代碼,第一行是經過傳遞HttpContext參數,從RouteCollection找到對應的靜態屬性RouteData( GetRouteData方法裏會先判斷真實文件是否存在,若是不存在纔去找RouteData),第二行而後從RouteData的屬性RouteHandler獲取一個IRouteHandler的實例,第三行是從該實例裏獲取對應的IHttpHandler實例,第4行是調用HttpContext的RemapHandler方法從新map新的handler(這行代碼的註釋雖說是remap IIS7,其實IIS6也是用了,只不過判斷該方法裏對IIS7集成模式多了一點特殊處理而已),而後能夠經過HttpContext. RemapHandlerInstance屬性來獲得這個實例。mvc

關於Route/RouteData/RouteCollection/IRouteHandler的做用主要就是定義URL匹配到指定的IHttpHandler,而後註冊進去,具體實現咱們稍後再講,如今先看一下Http Pipeline裏是如何找到這個IHttpHandler實例的,因爲IIS6和IIS7集成模式是差很少的,前面的文章咱們提到了都是最終調用到IHttpHandlerFactory的實例,而後從中獲取IHttpHandler,因此咱們這裏只分析IIS6和IIS7經典模式的實現。app

 

先來看BuildSteps裏查找HttpHandler的方法MapHandlerExecutionStep的代碼,只有幾行代碼,最重要的是:框架

context.Handler = _application.MapHttpHandler(
    context,
    request.RequestType,
    request.FilePathObject, 
    request.PhysicalPathInternal,
    false /*useAppConfig*/); 

MapHttpHandler就是咱們要查找Handler的方法了,來仔細看看代碼:asp.net

internal IHttpHandler MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, bool useAppConfig) { 
    // Don't use remap handler when HttpServerUtility.Execute called
    IHttpHandler handler = (context.ServerExecuteDepth == 0) ? context.RemapHandlerInstance : null;

    using (new ApplicationImpersonationContext()) { 
        // Use remap handler if possible
        if (handler != null){ 
            return handler; 
        }
 
        // Map new handler
        HttpHandlerAction mapping = GetHandlerMapping(context, requestType, path, useAppConfig);

        // If a page developer has removed the default mappings with <httpHandlers><clear> 
        // without replacing them then we need to give a more descriptive error than
        // a null parameter exception. 
        if (mapping == null) { 
            PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);
            PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED); 
            throw new HttpException(SR.GetString(SR.Http_handler_not_found_for_request_type, requestType));
        }

        // Get factory from the mapping 
        IHttpHandlerFactory factory = GetFactory(mapping);
 
 
        // Get factory from the mapping
        try { 
            // Check if it supports the more efficient GetHandler call that can avoid
            // a VirtualPath object creation.
            IHttpHandlerFactory2 factory2 = factory as IHttpHandlerFactory2;
 
            if (factory2 != null) {
                handler = factory2.GetHandler(context, requestType, path, pathTranslated); 
            } 
            else {
                handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated); 
            }
        }
        catch (FileNotFoundException e) {
            if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated)) 
                throw new HttpException(404, null, e);
            else 
                throw new HttpException(404, null); 
        }
        catch (DirectoryNotFoundException e) { 
            if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
                throw new HttpException(404, null, e);
            else
                throw new HttpException(404, null); 
        }
        catch (PathTooLongException e) { 
            if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated)) 
                throw new HttpException(414, null, e);
            else 
                throw new HttpException(414, null);
        }

        // Remember for recycling 
        if (_handlerRecycleList == null)
            _handlerRecycleList = new ArrayList(); 
        _handlerRecycleList.Add(new HandlerWithFactory(handler, factory)); 
    }
 
    return handler;
}

從代碼能夠看出,首先若是當前頁面使用了HttpServerUtility.Execute進行頁面內跳轉,就不使用咱們經過路由設置的HttpHandler(也就是HttpContent.RemapHandlerInstance屬性),若是沒有跳轉,就使用,而且優先級是第一的,只有當不設置任何基於Route的HttpHandler,才走剩餘的匹配規則(也就是以前ASP.NET默認的按照擴展名類匹配的,這部分和咱們關係不大就不作詳細分析了)。

 

好了,知道了UrlRouteModuel的大概機制,咱們再回頭看看如何經過Route/RouteData/RouteCollection/IRouteHandler這幾個類來實現動態註冊Route規則的,先來看Route的代碼:

[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
public class Route : RouteBase
{    
    public Route(string url, IRouteHandler routeHandler)
    {
        Url = url;
        RouteHandler = routeHandler;
    }
     
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) { 
            Url = url;
            Defaults = defaults; 
            Constraints = constraints; 
            RouteHandler = routeHandler;
        }

    //省略部分代碼
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        // Parse incoming URL (we trim off the first two chars since they're always "~/")
        string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

        RouteValueDictionary values = _parsedRoute.Match(requestPath, Defaults);

        if (values == null)
        {
            // If we got back a null value set, that means the URL did not match
            return null;
        }

        RouteData routeData = new RouteData(this, RouteHandler);

                // Validate the values
        if (!ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest)) { 
            return null; 
        }
 
        // Copy the matched values
        foreach (var value in values) {
            routeData.Values.Add(value.Key, value.Value);
        } 

        // Copy the DataTokens from the Route to the RouteData 
        if (DataTokens != null) { 
            foreach (var prop in DataTokens) {
                routeData.DataTokens[prop.Key] = prop.Value; 
            }
        }
        return routeData;
    }       
    }

Route代碼提供了一系列的構造函數重載(咱們這裏只列出了兩個),構造函數主要是傳入URL和對應的IRouteHandler實例以及約束規則(好比正則等),而後提供了一個最重要的GetRouteData方法,用於將Route自身和IRouteHandler組裝成RouteData,而後返回(中途也會驗證相應的約束條件,好比是否符合某個正則表達式),RouteData類自己沒有什麼邏輯,只是暴露了Route和RouteHandler屬性。

 

咱們再來看RouteCollection,該類保存了全部的Route規則(即URL和對應的IRouteHandler),經過靜態屬性RouteTable.Routes來獲取RouteCollection實例,經過UrlRoutingModule裏暴露的RouteCollection屬性咱們能夠驗證這一點:

public RouteCollection RouteCollection {
    get { 
        if (_routeCollection == null) { 
            _routeCollection = RouteTable.Routes;
        } 
        return _routeCollection;
    }
    set {
        _routeCollection = value; 
    }
} 

還有一個須要注意的,RouteHandler繼承的IRouteHandler的代碼:

public interface IRouteHandler
{
     IHttpHandler GetHttpHandler(RequestContext requestContext);
}

該代碼只提供了一個GetHttpHandler方法,全部實現這個接口的類須要實現這個方法,MVCHandler就是這麼實現的(下一章節咱們再細看)。

 

至此,咱們應該有一個清晰的認識了,咱們經過全局靜態屬性集合(RouteTable.Routes)去添加各類各樣的Route(但應該在HttpModule初始化週期以前),而後經過UrlRoutingModule負責註冊Route以及對應的IRouteHandler實例(IRouteHandler實例能夠經過GetHttpHandler獲取IHttpHandler),最終實現根據不一樣URL來接管不一樣的HttpHandler。

 

MVC正是利用HttpApplication建立的週期(Application_Start方法)來添加了咱們所須要的Route規則,固然在添加規則的時候帶上了MVCHandler這個重要的HttpHandler,

代碼以下:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                );
}

MapRoute方法是一個擴展方法,經過該擴展方法註冊Route是個不錯的方法,下一章節,咱們講講解MVC是如何註冊本身的MVCRouteHandler實例以及如何實現MVCHandler的調用的。

參考資料:

http://www.cnblogs.com/me-sa/archive/2009/06/01/MVCLifecycle.html

http://www.cnblogs.com/zhaoyang/archive/2011/11/16/2251200.html

 

 

 

 

 

 

 

 

 

 

 一、概要

當咱們新建一個MVC項目時,打開他的Web.Config文件能夠發現

    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 咱們知道ScriptModule 類就是管理用於 ASP.NET 中 AJAX 功能的 HTTP 模塊,在此咱們不作介紹
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> //這個UrlRoutingModule類纔是重點
    </httpModules>

這個HttpModule,攔截全部請求,對請求進行處理,最終建立和執行合適的處理請求的HttpHandler(MVC3以後,這個UrlRoutingModule集成到MVC程序集中了)。

 

  當客戶端在本地瀏覽器上輸入網址來請求我們的一個MVC程序時,服務端接收到請求.....此處省略N個字(和asp.net處理同樣).....

  HttpApplication的事件註冊,即將 UrlRoutingModule 註冊到HttpApplication的事件中

public class UrlRoutingModule : IHttpModule
{
    protected virtual void Init(HttpApplication application)
    {   //開始只是把要執行的具體方法註冊到事件中,等待事件被觸發時,在執行已被註冊的方法。
        application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); 
        application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
    }
}

  註冊完事件以後,那麼就要開始執行HttpApplication事件。

一、執行Global.asax文件中Application_Start方法。
即:在此處將一個本身定義的路由規則註冊到路由集合中。這個路由集合能夠由RouteTable.Routes得到。

 protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                "Default", // 路由名稱
                "{controller}/{action}/{id}", // 帶有參數的 URL
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數默認值
            ); //在路由表裏添加一條路由規則
        }

二、依次執行HttpApplication的事件。  

BeginRequest
AuthenticateRequest
PostAuthenticateRequest
AuthorizeRequest
PostAuthorizeRequest
ResolveRequestCache
PostResolveRequestCache 在UrlRoutingModule類中,在此事件中註冊了一個執行方法,即:OnApplicationPostResolveRequestCache
PostMapRequestHandler                                                       OnApplicationPostMapRequestHandler
AcquireRequestState
PostAcquireRequestState
PreRequesHandlerExecute
PostRequeshandlerExecute
ReleaseRequesState
PostReleaseRequestState
UpdateRequestCache
PostUpdateRequestCach
LogRequest
PostLogRequest
EndRequest
OnApplicationPostResolveRequestCache方法
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
    HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);
    this.PostResolveRequestCache(context);
}
//這裏用HttpContextWrapper類包裝當前的HttpContext,實質上也是一個請求的上下文。他可使用諸如Typemock Isolator或Rhino Mocks的Mock對象框進行模擬變得更簡單。
//並把這個包裝以後的上下文做爲PostResolveRequestCache的參數

------------------------------------------------------------------------------------------------------------------

public virtual void PostResolveRequestCache(HttpContextBase context)
{
    RouteData routeData = this.RouteCollection.GetRouteData(context);
//GetRouteData方法內部遍歷路由集合中的每一個路由對象去和上下文中指定的請求URL去匹配。如成功,就返回當前的路由對象RouteData,如不成功,返回null
//this.RouteCollection就是RouteTable.Routes,即:路由集合。

    if (routeData != null)----這裏即是判斷是否匹配成功
    {
        IRouteHandler routeHandler = routeData.RouteHandler;----//獲取一個處理當前匹配成功的路由的對象
     //這個routeHandler其實就是一個MvcRouteHandle類
     ----由於在第一句中執行的GetRouteData方法中,爲RouteData的RouteHandler屬性賦值爲MvcRouteHandler if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0])); } if (!(routeHandler is StopRoutingHandler)) { RequestContext requestContext = new RequestContext(context, routeData);//把當前的請求的信息和與當前請求匹配成功的路由信息再包裝起來。 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); //根據包裝後的請求信息,最終獲得一個MvcHandler
       ---MvcRouteHandler中只有一個方法,GetHttpHandler方法,返回MvcHandler,Mvc中處理請求的類。
       ---PageRouteHandler中也只有一個方法,GetHttpHandler方法,返回的是Page,asp.net中處理請求的類。 
MvcRouteHandler

 

          if (httpHandler == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
            }
            //RequestData類是UrlRoutingModule類中嵌套的一個私有類,把處理請求的類和當前請求的虛擬路徑
            RequestData data2 = new RequestData {
                OriginalPath = context.Request.Path,
                HttpHandler = httpHandler
            };
            context.Items[_requestDataKey] = data2;
            //把封裝的處理類MvcHandler和請求的虛擬路徑,賦值到 HttpContextWrapper類中。(這樣在用處處理類時,就須要實例化,直接取值便可)
            //HttpContextWrapper類包裝當前的HttpContext,實質上也是一個請求的上下文。
            context.RewritePath("~/UrlRouting.axd");
context.RemapHandler(httpHandler);//博客是裏這裏是這麼一句,可是我反編譯沒找到,多是版本的問題吧!
//將MvcHandler 實例 映射到管線中(一般咱們是利用web.config 進行配置的,可是MvcHandler 沒有默認無參構造函數,因此直接經過向其傳遞一個實例進行映射)
} } } 
OnApplicationPostMapRequestHandler方法
該方法作的事情很簡單,就是重寫下請求路徑,讓輸出的路徑和輸入的路徑相同,在這裏用來記憶輸入路徑的是context.Items[],從上下兩段代碼中能夠看到.
這個事件負責根據文件擴展名映射到具體的httphandle處理類,而MVC的URL信息沒有具體的文件後綴名 爲了使處理模塊可以在iis7中實現路由,則採起了這麼一種簡單的解決辦法。先把路徑指向~/UrlRouting.axd,在此事件中會設置一個UrlRouting.axd類型的Handler避免報錯,並在下一步事件中替換掉此處的Handler再把~/UrlRouting.axd這個路徑給改回來。
View Code

 

上文中獲得了一個MvcHandler類實例,MvcHandler繼承實現了IHttpAsyncHandler, IHttpHandler, IRequiresSessionState三個接口。而這三個接口若是都實現了,在MVC框架下是否是任何http請求就能夠通吃了嗎?從MSDN咱們得知,事實不是這樣的:注意,即便 MvcHandler 實現 IHttpHandler,也不能將其映射爲處理程序(例如.mvc 文件擴展名),由於該類不支持無參數構造函數。 (它惟一的構造函數須要一個 RequestContext 對象)
可是,還好,咱們還有MvcHttpHandler。

如你所知,MvcHttpHandler能夠「彌補」MvcHandler的不足,爲何這樣說呢?由於MvcHandler沒有無參的構造函數,所以即便MvcHandler實現了 IHttpHandler接口,在IIS中也不能將其映射爲某類文件擴展名的處理程序,而MvcHttpHandler就提供了不經過路由模塊的狀況下直接處理映射的處理程序。

  • MvcHttpHandler.使用此處理程序可便於實現直接處理程序映射(不經過路由模塊)。若是要將文件擴展名(如 .mvc)直接映射到一個 MVC 處理程序,此處理程序將很是有用。在內部,MvcHttpHandler 將執行 ASP.NET 路由一般執行(經過 MvcRouteHandler 和 MvcHandler)的任務。可是,它是做爲處理程序而不是做爲模塊來執行這些任務的。對全部請求啓用UrlRoutingModule 時,一般不使用此處理程序。

  • MvcHandler.此處理程序負責啓動 MVC 應用程序的 ASP.NET 管道。它從 MVC 控制器工廠接收 Controller 實例;此控制器處理請求的進一步處理。請注意,即便 MvcHandler 實現了IHttpHandler,它也不能映射爲處理程序(例如,針對 .mvc 文件擴展名),由於該類不支持無參數構造函數(而處理程序要求是無參數構造函數)。(其惟一的構造函數須要RequestContext 對象。)

 三、HttpApplication事件繼續執行

BeginRequest
AuthenticateRequest
PostAuthenticateRequest
AuthorizeRequest
PostAuthorizeRequest
ResolveRequestCache
PostResolveRequestCache 
PostMapRequestHandler                                                       
AcquireRequestState
PostAcquireRequestState
PreRequesHandlerExecute
PostRequeshandlerExecute
ReleaseRequesState
PostReleaseRequestState
UpdateRequestCache
PostUpdateRequestCach
LogRequest
PostLogRequest
EndRequest

在11-12個事件的時候拿到第7個事件的時候建立的MVCHandler對象執行他的ProcessRequest方法。

public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
    protected virtual void ProcessRequest(HttpContext httpContext)
    {
        //使用HttpContextWrapper對HttpContext進行封裝,封裝的目的是爲了解耦以得到可測試性.而後從RequestContext.RouteData中提取Controller名稱.
        HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
        this.ProcessRequest(httpContext2);
    }
    
    protected internal virtual void ProcessRequest(HttpContextBase httpContext)
    {
        IController controller;
        IControllerFactory controllerFactory;
        this.ProcessRequestInit(httpContext, out controller, out controllerFactory); //獲取到Controler實例       ----下節詳細介紹
        try
        {
                controller.Execute(this.RequestContext); //當前Controler對象的Action的建立與執行                   ----下節詳細介紹   
執行包括:加載TempData, 建立及執行Action,處理Action返回的ActionResult ,保存TempData數據。 } finally { controllerFactory.ReleaseController(controller); //釋放當前Controler對象 } } }

流程以下圖,MvcHandler實例來處理請求,他作爲處理的主幹,當完成以後,釋放當前的Controler實例,繼續執行HttpApplication事件

MvcHandler_1

 

 

 

重定向(Redirect)用於將用戶從一個URL從新路由到另外一個URL。重定向有不少種...301和302是最多見的兩種。一般針對
HTML文檔進行重定向,但一般也可能用在請求頁面中的組件(圖片,腳本等)時。實現重定向可能有不少不一樣的緣由,包
括網站從新設計、跟蹤流量、記錄廣告點擊和建議記憶的URL等。

重定向的類型:

300 Multiple Choices :可選重定向,表示客戶請求的資源已經被轉向到另外的地址了,可是沒有說明是不是永久重定向
仍是臨時重定向。

301 Moved Permancently :永久重定向,同上,可是這個狀態會告知客戶請求的資源已經永久性的存在在新的重定向的
URL上。

302 Moved Temporarily : 臨時重定向,在HTTP1.1中狀態描述是Found,這個和300同樣,可是說明請求的資源臨時被轉
移到新的URL上,在之後可能會再次變更或者此URL會正常請求客戶的鏈接。

303 See Other : 相似於301/302,不一樣之處在於,若是原來的請求是POST,Location頭指定的重定向目標文檔應該經過
GET提取(HTTP 1.1新)。

304 Not Modified : 並不真的是重定向 - 它用來響應條件GET請求,避免下載已經存在於瀏覽器緩存中的數據。

305 Use Proxy : 客戶請求的文檔應該經過Location頭所指明的代理服務器提取(HTTP 1.1新)。

306 (廢棄,不在使用)

307 Temporary Redirect : 和302(Found)相同。許多瀏覽器會錯誤地響應302應答進行重定向,即便原來的請求是POST
,即便它實際上只能在POST請求的應答是303時 才能重定向。因爲這個緣由,HTTP 1.1新增了307,以便更加清除地區分幾
個狀態代碼:當出現303應答時,瀏覽器能夠跟隨重定向的GET和POST請求;若是是307應答,則瀏覽器只 能跟隨對GET請求
的重定向。(HTTP 1.1新) 

由於常見的重定向爲301和302,因此下面重點說說這兩種重定向對於搜索引擎的優化和實現方法。


對於搜索引擎的優化:

一、首先來講下301:301是永久性的,適用於網站域名或者網頁存儲目錄永久性的更改的狀況,這種永久性的重定向對於搜
索引擎無疑是比較友好的。
在搜索優化之中,301重定向每每還用於實現URL靜態化。

二、再來講下302:302區別於301的永久性,它(302重定向)屬於暫時性的轉移,這種臨時性的重定向適用於臨時更換域名
或者目錄名稱等狀況。
這種重定向由於是臨時性質的,因此對搜索引擎的友好程度就不如301那麼友好,請你們使用的時候還需慎重。

實現方法:

由於302可能會有URL規範化問題,其方法都是經常使用的做弊手法,如上所說對搜索引擎不是很友好,因此下面會以301爲例。

首先說下301重定向的必要性:

當網頁A用301重定向轉到網頁B時,搜索引擎能夠確定網頁A永久的改變位置,或者說實際上不存在了,搜索引擎就會把網
頁B看成惟一有效目標。好處是:

第1、沒有網址規範化問題 

第2、網頁A的PR網頁級別會傳到網頁B 

第3、收錄不會由於域名更換沒有

其次301在各類環境下的實現:

一、IIS下301設置
Internet信息服務管理器 -> 虛擬目錄 -> 重定向到URL,輸入須要轉向的目標URL,並選擇"資源的永久重定向"。

二、ASP下的301重定向代碼
<%@ Language=VBScript %> 
<% Response.Status="301 Moved Permanently" Response.AddHeader "Location", "http://www.newurl.com" %>

三、ASP.Net下的301重定向代碼
<script runat="server"> 
private void Page_Load(object sender, System.EventArgs e) 

  Response.Status = "301 Moved Permanently"; Response.AddHeader    
  ("Location","http://www.newurl.com"); 

</script>

四、PHP下的301重定向代碼
header("HTTP/1.1 301 Moved Permanently"); 
header("Location: http://www.newurl.com"); exit();

五、CGI Perl下的301重定向代碼
$q = new CGI; print $q->redirect("http://www.newurl.com/");

六、JSP下的301重定向代碼
<% 
response.setStatus(301); 
response.setHeader( "Location", "http://www.newurl.com/" ); response.setHeader( "Connection", "close" ); %>注:重定向會使你的頁面變慢。

相關文章
相關標籤/搜索