前言
在《如何使用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