1

我正在嘗試使用類似於Handling legacy url's for any level in MVC的自定義路由(從RouteBase派生的類)編寫301重定向方案。我使用反射器在RedirectPermanent()方法中窺探了HttpResponse類,並注意到代碼都設置了狀態並輸出了一個簡單的HTML頁面。創建自定義301重定向頁面

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(); 
    } 

如何我寫一個視圖響應流的輸出?

其他信息

在過去,我們有問題,301 mydomain.com重定向到www.mydomain.com,並隨後得到了很多的報告,從用戶的SSL證書是無效的。搜索引擎完成了他們的工作,但用戶有問題,直到我切換到302重定向。我實際上無法複製它,但我們得到了大量的報告,所以我們必須做些事情。

我打算讓視圖做一個元重定向以及一個JavaScript重定向,以幫助提高可靠性,但對於那些仍然以301頁爲結尾的用戶,我希望他們有賓至如歸的感覺。我們已經有了自定義的404和500頁面,爲什麼不是自定義主題的301頁面呢?

+0

哪些瀏覽器不支持301重定向? – jrummell 2013-03-05 21:26:32

+0

@ jrummell:我知道很多插件(包括tinyurl的發展等等)停止重定向。雖然瀏覽器支持它,但用戶選擇退出是出於安全原因。 – 2013-03-05 21:27:30

+0

這是否應該保護用戶免受網絡釣魚? – jrummell 2013-03-05 21:30:24

回答

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以獲得更全面的解決方案。

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(); 
} 

這將在HomeController呈現SomeAction的響應。

+0

這看起來很有前途。正如您在上面的方法簽名中看到的那樣,它接受HttpContextBase作爲參數。但是,我很好奇,如果請求上下文調用將再次擊中路由器(請記住,這個重定向代碼本身將在路由器中)。 – NightOwl888 2013-03-05 22:31:09

+0

我不太確定,嘗試它會爲您提供一個明確的答案。 – 2013-03-05 22:31:52

+0

沒有快樂。我得到一個「System.Threading.LockRecursionException:在此模式下不允許遞歸讀取鎖定採集。」當試圖解決佈局頁面上的一些鏈接時。它從MVC框架的RouteCollectionExtensions.FilterRouteCollectionByArea()方法中引發,該方法由ActionLink()調用。 – NightOwl888 2013-03-06 01:16:20