c#如何使用Refit调用API?Refit快速上手实战教程

来源:站长工具作者:赵景明头衔:网络博主
导读:本期聚焦于赵景明创作的《c#如何使用Refit调用API?Refit快速上手实战教程》,敬请观看详情。在C#项目里调用REST API,还在手写HttpClient拼接URL和处理响应吗?Refit这款开源库可以把接口定义变成C#接口,通过特性声明式描述请求方式、路径和参数,运行时自动生成实现,写法类似前端axios。本文从安装配置讲起,覆盖GET、POST、文件上传、动态Header、动态BaseAddress等常见场景,并演示如何与依赖注入、Polly重试策略结合,处理JSON序列化和错误码,最后对比手写HttpClient的优缺点,给出适用建议,帮你快速在项目中落地这个类型安全的REST客户端库。

Refit 是 .NET 平台上一个非常流行的声明式 REST 客户端库,受到 Square 公司的 Retrofit 启发。它的核心思路是:你只需要定义一个 C# 接口,用特性标注每个方法对应的 HTTP 方法和路由,Refit 就会在运行时帮你生成具体的实现代码。相比手动使用 HttpClient 拼接请求地址、序列化参数、解析响应,Refit 让 API 调用代码变得简洁且类型安全。这篇文章带你从零开始掌握 Refit 的使用方法。

c#如何使用Refit调用API?Refit快速上手实战教程

一、Refit 的安装与第一个请求

1. 安装 NuGet 包

在 Visual Studio 的 NuGet 包管理器中搜索 Refit,或者直接在包管理器控制台执行安装命令:

Install-Package Refit
// 或者使用 dotnet CLI
// dotnet add package Refit</code>

Refit 本身依赖 System.Text.Json 作为默认序列化器,如果你习惯用 Newtonsoft.Json,可以额外安装 Refit.Newtonsoft.Json 包,两者可以并存使用。

2. 定义接口并发起请求

假设我们要调用一个用户管理接口,先定义模型类和接口:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

public interface IUserApi
{
    // GET /api/users/{id}
    [Get("/api/users/{id}")]
    Task<User> GetUserAsync(int id);

    // GET /api/users?page=1&pageSize=20
    [Get("/api/users")]
    Task<List<User>> GetUsersAsync([Query] int page, [Query] int pageSize);
}

注意接口中的泛型 Task<T>,Refit 会自动把响应的 JSON 反序列化为对应类型。路径中的占位符 {id} 会与方法参数自动匹配,参数名必须一致。

接下来生成客户端实例并发起调用:

var api = RestService.For<IUserApi>("https://api.ipipp.com");
var user = await api.GetUserAsync(1);
Console.WriteLine($"用户名:{user.Name}");

三行代码就完成了一次完整的 GET 请求,不需要手动处理 HttpResponseMessage,也不需要自己写反序列化逻辑,这就是 Refit 最大的魅力。

二、常见的请求场景

1. POST 提交与 PUT 更新

提交数据时使用 [Post][Put] 特性,复杂对象默认会以 JSON 形式放入请求体:

public interface IUserApi
{
    [Post("/api/users")]
    Task<User> CreateUserAsync([Body] User user);

    [Put("/api/users/{id}")]
    Task<User> UpdateUserAsync(int id, [Body] User user);

    [Delete("/api/users/{id}")]
    Task DeleteUserAsync(int id);
}

[Body] 特性标记的参数会被序列化为请求体,默认使用 JSON 格式。如果服务端要求表单提交,可以写成 [Body(BodySerializationMethod.UrlEncoded)],Refit 会把对象转成 application/x-www-form-urlencoded 格式。

2. 动态 Header 与鉴权 Token

很多 API 需要 Authorization 头携带 Token。固定头部可以直接标在方法上,动态头部则用参数传入:

public interface IUserApi
{
    [Get("/api/users/me")]
    [Headers("Accept: application/json")]
    Task<User> GetCurrentUserAsync([Header("Authorization")] string token);
}

// 调用时动态传入
var user = await api.GetCurrentUserAsync("Bearer eyJhbGciOi...");

也可以把 [Headers] 标在整个接口上,这样所有方法都会携带该头部,适合设置统一的 API 版本号或租户标识。

3. 文件上传与流式下载

上传文件时使用 StreamPartByteArrayPart,Refit 会自动以 multipart/form-data 形式发送:

public interface IFileApi
{
    [Post("/api/files/upload")]
    Task UploadFileAsync([AliasAs("file")] StreamPart stream);
}

// 调用
using var fileStream = File.OpenRead(@"C:\data\report.pdf");
var part = new StreamPart(fileStream, "report.pdf", "application/pdf");
await fileApi.UploadFileAsync(part);

