在现代的分布式系统和微服务架构中,HTTP API 调用是不可或缺的一部分。为了简化 HTTP 请求的构建和解析,我们可以使用 Refit 这个强大的库。Refit 通过将 HTTP API 抽象为接口,使得调用远程服务变得非常简单和直观。
1. 初识 Refit
Refit 是一个用于 .NET 的类型安全的 REST 客户端库。它允许你通过定义一个接口来描述 HTTP API,并自动生成实现代码。Refit 的核心思想是将 HTTP API 调用抽象为接口方法,开发者只需要定义接口,Refit 会自动处理 HTTP 请求的构建、发送和响应的解析。
定义一个简单的 API 接口
public interface IUserRefitApi
{
[Get("/users/{id}")]
Task<User> GetUserAsync(int id);
}
在这个例子中,IUserRefitApi
接口描述了一个获取用户信息的 API。Refit 会根据接口定义自动生成 HTTP 请求代码。
2. Refit 的作用
Refit 的主要作用是简化 HTTP API 的调用。具体来说,Refit 可以帮助开发者:
-
- 减少样板代码 :不需要手动创建
HttpClient
、构建请求、解析响应。
- 减少样板代码 :不需要手动创建
-
- 提高代码可读性:通过接口定义 API,代码更加清晰和易于理解。
-
- 增强类型安全:编译器会检查接口定义和返回值类型,减少运行时错误。
-
- 支持异步操作 :所有方法都支持
async/await
,适合现代异步编程模式。
- 支持异步操作 :所有方法都支持
-
- 灵活的配置:支持自定义序列化、添加请求头、处理错误等。
3. Refit 的原理
Refit 的工作原理可以分为以下几个步骤:
3.1 接口解析
Refit 通过反射解析接口定义,提取出 HTTP 方法(如 [Get]
、[Post]
)、路径、参数等信息。
- • HTTP 方法 :通过注解(如
[Get]
、[Post]
)指定。 - • 路径 :注解中的路径可以包含占位符(如
{username}
),这些占位符会被方法的参数替换。 - • 参数:方法的参数可以绑定到路径、查询字符串、请求体等。
3.2 请求构建
Refit 根据接口定义构建 HTTP 请求。它会将方法的参数绑定到请求的路径、查询字符串、请求体等。
- • 路径参数:通过占位符替换。
- • 查询参数 :通过
[Query]
注解指定。 - • 请求体 :通过
[Body]
注解指定。
3.3 请求发送
Refit 使用 HttpClient
发送 HTTP 请求。它会将构建好的请求发送到指定的 API 端点。
3.4 响应解析
Refit 接收 HTTP 响应,并将其反序列化为方法的返回类型。默认情况下,Refit 使用 System.Text.Json
进行反序列化。
3.5 异常处理
如果 HTTP 请求失败(如返回 4xx 或 5xx 状态码),Refit 会抛出 ApiException
,开发者可以捕获并处理这些异常。
4. Refit 的使用场景
Refit 适用于以下场景:
-
- 调用 RESTful API :
- • 当你需要与外部服务(如第三方 API)进行通信时,Refit 可以简化 HTTP 请求的构建和解析。
-
- 微服务架构 :
- • 在微服务架构中,服务之间通常通过 HTTP 进行通信。Refit 可以帮助你快速创建类型安全的客户端,减少手动编写 HTTP 请求代码的工作量。
-
- 移动应用和后端通信 :
- • 在移动应用中,Refit 可以用于与后端服务进行通信,简化网络请求的逻辑。
-
- 快速开发 :
- • 当你需要快速测试或集成一个 API 时,Refit 可以让你在几分钟内完成 API 调用代码的编写。
-
- 需要强类型支持的场景 :
- • Refit 提供了强类型的 API 调用方式,避免了手动解析 JSON 或处理字符串的麻烦。
5.项目实践
5.1 安装 Refit
安装 Refit 的 NuGet 包:
dotnet add package Refit.HttpClientFactory
我们这里安装的是Refit.HttpClientFactory
包,Refit
和 Refit.HttpClientFactory
是 Refit 库的两个不同部分,它们的作用和使用场景有所不同。
Refit
和 Refit.HttpClientFactory
大致区别如下:
特性 | Refit 核心库 | Refit.HttpClientFactory |
---|---|---|
依赖 | 直接依赖 HttpClient |
依赖 HttpClientFactory |
生命周期管理 | 需要手动管理 HttpClient |
|
生命周期 | 由 HttpClientFactory 自动管理 |
|
依赖注入支持 | 不支持直接依赖注入 | 支持依赖注入 |
适用场景 | 简单的控制台应用或手动管理 | |
HttpClient |
ASP.NET Core 或其他依赖注入的应用 | |
配置灵活性 | 需要手动配置 HttpClient |
可以通过 HttpClientFactory 配置 |
在 ASP.NET Core 中使用 Refit,推荐使用 Refit.HttpClientFactory
,因为它与 HttpClientFactory
集成得更好,能够更灵活地配置和管理 HttpClient
。
5.2 定义 API 接口
在项目中定义一个接口来描述你要调用的外部 API。我们将使用 /users
相关的端点。
using System.Collections.Generic;
using System.Threading.Tasks;
using Refit;
public interface IUserRefitApi
{
// 获取所有用户
[Get("/users")]
Task<List<User>> GetUsersAsync();
// 获取单个用户
[Get("/users/{id}")]
Task<User> GetUserAsync(int id);
// 创建新用户
[Post("/users")]
Task<User> CreateUserAsync([Body] User user);
// 更新用户
[Put("/users/{id}")]
Task<User> UpdateUserAsync(int id, [Body] User user);
// 删除用户
[Delete("/users/{id}")]
Task DeleteUserAsync(int id);
}
5.3 注册 Refit 客户端
在 Program.cs
中注册 Refit 客户端。你可以使用 HttpClientFactory
来管理 HttpClient
的生命周期。
using Microsoft.Extensions.DependencyInjection;
using Refit;
var builder = WebApplication.CreateBuilder(args);
// 添加 Refit 客户端
builder.Services.AddRefitClient<IUserRefitApi>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://******"));
var app = builder.Build();
// 配置中间件和路由
app.MapControllers();
app.Run();
5.4 在控制器中使用 Refit 客户端
在 Web API 的控制器中注入 Refit 客户端,并调用外部 API。
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IUserRefitApi _userRefitApi;
public UsersController(IUserRefitApi userRefitApi)
{
_userRefitApi = userRefitApi;
}
// 获取所有用户
[HttpGet]
public async Task<IActionResult> GetUsers()
{
var users = await _userRefitApi.GetUsersAsync();
return Ok(users);
}
// 获取单个用户
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
var user = await _userRefitApi.GetUserAsync(id);
return Ok(user);
}
// 创建新用户
[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] User user)
{
var createdUser = await _userRefitApi.CreateUserAsync(user);
return Ok(createdUser);
}
// 更新用户
[HttpPut("{id}")]
public async Task<IActionResult> UpdateUser(int id, [FromBody] User user)
{
var updatedUser = await _userRefitApi.UpdateUserAsync(id, user);
return Ok(updatedUser);
}
// 删除用户
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteUser(int id)
{
await _userRefitApi.DeleteUserAsync(id);
return NoContent();
}
}
6. 扩展功能
6.1 添加请求头
可以通过 [Headers]
注解为接口或方法添加请求头:
[Headers("Authorization: Bearer TOKEN")]
public interface IUserRefitApi
{
[Get("/users")]
Task<List<User>> GetUsersAsync();
}
6.2 自定义序列化
可以通过 RefitSettings
自定义序列化行为:
builder.Services.AddRefitClient<IUserRefitApi>(new RefitSettings
{
ContentSerializer = new NewtonsoftJsonContentSerializer()
})
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://******"));
6.3 文件上传
Refit 支持文件上传。可以使用 [Multipart]
注解:
public interface IFileApi
{
[Multipart]
[Post("/upload")]
Task UploadFileAsync([AliasAs("file")] StreamPart file);
}
7. 总结
在 .NET Core Web API 中使用 Refit 可以极大地简化对外部 HTTP API 的调用。通过定义接口和注解,Refit 可以自动生成 HTTP 请求代码,并通过 HttpClientFactory
管理 HttpClient
的生命周期。无论是调用第三方 API 还是实现微服务通信,Refit 都是一个非常实用的工具。