ASP.NET Core反向代理:如何返回目标服务器的HTTP状态码?
解决方案
方案一:保留Flurl实现
Flurl默认会对非2xx状态码抛出FlurlHttpException,导致ASP.NET Core返回500。我们可以绕过自动异常抛出,直接获取原始响应并原样转发:
app.MapGet("test", async (string input) => { string serviceUrl = "https://my.server.here/api"; // 获取原始响应,不自动抛出异常 var flurlResponse = await serviceUrl.AppendPathSegment(input).GetAsync(); // 构建ASP.NET Core响应,复用目标服务器的状态码 var proxyResponse = Results.StatusCode((int)flurlResponse.StatusCode); // 复制目标服务器的响应头部 foreach (var header in flurlResponse.Headers) { proxyResponse.Headers.TryAdd(header.Key, header.Value.FirstOrDefault()); } foreach (var header in flurlResponse.Content.Headers) { proxyResponse.Headers.TryAdd(header.Key, header.Value.FirstOrDefault()); } // 复制响应内容和媒体类型 var content = await flurlResponse.Content.ReadAsStringAsync(); return proxyResponse.Content(content, flurlResponse.Content.Headers.ContentType?.MediaType); }) .WithName("Test") .WithOpenApi();
如果需要在成功时解析JSON,仅在错误时转发原始响应:
app.MapGet("test", async (string input) => { string serviceUrl = "https://my.server.here/api"; try { var result = await serviceUrl.AppendPathSegment(input).GetJsonAsync<MyOutputClass>(); return Results.Ok(result); } catch (FlurlHttpException ex) { var originalResponse = ex.Response; var proxyResponse = Results.StatusCode((int)originalResponse.StatusCode); // 复制所有响应头部 foreach (var header in originalResponse.Headers) { proxyResponse.Headers.TryAdd(header.Key, header.Value.FirstOrDefault()); } foreach (var header in originalResponse.Content.Headers) { proxyResponse.Headers.TryAdd(header.Key, header.Value.FirstOrDefault()); } var content = await originalResponse.Content.ReadAsStringAsync(); return proxyResponse.Content(content, originalResponse.Content.Headers.ContentType?.MediaType); } }) .WithName("Test") .WithOpenApi();
方案二:使用原生HttpClient(弃用Flurl)
直接利用ASP.NET Core注入的HttpClient,完全手动控制响应转发逻辑:
app.MapGet("test", async (string input, HttpClient httpClient) => { string serviceUrl = $"https://my.server.here/api/{input}"; var targetResponse = await httpClient.GetAsync(serviceUrl); // 构建代理响应,复用目标状态码 var proxyResponse = Results.StatusCode((int)targetResponse.StatusCode); // 复制所有响应头部 foreach (var header in targetResponse.Headers) { proxyResponse.Headers.TryAdd(header.Key, header.Value.FirstOrDefault()); } foreach (var header in targetResponse.Content.Headers) { proxyResponse.Headers.TryAdd(header.Key, header.Value.FirstOrDefault()); } // 复制响应内容 var content = await targetResponse.Content.ReadAsStringAsync(); return proxyResponse.Content(content, targetResponse.Content.Headers.ContentType?.MediaType); }) .WithName("Test") .WithOpenApi();
核心思路
- 避免使用Flurl中自动解析且抛出异常的方法(如
GetJsonAsync),改用GetAsync获取原始响应对象 - 直接复用目标服务器的状态码、响应头部和内容,无需逐个判断状态码
- 确保代理响应的媒体类型、头部信息与目标服务器完全一致
内容的提问来源于stack exchange,提问作者jason44107
相关产品推荐
相关产品推荐

