You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC 5站点如何将旧子域名请求完整重定向至新子域名?

解决IIS上ASP.NET MVC5应用子域名重定向保留请求体的问题

问题根源

你用的IIS httpRedirect模块默认返回302临时重定向,对于POST、PUT这类带请求体的HTTP方法,浏览器会自动将请求转为GET,直接导致请求体丢失——这也是Web API请求失效的核心原因。

解决方案

方案一:用IIS URL Rewrite+ARR做反向代理(推荐)

这种方式是服务器端直接转发请求到新域名,完全不经过客户端重定向,请求体、请求头、凭证都能完整保留,适合过渡阶段或不需要客户端地址栏更新的场景。

  1. 先安装IIS官方扩展:URL Rewrite和Application Request Routing (ARR)。
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 23:05:04