前言
在《如何使用ASP.NET Core Web API實現短鏈接服務》中,我們使用了Redirect
方法返回跳轉狀態碼:
[HttpGet("{shortUrl}")]
public?IActionResult?GetUrl(string?shortUrl)
{var?hashids?=?new?Hashids("公眾號My?IO",?minHashLength:?6);var?id?=?hashids.Decode(shortUrl)[0];var?urlData?=?db.Get(id);return?Redirect(urlData.Url);
}
Redirect
方法會生成RedirectResult
類實例,而RedirectResult
構造函數可以傳入 2 個 bool 值:
public?RedirectResult(string?url,?bool?permanent,?bool?preserveMethod)
那么,為它們賦不同值,對跳轉狀態碼有什么影響呢?
探究
查找這 2 個參數的引用,我們最終定位到RedirectResultExecutor.cs[1]:
if?(result.PreserveMethod)
{context.HttpContext.Response.StatusCode?=?result.Permanent??StatusCodes.Status308PermanentRedirect?:?StatusCodes.Status307TemporaryRedirect;context.HttpContext.Response.Headers.Location?=?destinationUrl;
}
else
{context.HttpContext.Response.Redirect(destinationUrl,?result.Permanent);
}
PreserveMethod = true
使用 Location 標頭返回需要跳轉的 Url。
Permanent 決定狀態碼:
Permanent | 狀態碼 | 說明 |
---|---|---|
false | 307 | 臨時重定向響應狀態碼,表示請求的資源暫時地被移動到了響應的 Location 所指向的 URL 上。 |
true | 308 | 永久重定向響應狀態碼,說明請求的資源已經被永久的移動到了由 Location 指定的 URL 上 |
PreserveMethod = false
執行Response.Redirect
方法進行跳轉,內部實現如下:
public?override?void?Redirect(string?location,?bool?permanent)
{if?(permanent){HttpResponseFeature.StatusCode?=?301;}else{HttpResponseFeature.StatusCode?=?302;}Headers.Location?=?location;
}
其實和PreserveMethod = true
的邏輯是一樣的,只是返回的狀態碼不同:
Permanent | 狀態碼 | 說明 |
---|---|---|
false | 302 | 表明請求的資源被暫時的移動到了由該HTTP響應的響應頭Location 指定的 URL 上。 |
true | 301 | 表明請求的資源已經被移動到了由 Location 頭部指定的url上,是固定的不會再改變 |
綜上,ASP.NET Core 中的重定向一共包含 4 種:
狀態碼 | PreserveMethod | Permanent | 生成RedirectResult方法 |
---|---|---|---|
301 | false | true | RedirectPermanent() |
302 | false | false | Redirect() |
307 | true | false | RedirectPreserveMethod() |
308 | true | true | RedirectPermanentPreserveMethod() |
Demo
那它們之間具體有什么差別呢?
編寫如下代碼:
[HttpGet("RedirectPermanent")]
[HttpPost("RedirectPermanent")]
public?IActionResult?RedirectPermanent()
{_logger.LogInformation("RedirectPermanent");return?RedirectPermanent("MyIO");
}[HttpGet("Redirect")]
[HttpPost("Redirect")]
public?IActionResult?Redirect()
{_logger.LogInformation("Redirect");return?Redirect("MyIO");
}[HttpGet("RedirectPreserveMethod")]
[HttpPost("RedirectPreserveMethod")]
public?IActionResult?RedirectPreserveMethod()
{_logger.LogInformation("RedirectPreserveMethod");return?RedirectPreserveMethod("MyIO");
}[HttpGet("RedirectPermanentPreserveMethod")]
[HttpPost("RedirectPermanentPreserveMethod")]
public?IActionResult?RedirectPermanentPreserveMethod()
{_logger.LogInformation("RedirectPermanentPreserveMethod");return?RedirectPermanentPreserveMethod("MyIO");
}[HttpGet("MyIO")]
[HttpPost("MyIO")]
public?string?MyIO()
{return?this.Request.Method;
}
所有方法都同時支持
GET
和POST
方法所有方法都會重定向到同一個方法,顯示當前請求方法
每個 API 都請求 2 遍,可以看到:
Permanent = true 的
Get
請求只會執行一次,后續會直接請求跳轉后的地址PreserveMethod = false 的
POST
請求,跳轉后實際執行的Get
請求
結論
如果想只發生一次重定向,則應考慮使用RedirectPermanent
或者RedirectPermanentPreserveMethod
。
如果要為非 GET 請求使用重定向,則應考慮使用RedirectPreserveMethod
或者RedirectPermanentPreserveMethod
。
添加微信號【MyIO666】,邀你加入技術交流群
參考資料
[1]
RedirectResultExecutor.cs: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Infrastructure/RedirectResultExecutor.cs#L63