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. 使用注意点( ...
随机推荐
- HttpClientManager
HttpClientManger package com.gateway.http.client; import com.fasterxml.jackson.core.type.TypeReferen ...
- jacoco代码覆盖率报告分析
一.目的 对Jacoco代码覆盖率统计维度.报告字段说明.报告详细分析描述.并为精准测试.健壮性测试提供指导. 二.Jacoco代码覆盖率统计维度 Jacoco是从代码指令(Instructions, ...
- 利用H2的自定义函数更好的支持测试
在写DAO层的单元测试时,用mock的写法意义不大,因为DAO层的测试更多的关注是Java对象的传递和生成SQL的正确性,所以需要链接真实的数据库. 但是对于单元测试,真实的数据库是很重的,还要依赖于 ...
- Qt开源作品8-通用控件移动
一.前言 在做一些项目的过程中,有一种应用场景是需要拖动设备在一个容器中,自由拖动摆放到合适的位置,然后保存对应设备的坐标位置信息,在软件启动好以后自动加载配置好的坐标位置信息,将每个设备移动到对应的 ...
- C# SynchronizationContext线程上下文简单说明
SynchronizationContext线程上下文说明SynchronizationContext在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯 那么Synchronizati ...
- Redis 源码简洁剖析 08 - epoll
select, poll, epoll 源码分析 参考链接 Redis 源码简洁剖析系列 select, poll, epoll 关于 select, poll, epoll,网络 IO 演变发展过 ...
- GIS开发的基础优化策略
GIS开发的基础优化策略 1. GIS开发 空间字段要建对,类型明确,坐标系明确. 空间索引要建立,提高查询效率. 使用空间字段要谨慎,不用的地方不要查. 地图显示尽量用切片,用WMTS. WMS能用 ...
- 解决STM32 CubeMX中配置RTC每次上电就会重置的问题
自从有了Cube MX,配置STM32的外设就变得格外简单.不过这次差点踩坑,下载完程序后RTC自动就恢复到了我设置的初始值,重启之后现象依旧. 下面就以上问题简单分析一下代码. /* RTC ini ...
- 快速定位Linux 内核驱动中GPIO冲突
#全开开kernel log echo "8" > /proc/sys/kernel/printk #打开gpiolib 动态调试 echo 'file gpiolib.c ...
- Vue + Axios 请求接口方法与传参详解
使用Vue的脚手架搭建的前端项目,通常都使用Axios封装的接口请求,项目中引入的方式不做多介绍,本文主要介绍接口调用与不同形式的传参方法. 一.Get请求: Get请求比较简单,通常就是将参数拼接到 ...