ASP.NET MVC 5站点如何将旧子域名请求完整重定向至新子域名?
解决IIS上ASP.NET MVC5应用子域名重定向保留请求体的问题
问题根源
你用的IIS httpRedirect模块默认返回302临时重定向,对于POST、PUT这类带请求体的HTTP方法,浏览器会自动将请求转为GET,直接导致请求体丢失——这也是Web API请求失效的核心原因。
解决方案
方案一:用IIS URL Rewrite+ARR做反向代理(推荐)
这种方式是服务器端直接转发请求到新域名,完全不经过客户端重定向,请求体、请求头、凭证都能完整保留,适合过渡阶段或不需要客户端地址栏更新的场景。
- 先安装IIS官方扩展:URL Rewrite和Application Request Routing (ARR)。
- 在
web.config的<system.webServer>节点下添加以下配置:
<rewrite> <rules> <rule name="Proxy to new subdomain" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTP_HOST}" pattern="^old\.example\.com$" /> </conditions> <action type="Rewrite" url="https://new.example.com/{R:1}" /> </rule> </rules> <outboundRules> <!-- 修正新域名返回的跳转地址,避免客户端直接跳去新域名(不需要可删除) --> <rule name="Fix Location Header" preCondition="Response is Redirect"> <match serverVariable="RESPONSE_Location" pattern="^https://new\.example\.com/(.*)" /> <action type="Rewrite" value="https://old.example.com/{R:1}" /> </rule> <preConditions> <preCondition name="Response is Redirect"> <add input="{RESPONSE_STATUS}" pattern="3\d\d" /> </preCondition> </preConditions> </outboundRules> </rewrite>
- 入站规则:把所有
old.example.com的请求转发到new.example.com,相当于反向代理,所有请求数据完整传递。 - 出站规则:如果新域名返回重定向(比如301/302),自动把地址换回
old.example.com,保持客户端地址栏不变;如果希望用户最终切换到新域名,直接删除这部分配置即可。
方案二:在ASP.NET应用内手动处理重定向(需更新客户端地址栏)
如果必须让用户地址栏切换到new.example.com,就得针对HTTP方法区分处理:GET请求用普通重定向,带请求体的方法用307/308重定向(这两个状态码会让浏览器保留原请求方法和请求体)。
方式1:全局过滤器(覆盖MVC和Web API)
创建两个过滤器分别处理MVC和Web API请求:
using System; using System.Web; using System.Web.Mvc; using System.Web.Http.Filters; using System.Net; // MVC 请求过滤器 public class DomainRedirectFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var request = filterContext.HttpContext.Request; if (request.Url.Host.Equals("old.example.com", StringComparison.OrdinalIgnoreCase)) { var newUrl = new UriBuilder(request.Url) { Host = "new.example.com" }.ToString(); if (request.HttpMethod == "GET") { // GET请求用301永久重定向 filterContext.Result = new RedirectResult(newUrl, permanent: true); } else { // 非GET请求用307临时重定向,保留请求方法和体 filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.TemporaryRedirect; filterContext.HttpContext.Response.RedirectLocation = newUrl; filterContext.Result = new EmptyResult(); } } base.OnActionExecuting(filterContext); } } // Web API 请求过滤器 public class ApiDomainRedirectFilter : ActionFilterAttribute { public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { var request = actionContext.Request; if (request.RequestUri.Host.Equals("old.example.com", StringComparison.OrdinalIgnoreCase)) { var newUri = new UriBuilder(request.RequestUri) { Host = "new.example.com" }.Uri; if (request.Method.Method == "GET") { actionContext.Response = request.CreateResponse(HttpStatusCode.MovedPermanently); actionContext.Response.Headers.Location = newUri; } else { actionContext.Response = request.CreateResponse(HttpStatusCode.TemporaryRedirect); actionContext.Response.Headers.Location = newUri; } } base.OnActionExecuting(actionContext); } }
然后在Global.asax的Application_Start方法中注册过滤器:
protected void Application_Start() { // 注册MVC过滤器 GlobalFilters.Filters.Add(new DomainRedirectFilter()); // 注册Web API过滤器 GlobalConfiguration.Configuration.Filters.Add(new ApiDomainRedirectFilter()); // 其他初始化代码... }
方式2:HttpModule(更底层,覆盖所有请求)
如果需要拦截所有请求(包括静态资源),可以用HttpModule:
using System; using System.Web; using System.Net; public class DomainRedirectModule : IHttpModule { public void Init(HttpApplication context) { context.BeginRequest += Context_BeginRequest; } private void Context_BeginRequest(object sender, EventArgs e) { var app = (HttpApplication)sender; var request = app.Context.Request; if (request.Url.Host.Equals("old.example.com", StringComparison.OrdinalIgnoreCase)) { var newUrl = new UriBuilder(request.Url) { Host = "new.example.com" }.ToString(); if (request.HttpMethod == "GET") { app.Context.Response.RedirectPermanent(newUrl); } else { app.Context.Response.StatusCode = (int)HttpStatusCode.TemporaryRedirect; app.Context.Response.RedirectLocation = newUrl; app.Context.Response.End(); } } } public void Dispose() { } }
在web.config的<system.webServer>节点下注册模块:
<modules> <add name="DomainRedirectModule" type="你的命名空间.DomainRedirectModule" /> </modules>
注意事项
- 307/308重定向需要客户端支持,现代浏览器都兼容,但老旧客户端可能有问题,这种情况优先用方案一的反向代理。
- 如果要做永久重定向,把307换成308(
HttpStatusCode.PermanentRedirect)。 - 反向代理方案需要在IIS管理器的"Application Request Routing"中开启"Enable Proxy"。
内容的提问来源于stack exchange,提问作者Can
相关产品推荐
相关产品推荐

