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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 14:37:03