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" ); %>注:重定向会使你的页面变慢。

相关文章
相关标签/搜索