下载文件时,把返回类型声明为 StreamHttpContent 即可获得原始流,适合处理大文件或非 JSON 响应。

三、在 ASP.NET Core 中与依赖注入集成

1. 注册 Refit 客户端

实际项目中很少直接用 RestService.For,更推荐的做法是通过 HttpClientFactory 集成,这样能享受连接池管理和生命周期控制:

builder.Services
    .AddRefitClient<IUserApi>()
    .ConfigureHttpClient(c =>
    {
        c.BaseAddress = new Uri("https://api.ipipp.com");
        c.Timeout = TimeSpan.FromSeconds(30);
    });

注册之后,在控制器或服务中直接通过构造函数注入 IUserApi 即可使用,整个调用链都是接口化的,方便单元测试时替换成 Mock。

2. 结合 Polly 实现重试与熔断

网络请求难免出现瞬时故障,可以借助 Microsoft.Extensions.Http.Polly 做重试策略:

builder.Services
    .AddRefitClient<IUserApi>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.ipipp.com"))
    .AddPolicyHandler(
        HttpPolicyExtensions
            .HandleTransientHttpError()
            .WaitAndRetryAsync(3, retry => TimeSpan.FromSeconds(Math.Pow(2, retry))));

这段配置实现了指数退避重试:第一次失败等 2 秒,第二次等 4 秒,第三次等 8 秒,最多重试三次。对于关键的支付、订单类接口,还可以追加熔断策略,避免故障扩散。

四、错误处理与高级用法

1. 捕获 ApiException 获取错误信息

当服务端返回非成功状态码时,Refit 会抛出 ApiException,其中包含状态码和原始响应内容:

try
{
    var user = await api.GetUserAsync(999);
}
catch (ApiException ex)
{
    var statusCode = ex.StatusCode;        // 例如 HttpStatusCode.NotFound
    var errorContent = ex.Content;         // 服务端返回的错误正文
    Console.WriteLine($"请求失败:{statusCode},{errorContent}");
}

对于验证类接口,服务端往往在错误响应中返回结构化的错误描述,可以把 ex.Content 手动反序列化成错误模型,给用户展示更友好的提示。

2. 动态 BaseAddress 与多环境切换

有些场景需要在运行时决定请求地址,比如多租户系统每个租户有自己的域名。Refit 提供了每次请求设置地址的能力:

public interface ITenantApi
{
    [Get("/api/info")]
    Task<TenantInfo> GetInfoAsync([Host] string host, string tenantId);
}

使用 [Host] 特性后,每次调用可以传入不同的主机地址,配合配置中心可以轻松实现多环境、多租户的切换,不需要为每个地址重复注册一套客户端。

3. 自定义序列化行为

默认的 System.Text.Json 采用驼峰命名策略,如果服务端要求下划线命名或日期格式,可以通过 RefitSettings 定制:

var settings = new RefitSettings
{
    ContentSerializer = new SystemTextJsonContentSerializer(
        new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        })
};
var api = RestService.For<IUserApi>("https://api.ipipp.com", settings);

与依赖注入配合时,使用 AddRefitClient<IUserApi>(settings) 的重载传入即可,全局生效。

五、Refit 的优缺点与选型建议

Refit 的优势非常明显:接口即文档,调用代码可读性高;强类型约束让参数和返回值在编译期就能发现问题;与 HttpClientFactory、Polly、Mock 测试框架无缝集成。特别是接口定义文件可以单独抽成一个类库项目,多个项目共享同一份 API 定义,前后端协作时甚至可以根据 OpenAPI 规范自动生成 Refit 接口,进一步减少手写工作量。

它的局限性也需要了解:反射生成的代理在极高性能场景下比手写 HttpRequestMessage 略慢,不过绝大多数业务系统感知不到;接口定义要求和服务端路由严格对齐,服务端接口变更时需要同步修改接口文件;对于需要精细控制请求头顺序、自定义传输层的场景,Refit 的抽象层反而会碍事,这时直接用 HttpClient 更合适。

总体来说,如果你的项目需要频繁调用第三方 REST API,或者微服务之间通信想统一封装,Refit 都是值得引入的选择。从定义第一个接口到集成依赖注入和重试策略,整个过程通常不超过半小时就能跑通,学习成本远低于它带来的代码整洁度收益。建议新项目直接采用 Refit 管理所有出站 HTTP 请求,老项目则可以在新增模块中逐步试点,验证稳定后再全面推广。

RefitC#调用APIREST客户端修改时间:2026-09-07 13:48:48

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260907/52239.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。