1

我正在尝试使用自定义路由(派生自 RouteBase 的类)编写 301 重定向方案,类似于为MVC 中的任何级别处理旧版 url。我正在使用反射器查看 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 页面呢?

4

2 回答 2

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 重定向到要启动的视图 - 浏览器很可能会遵循其中一个.

另请参阅此答案以获得更全面的解决方案。

于 2013-03-06T01:53:26.337 回答
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

于 2013-03-05T22:23:44.557 回答