﻿# ASP.NET MVC 開發心得分享 (14)：實做 HTTP 301 永久轉向

最近有人問我 ASP.NET MVC 如何實做 HTTP 301 永久轉向 ([HTTP 301 Moved Permanently](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2))，因為內建的 RedirectResult 或 RedirectActionResult 或 RedirectToRouteResult 的轉向動作都是用 [HTTP 302](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3) 做轉向，但事實上這個問題與 ASP.NET MVC 無關，因為這部分的解決方法跟 ASP.NET Web Form 一模一樣。

由於 ASP.NET 核心中 [HttpResponse 類別](http://msdn.microsoft.com/zh-tw/library/system.web.httpresponse.aspx)的 [HttpResponse.Redirect 方法](http://msdn.microsoft.com/zh-tw/library/a8wa7sdt.aspx)預設就是以 HTTP 302 做轉向，ASP.NET MVC 只是繼續沿用這個方法轉向而已，即便在 ASP.NET Web Form 開發架構下要利用 HTTP 301 轉向一樣要用相同的開發技巧，只要兩行就能夠完成：

```
Response.StatusCode = 301;Response.AppendHeader("Location", "/Home/About");
```

在 ASP.NET MVC 的 Controller 裡由於轉向之後並不需要直接回應 View，所以針對 Action 的回傳值可以有兩種寫法：

1\. 使用 Implicit Action Result 將 Action 的回傳型別改成 void

```
public void Redirect1(){    Response.StatusCode = 301;    Response.AppendHeader("Location", Url.Action("About"));}
```

2\. 使用內建的 EmptyResult 回應

```
public ActionResult Redirect2(){    Response.StatusCode = 301;    Response.AppendHeader("Location", Url.Action("About"));    return new EmptyResult();}
```

當然，如上範例中對於轉向網址的產生我們一律透過 Url Helper 幫我們計算出實際要轉向的網址，這是在 ASP.NET MVC 中的標準作法，因為 ASP.NET 3.5 的 Routing 機制可以讓你輕鬆的定義千變萬化的網址格式。

> **注意**：對於這種不需要回傳 View 的情況，千萬不要利用 [Response.End()](http://msdn.microsoft.com/zh-tw/library/system.web.httpresponse.end.aspx) 中斷 ASP.NET 的執行，因為每當執行 Response.End() 方法都會引發一次 [ThreadAbortException](http://msdn.microsoft.com/zh-tw/library/system.threading.threadabortexception.aspx) 例外狀況，過於頻繁的發生例外狀況會導致系統效能降低、消耗系統資源，對於這種需要轉向而不需要回應 View 的情況，最好利用 [EmptyResult](http://msdn.microsoft.com/en-us/library/system.web.mvc.emptyresult.aspx) 來回應較為恰當。

**相關連結**

-   [HTTP/1.1: Status Code Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
-   [HTTP 301 - Wikipedia, the free encyclopedia](http://en.wikipedia.org/wiki/HTTP_301)
-   [HttpResponse.StatusCode 屬性](http://msdn.microsoft.com/zh-tw/library/system.web.httpresponse.statuscode.aspx)
-   [HttpResponse.AppendHeader 方法](http://msdn.microsoft.com/zh-tw/library/system.web.httpresponse.appendheader.aspx)
-   [HttpResponse.End 方法](http://msdn.microsoft.com/zh-tw/library/system.web.httpresponse.end.aspx)
-   Ending a Response without Response.End() Exceptions?
-   Response.End() behavior change in ASP.NET 2.0
-   Using Response.Redirect and Response.End in Try...Catch block
-   [Don’t use Response.End() with OutputCache](http://csharpfeeds.com/post/11222/Donrsquot_use_Response.End_with_OutputCache.aspx)
-   [Response.Redirect(url) ThreadAbortException Solution](http://www.c6software.com/articles/ThreadAbortException.aspx)
