在前端开发中,网络请求是核心一环。长期以来,Axios 凭借强大的拦截器和广泛的兼容性统治了社区,而原生的 Fetch API 则因其底层的设计略显"简陋"。
如果你正在寻找一个更现代、更轻量、且完美契合浏览器标准 的解决方案,那么 ky 绝对值得你关注。
什么是 ky?
ky 是由开源大神 Sindre Sorhus(Got、Chalk 等知名库的作者)基于浏览器原生 Fetch 封装的一个极小(压缩后约 2KB)的 HTTP 客户端。它的口号是:Tiny and elegant(微小而优雅)。
为什么选择 ky 而不是 Axios 或 Fetch?
虽然 Fetch 是 Web 标准,但它在实际开发中存在几个令人头疼的问题:
- 4xx/5xx 状态码不抛错:即使后端返回 500,Fetch 依然认为请求成功。
- 需要手动处理 JSON :你得写
await res.json()。 - 缺乏超时控制 :需要配合复杂的
AbortController。
ky 巧妙地解决了这些痛点,并保持了极低的体积。
核心优势一:极其简洁的语法
在 ky 中,发送请求和解析数据可以链式调用,一气呵成:
javascript
import ky from 'ky';
// 自动处理 JSON 序列化和解析
const userInfo = await ky.get('https://api.example.com/user/1').json();
// 发送 POST 请求
await ky.post('https://api.example.com/update', {
json: { role: 'admin' }
});
核心优势二:内置自动重试机制
这是 ky 最亮眼的功能。在不稳定的网络环境下,ky 默认会在请求遇到 408、413、429、500、502、503、504 等状态码时自动重试。
javascript
const data = await ky.get('https://api.slow-server.com', {
retry: {
limit: 5, // 最多重试 5 次
methods: ['get'],
statusCodes: [408, 500]
}
}).json();
核心优势三:现代化的钩子 (Hooks)
类似于 Axios 的拦截器,ky 提供了简洁的钩子系统,非常适合统一注入 Token 或处理全局错误。
javascript
const api = ky.create({
prefixUrl: 'https://api.example.com/v1',
hooks: {
beforeRequest: [
request => {
request.headers.set('Authorization', `Bearer ${getToken()}`);
}
],
afterResponse: [
(_request, _options, response) => {
if (response.status === 401) {
logout(); // 处理登录过期
}
}
]
}
});
ky vs Axios:数据对比
| 特性 | Ky | Axios |
|---|---|---|
| 包体积 (Gzipped) | ~2 KB | ~11 KB |
| 底层实现 | Fetch API | XMLHttpRequest / Http (Node) |
| 自动重试 | 内置 | 需第三方插件 |
| 超时处理 | 内置 | 内置 |
| 浏览器兼容性 | 现代浏览器 (ESM) | 所有浏览器 (包括 IE) |
什么时候该切换到 ky?
- 追求极致体积:如果你的项目对 Bundle Size 非常敏感,ky 仅有 Axios 的五分之一。
- 现代浏览器环境:如果你不再需要兼容 IE,那么基于原生 Fetch 的 ky 是更顺应潮流的选择。
- React/Vue 组件开发:在编写轻量级组件库时,引入 ky 作为依赖不会让包体臃肿。
ky 不是要取代所有场景下的 Axios,而是在现代 Web 开发中提供了一个更轻、更符合标准的选择。 如果你厌倦了原生 Fetch 的繁琐,又不希望引入笨重的 Axios,那么 ky 就是那个"刚刚好"的中间点。
以下是 ky 在实际开发中最常用的基础案例:
1. GET 请求:获取 JSON 数据
这是最常见的用法。ky 默认假设你想要处理 JSON,通过 .json() 方法可以直接解构数据,无需像 fetch 那样写两次 await。
javascript
import ky from 'ky';
async function fetchUser() {
// 基础用法
const user = await ky.get('https://api.example.com/user/1').json();
console.log(user.name);
}
2. POST 请求:发送 JSON 载荷
使用 json 选项时,ky 会自动设置 Content-Type: application/json 并序列化你的对象。
javascript
const newUser = { name: 'Gemini', role: 'AI' };
const response = await ky.post('https://api.example.com/users', {
json: newUser
}).json();
3. 处理 URL 查询参数 (Search Params)
不再需要手动拼接字符串或使用 new URLSearchParams(),直接传对象即可。
javascript
const users = await ky.get('https://api.example.com/search', {
searchParams: {
limit: 10,
page: 1,
active: true
}
}).json();
// 生成的 URL 为: .../search?limit=10&page=1&active=true
4. 实例化配置 (ky.create)
这是生产环境中最推荐的写法。你可以创建一个带有基础 URL 和通用 Headers 的实例。
javascript
const api = ky.create({
prefixUrl: 'https://api.example.com/v1',
headers: {
'x-api-key': 'your-secret-key'
}
});
// 此时只需要写相对路径
const data = await api.get('dashboard').json();
5. 错误处理 (Error Handling)
ky 的一大优势是它会将非 2xx 的状态码视为错误并抛出。你可以轻松访问错误状态和响应体。
javascript
try {
const data = await ky.get('https://api.com/private').json();
} catch (error) {
if (error.name === 'HTTPError') {
const errorData = await error.response.json();
console.error(`Status: ${error.response.status}`, errorData);
}
}
6. 超时与重试 (Timeout & Retry)
这是 ky 的"杀手锏"功能,配置非常直观。
javascript
const data = await ky.get('https://slow-api.com', {
timeout: 3000, // 3秒超时
retry: {
limit: 3, // 最多重试3次
methods: ['get'], // 仅对 GET 请求重试
statusCodes: [408, 500, 502, 504] // 遇到这些状态码重试
}
}).json();
7. 下载进度监控
得益于对原生 Fetch 流的支持,ky 提供了一个简单的 onDownloadProgress 回调。
javascript
const response = await ky.get('https://example.com/large-file.zip', {
onDownloadProgress: (progress, chunk) => {
console.log(`下载进度: ${Math.round(progress.percent * 100)}%`);
console.log(`已传输字节: ${progress.transferredBytes}`);
}
});
总结对照表
| 场景 | ky 参数项 |
优势 |
|---|---|---|
| 基础路径 | prefixUrl |
避免重复写完整 API 地址 |
| 发送数据 | json |
自动序列化并设置 Header |
| 查询参数 | searchParams |
自动处理对象转 URL 字符串 |
| 重试控制 | retry |
内置退避算法,增强网络容错性 |
| 认证信息 | hooks |
适合在 beforeRequest 中统一注入 Token |