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

如何使用Task<IResult>将HTTP请求封装为Success或Failure结果

实现方案:基于泛型Result类的API返回结果封装

核心思路是用可区分联合(Discriminated Union)风格的泛型Result类型封装成功、失败两种状态,避免空值返回和非预期异常泄露,完美适配HTTP调用的故障处理需求。


1 定义基础Result类型

首先实现泛型和非泛型两类Result结构,覆盖带返回数据、仅需操作状态两种业务场景:

// 泛型Result:带返回数据的场景
public abstract class Result<T>
{
    public bool IsSuccess { get; protected set; }
    public T? Data { get; protected set; }
    public string? ErrorMessage { get; protected set; }
    public Exception? InnerException { get; protected set; }

    // 快速构建成功结果
    public static Result<T> Success(T data) => new SuccessResult<T>(data);
    // 快速构建失败结果
    public static Result<T> Failure(string errorMessage, Exception? ex = null) 
        => new FailureResult<T>(errorMessage, ex);
}

public class SuccessResult<T> : Result<T>
{
    public SuccessResult(T data)
    {
        IsSuccess = true;
        Data = data;
        ErrorMessage = null;
        InnerException = null;
    }
}

public class FailureResult<T> : Result<T>
{
    public FailureResult(string errorMessage, Exception? ex = null)
    {
        IsSuccess = false;
        Data = default;
        ErrorMessage = errorMessage;
        InnerException = ex;
    }
}

// 非泛型Result:不需要返回数据、仅需判断操作是否成功的场景
public abstract class Result
{
    public bool IsSuccess { get; protected set; }
    public string? ErrorMessage { get; protected set; }
    public Exception? InnerException { get; protected set; }
    
    public static Result Success() => new SuccessResult();
    public static Result Failure(string errorMessage, Exception? ex = null) 
        => new FailureResult(errorMessage, ex);
}

public class SuccessResult : Result
{
    public SuccessResult()
    {
        IsSuccess = true;
        ErrorMessage = null;
        InnerException = null;
    }
}

public class FailureResult : Result
{
    public FailureResult(string errorMessage, Exception? ex = null)
    {
        IsSuccess = false;
        ErrorMessage = errorMessage;
        InnerException = ex;
    }
}

2 封装HTTP调用逻辑,返回Task<Result>

给HttpClient写扩展方法,自动处理状态码校验、响应序列化、全链路异常捕获,直接返回封装好的Result类型:

public static async Task<Result<T>> SendRequestAsync<T>(this HttpClient client, 
    HttpRequestMessage request, CancellationToken cancellationToken = default)
{
    try
    {
        using var response = await client.SendAsync(request, cancellationToken);
        // 处理HTTP错误状态码
        if (!response.IsSuccessStatusCode)
        {
            var errorContent = await response.Content.ReadAsStringAsync(cancellationToken);
            return Result<T>.Failure($"HTTP请求失败,状态码:{(int)response.StatusCode},错误详情:{errorContent}");
        }
        // 序列化返回结果
        var content = await response.Content.ReadAsStringAsync(cancellationToken);
        var data = System.Text.Json.JsonSerializer.Deserialize<T>(content);
        if (data == null)
        {
            return Result<T>.Failure("返回结果序列化失败,数据为空");
        }
        return Result<T>.Success(data);
    }
    catch (HttpRequestException ex)
    {
        return Result<T>.Failure($"HTTP网络异常:{ex.Message}", ex);
    }
    catch (TaskCanceledException ex)
    {
        return Result<T>.Failure("请求超时或被手动取消", ex);
    }
    catch (System.Text.Json.JsonException ex)
    {
        return Result<T>.Failure($"返回结果序列化异常:{ex.Message}", ex);
    }
    catch (Exception ex)
    {
        return Result<T>.Failure($"请求发生未知异常:{ex.Message}", ex);
    }
}

3 调用示例

// 构造HTTP请求
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/user/info");
var httpClient = new HttpClient();

// 调用封装后的请求方法
var result = await httpClient.SendRequestAsync<UserInfoModel>(request);

// 分支处理逻辑
if (result.IsSuccess)
{
    // 正常业务逻辑,直接使用result.Data
    Console.WriteLine($"用户昵称:{result.Data.NickName}");
}
else
{
    // 故障处理逻辑,可直接取错误信息和原始异常打日志、返回前端等
    _logger.LogError(result.InnerException, "获取用户信息失败:{ErrorMsg}", result.ErrorMessage);
}

可选优化点

  • 给Result类添加Match方法,强制调用方必须处理成功、失败两种分支,避免遗漏状态判断:
    public async Task<TOut> Match<TOut>(Func<T, Task<TOut>> onSuccess, Func<string, Exception?, Task<TOut>> onFailure)
    {
        return IsSuccess ? await onSuccess(Data!) : await onFailure(ErrorMessage!, InnerException);
    }
    
  • 可在FailureResult中扩展错误码字段,适配业务错误分类、多语言错误提示的需求
  • 可添加隐式类型转换,省略手动调用Success/Failure方法的冗余代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:18:00