利用IIS重写规则将主网站请求转发至子应用失败的问题求助
解决方案:主站与子API共用/api路径的IIS部署问题
首先明确你的核心困境:单纯依靠IIS URL Rewrite的Rewrite动作无法实现跨应用池的请求转发——重写后的URL依然会由主站的应用池处理,不会自动流转到子应用的独立上下文。下面针对你的限制(无法使用反向代理)给出可行方案,同时补充官方推荐的ARR方案作为参考。
方案1:主站添加转发控制器(无需IIS扩展)
这个方案在主站的ASP.NET Web API中新增一个控制器,专门处理非/api/v1的/api请求,将其转发到子应用。完全在代码层面实现,不需要额外的IIS扩展。
步骤:
- 在主站项目中创建一个转发控制器:
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; } }
- 调整主站的路由优先级:确保
/api/v1的路由规则优先于这个转发控制器的规则,这样原有的API不会受到影响。
方案2:使用IIS ARR实现反向代理(官方推荐,若允许使用)
虽然你提到无法使用反向代理,但IIS的Application Request Routing (ARR) 是微软官方的扩展,本质上是IIS原生的反向代理方案,很多企业环境是允许部署的。这个方案能在IIS层面完成请求转发,无需修改代码。
步骤:
- 安装ARR和URL Rewrite扩展(可通过IIS管理器的Web平台安装)。
- 在主站的
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>
- 确保ARR已启用反向代理(在IIS管理器的服务器级别,找到ARR,启用代理功能)。
方案3:调整子应用路由前缀(仅当重写规则能触发子应用上下文时)
这个方案需要配合子应用的路由配置,让子应用的路由前缀为空,然后主站的重写规则将/api/xxx(非v1)转发到/foo/xxx。但注意:这个方案仅当IIS能识别/foo/xxx属于子应用上下文时生效,部分场景下可能依然由主站处理,所以优先级低于前两个方案。
步骤:
- 在子应用的
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();
- 主站的
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
相关产品推荐
相关产品推荐

