创建自定义301重定向页面

时间:2013-03-05 21:24:16

标签: asp.net-mvc asp.net-mvc-4 asp.net-mvc-routing url-routing httpresponse

我正在尝试使用类似于Handling legacy url's for any level in MVC的自定义路由(源自RouteBase的类)编写301重定向方案。我正在使用反射器在RedirectPermanent()方法中窥视HttpResponse类,并注意到代码既设置状态又输出一个简单的HTML页面。

    this.StatusCode = permanent ? 0x12d : 0x12e;
    this.RedirectLocation = url;
    if (UriUtil.IsSafeScheme(url))
    {
        url = HttpUtility.HtmlAttributeEncode(url);
    }
    else
    {
        url = HttpUtility.HtmlAttributeEncode(HttpUtility.UrlEncode(url));
    }
    this.Write("<html><head><title>Object moved</title></head><body>\r\n");
    this.Write("<h2>Object moved to <a href=\"" + url + "\">here</a>.</h2>\r\n");
    this.Write("</body></html>\r\n");

这是可取的,因为根据我的经验,并非所有浏览器都配置为遵循301重定向(尽管搜索引擎会这样做)。因此,如果浏览器没有自动转到该页面,也可以为用户提供指向该页面的链接。

我想要做的是将其提升到一个新的水平 - 我想输出MVC视图的结果(以及它的主题布局页面),而不是在响应中输入硬编码的丑陋通用HTML。类似的东西:

    private void RedirectPermanent(string destinationUrl, HttpContextBase httpContext)
    {
        var response = httpContext.Response;

        response.Clear();
        response.StatusCode = 301;
        response.RedirectLocation = destinationUrl;

        // Output a Custom View Here
        response.Write(The View)

        response.End();
    }

如何将视图的输出写入响应流?

其他信息

过去,我们遇到了从mydomain.com到www.mydomain.com的301重定向问题,随后有很多用户报告SSL证书无效。搜索引擎完成了他们的工作,但用户遇到了问题,直到我切换到302重定向。我实际上无法重现它,但我们得到了大量的报告,因此必须要做些什么。

我计划让视图执行元重定向以及javascript重定向以帮助提高可靠性,但对于那些仍然在301页面结束的用户,我希望他们有宾至如归的感觉。我们已经有自定义的404页和500页,为什么不是自定义主题301页呢?

2 个答案:

答案 0 :(得分:1)

事实证明我只是过度思考问题而且解决方案比我想象的要简单得多。我真正需要做的就是使用routeData将请求推送到另一个控制器操作。让我失望的是需要附加到请求的额外301状态信息。

    private RouteData RedirectPermanent(string destinationUrl, HttpContextBase httpContext)
    {
        var response = httpContext.Response;

        response.CacheControl = "no-cache";
        response.StatusCode = 301;
        response.RedirectLocation = destinationUrl;

        var routeData = new RouteData(this, new MvcRouteHandler());
        routeData.Values["controller"] = "Home";
        routeData.Values["action"] = "Redirect301";
        routeData.Values["url"] = destinationUrl;

        return routeData;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData result = null;

        // Do stuff here...

        if (this.IsDefaultUICulture(cultureName))
        {
            var urlWithoutCulture = url.ToString().ToLowerInvariant().Replace("/" + cultureName.ToLowerInvariant(), "");

            return this.RedirectPermanent(urlWithoutCulture, httpContext);
        }

        // Get the page info here...

        if (page != null)
        {
            result = new RouteData(this, new MvcRouteHandler());

            result.Values["controller"] = page.ContentType.ToString();
            result.Values["action"] = "Index";
            result.Values["id"] = page.ContentId;
        }

        return result;

    }

我只需要返回RouteData,以便路由器处理它!

另请注意,我添加了一个CacheControl标头,以防止IE9和Firefox以无法清除的方式缓存重定向。

现在我有一个很好的页面,当浏览器无法跟踪301时,会向用户显示链接和消息,我将添加元重定向和javascript重定向到视图以启动 - 浏览器将遵循的几率其中之一。

  

另请参阅this answer了解更全面的解决方案。

答案 1 :(得分:0)

假设您可以访问HttpContextBase,这里可以将控制器操作的内容呈现给响应:

private void RedirectPermanent(string destinationUrl, HttpContextBase httpContext)
{
    var response = httpContext.Response;

    response.Clear();
    response.StatusCode = 301;
    response.RedirectLocation = destinationUrl;

    // Output a Custom View Here (HomeController/SomeAction in this example)
    var routeData = new RouteData();
    routeData.Values["controller"] = "Home";
    routeData.Values["action"] = "SomeAction";
    IController homeController = new HomeController();
    var rc = new RequestContext(new HttpContextWrapper(context), routeData);
    homeController.Execute(rc);

    response.End();
}

这会在SomeAction上将HomeController呈现给回复。