Refit 原理解析:从初识到实践
在现代的分布式系统和微服务架构中,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 可以帮助开发者:
- 1. 减少样板代码:不需要手动创建
HttpClient、构建请求、解析响应。 - 2. 提高代码可读性:通过接口定义 API,代码更加清晰和易于理解。
- 3. 增强类型安全:编译器会检查接口定义和返回值类型,减少运行时错误。
- 4. 支持异步操作:所有方法都支持
async/await,适合现代异步编程模式。 - 5. 灵活的配置:支持自定义序列化、添加请求头、处理错误等。
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 适用于以下场景:
- 1. 调用 RESTful API:
- • 当你需要与外部服务(如第三方 API)进行通信时,Refit 可以简化 HTTP 请求的构建和解析。
- 2. 微服务架构:
- • 在微服务架构中,服务之间通常通过 HTTP 进行通信。Refit 可以帮助你快速创建类型安全的客户端,减少手动编写 HTTP 请求代码的工作量。
- 3. 移动应用和后端通信:
- • 在移动应用中,Refit 可以用于与后端服务进行通信,简化网络请求的逻辑。
- 4. 快速开发:
- • 当你需要快速测试或集成一个 API 时,Refit 可以让你在几分钟内完成 API 调用代码的编写。
- 5. 需要强类型支持的场景:
- • 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 都是一个非常实用的工具。

Refit 原理解析:从初识到实践的更多相关文章
- Tengine HTTPS原理解析、实践与调试【转】
本文邀请阿里云CDN HTTPS技术专家金九,分享Tengine的一些HTTPS实践经验.内容主要有四个方面:HTTPS趋势.HTTPS基础.HTTPS实践.HTTPS调试. 一.HTTPS趋势 这一 ...
- vue.js响应式原理解析与实现
vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...
- tomcat原理解析(一):一个简单的实现
tomcat原理解析(一):一个简单的实现 https://blog.csdn.net/qiangcai/article/details/60583330 2017年03月07日 09:54:27 逆 ...
- Spring Boot干货系列:(三)启动原理解析
Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说 ...
- 基于OpenCV进行图像拼接原理解析和编码实现(提纲 代码和具体内容在课件中)
一.背景 1.1概念定义 我们这里想要实现的图像拼接,既不是如题图1和2这样的"图片艺术拼接",也不是如图3这样的"显示拼接",而是实现类似"BaiD ...
- APPcrawler基础原理解析及使用
一.背景 一年前,我们一直在用monkey进行Android 的稳定性测试 ,主要目的就是为了测试app 是否会产生Crash,是否会有ANR,页面错误等问题,在monkey测试过程中,实现了脱离Ca ...
- Spring Boot启动原理解析
Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...
- 第16 章 : 深入理解 etcd:基于原理解析
深入理解 etcd:基于原理解析 本文将主要分享以下三方面的内容: 第一部分,会为大家介绍 etcd 项目发展的整个历程,从诞生至今 etcd 经历的那些重要的时刻: 第二部分,会为大家介绍 etcd ...
- [原][Docker]特性与原理解析
Docker特性与原理解析 文章假设你已经熟悉了Docker的基本命令和基本知识 首先看看Docker提供了哪些特性: 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上, ...
- 【算法】(查找你附近的人) GeoHash核心原理解析及代码实现
本文地址 原文地址 分享提纲: 0. 引子 1. 感性认识GeoHash 2. GeoHash算法的步骤 3. GeoHash Base32编码长度与精度 4. GeoHash算法 5. 使用注意点( ...
随机推荐
- ABS函数:C语言与Excel中的绝对值计算
ABS函数:C语言与Excel中的绝对值计算 ABS函数在不同的编程和计算环境中有着相似但又有所区别的用途.在本文中,我们将重点探讨ABS函数在C语言中的应用,同时也会结合Excel中的ABS函数进行 ...
- TokenService
https://github.com/ng-alain/delon/blob/master/packages/auth/src/token/token.service.ts set(data: ITo ...
- GraphQL Part IV: 浏览器内的 IDE
只是一个使用,这里不做介绍了.
- 共建共荣金融生态!金融级数字底座“源启”与GoldenDB数据库完成互认证
近日,中电金信金融级数字底座"源启"顺利与金篆信科GoldenDB分布式数据库完成互认证.GoldenDB数据库安全稳定运行在"源启"之上,整体性能表现卓越,进 ...
- 【MyBatis】学习笔记12:通过级联属性赋值解决多对一的映射关系
[Mybatis]学习笔记01:连接数据库,实现增删改 [Mybatis]学习笔记02:实现简单的查 [MyBatis]学习笔记03:配置文件进一步解读(非常重要) [MyBatis]学习笔记04:配 ...
- 实现一个分布式调用(OkHttp+SpringBoot)
很多情况,trace是分布在不同的应用中的,最常用的远程调用方式就是Http. 在这种情况下,我们通常通过增加额外的Http Header传递Trace信息,然后将其组织起来. 本部分通过构建一个目前 ...
- 聊一聊 C#线程池 的线程动态注入 (中)
一:背景 1. 讲故事 上一篇我们用 Thread.Sleep 的方式演示了线程池饥饿场景下的动态线程注入,可以观察到大概 1s 产生 1~2 个新线程,很显然这样的增长速度扛不住上游请求对线程池的D ...
- Qt编写物联网管理平台47-通用数据库设置
一.前言 为了做这个通用的数据库组件,专门安装了虚拟机来安装各种版本的不同类型的数据库做测试,包括编译对应的数据库插件,我一直坚信的是一切从实际出发+有实际采用发言权,包括不同Qt版本编译mysql. ...
- Qt开发经验小技巧151-155
当Qt中编译资源文件太大时,效率很低,或者需要修改资源文件中的文件比如图片.样式表等,需要重新编译可执行文件,这样很不友好,当然Qt都给我们考虑好了策略,此时可以将资源文件转化为二进制的rcc文件,这 ...
- Web端IM聊天消息该不该用浏览器本地存储?一文即懂!
本文由转转技术团队刘筱雨分享,原题"一文读懂浏览器本地存储:Web Storage",下文进行了排版和内容优化. 1.引言 鉴于目前浏览器技术的进步(主要是HTML5的普及),在W ...