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

利用IIS重写规则将主网站请求转发至子应用失败的问题求助

解决方案:主站与子API共用/api路径的IIS部署问题

首先明确你的核心困境:单纯依靠IIS URL Rewrite的Rewrite动作无法实现跨应用池的请求转发——重写后的URL依然会由主站的应用池处理,不会自动流转到子应用的独立上下文。下面针对你的限制(无法使用反向代理)给出可行方案,同时补充官方推荐的ARR方案作为参考。

方案1:主站添加转发控制器(无需IIS扩展)

这个方案在主站的ASP.NET Web API中新增一个控制器,专门处理非/api/v1的/api请求,将其转发到子应用。完全在代码层面实现,不需要额外的IIS扩展。

步骤:

  1. 在主站项目中创建一个转发控制器:
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;

public class ApiForwardController : ApiController
{
    // 初始化HttpClient,指向子应用的根地址
    private static readonly HttpClient _httpClient = new HttpClient
    {
        BaseAddress = new Uri("http://localhost/foo/") // 替换为你的子应用实际地址
    };

    // 匹配所有/api下非v1的请求
    [Route("api/{*path}")]
    public async Task<HttpResponseMessage> ForwardRequest(string path)
    {
        // 确保/api/v1的请求仍由主站处理,直接返回404让主站的路由接管
        if (Request.RequestUri.PathAndQuery.StartsWith("/api/v1"))
        {
            return new HttpResponseMessage(System.Net.HttpStatusCode.NotFound);
        }

        // 构建转发到子应用的请求
        var forwardRequest = new HttpRequestMessage
        {
            Method = new HttpMethod(Request.Method.Method),
            RequestUri = new Uri(_httpClient.BaseAddress, path)
        };

        // 复制原请求的所有请求头
        foreach (var header in Request.Headers)
        {
            forwardRequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
        }

        // 复制请求内容(如果有)
        if (Request.Content != null)
        {
            var contentBytes = await Request.Content.ReadAsByteArrayAsync();
            forwardRequest.Content = new ByteArrayContent(contentBytes);
            foreach (var header in Request.Content.Headers)
            {
                forwardRequest.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }
        }

        // 发送请求并返回子应用的响应
        var response = await _httpClient.SendAsync(forwardRequest);
        return response;
    }
}
  1. 调整主站的路由优先级:确保/api/v1的路由规则优先于这个转发控制器的规则,这样原有的API不会受到影响。

方案2:使用IIS ARR实现反向代理(官方推荐,若允许使用)

虽然你提到无法使用反向代理,但IIS的Application Request Routing (ARR) 是微软官方的扩展,本质上是IIS原生的反向代理方案,很多企业环境是允许部署的。这个方案能在IIS层面完成请求转发,无需修改代码。

步骤:

  1. 安装ARR和URL Rewrite扩展(可通过IIS管理器的Web平台安装)。
  2. 在主站的web.config中修改重写规则,使用代理动作:
<system.webServer>
  <rewrite>
    <rules>
      <rule name="Forward to New API" stopProcessing="true">
        <match url="^api\/((?!v1).*)$" />
        <!-- 转发到子应用的地址 -->
        <action type="Rewrite" url="http://localhost/foo/{R:1}" />
        <!-- 处理编码问题,避免响应乱码 -->
        <serverVariables>
          <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
          <set name="HTTP_ACCEPT_ENCODING" value="" />
        </serverVariables>
      </rule>
    </rules>
    <!-- 还原编码设置 -->
    <outboundRules>
      <rule name="Restore Accept Encoding">
        <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^$" />
        <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
      </rule>
    </outboundRules>
  </rewrite>
</system.webServer>
  1. 确保ARR已启用反向代理(在IIS管理器的服务器级别,找到ARR,启用代理功能)。

方案3:调整子应用路由前缀(仅当重写规则能触发子应用上下文时)

这个方案需要配合子应用的路由配置,让子应用的路由前缀为空,然后主站的重写规则将/api/xxx(非v1)转发到/foo/xxx。但注意:这个方案仅当IIS能识别/foo/xxx属于子应用上下文时生效,部分场景下可能依然由主站处理,所以优先级低于前两个方案。

步骤:

  1. 在子应用的Program.cs中设置路由前缀为空:
var builder = WebApplication.CreateBuilder(args);

// 移除路由前缀,让子应用直接处理根路径的请求
builder.Services.AddRouting(options => options.RoutePrefix = "");

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();
  1. 主站的web.config中修改重写规则:
<system.webServer>
  <rewrite>
    <rules>
      <rule name="Forward to Foo API" stopProcessing="true">
        <match url="^api\/((?!v1).*)$" />
        <action type="Rewrite" url="foo/{R:1}" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

内容的提问来源于stack exchange,提问作者dotarj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:16:33