ky

ky

基于Fetch API的轻量级现代HTTP客户端

ky是基于Fetch API开发的轻量级HTTP客户端,适用于现代浏览器、Node.js、Bun和Deno环境。它提供简化的API、方法快捷键、错误处理、请求重试、JSON操作和超时支持等功能,相比原生fetch更加便捷。作为一个无依赖的小型包,ky为开发者简化了HTTP请求处理流程。

KyHTTP客户端Fetch API异步请求JavaScriptGithub开源项目
<div align="center"> <br> <div> <img width="600" height="600" src="https://yellow-cdn.veclightyear.com/835a84d5/50730632-ab7a-4071-b5e2-f8c09e941272.svg" alt="ky"> </div> <br> <br> <p> <p> <sup> Sindre的开源工作得到了社区的支持。<br>特别感谢: </sup> </p> <br> <br> <a href="https://logto.io/?ref=sindre"> <div> <picture> <source width="200" media="(prefers-color-scheme: dark)" srcset="https://sindresorhus.com/assets/thanks/logto-logo-dark.svg?x"> <source width="200" media="(prefers-color-scheme: light)" srcset="https://yellow-cdn.veclightyear.com/835a84d5/c5e9f627-ce2f-4aaf-a1d5-753c868fbb28.svg?x"> <img width="200" src="https://yellow-cdn.veclightyear.com/835a84d5/c5e9f627-ce2f-4aaf-a1d5-753c868fbb28.svg?x" alt="Logto logo"> </picture> </div> <b>为开发者提供更好的身份基础设施</b> <div> <sup>Logto是为每个应用设计的开源Auth0替代方案。</sup> </div> </a> </p> <br> <br> <br> <br> <br> <br> <br> <br> </div>

Ky是一个基于Fetch API的小巧而优雅的HTTP客户端

覆盖率状态

Ky针对现代浏览器、Node.js、Bun和Deno。

它只是一个没有依赖项的小型包。

相比普通fetch的优势

  • 更简单的API
  • 方法快捷方式(ky.post()
  • 将非2xx状态码视为错误(在重定向之后)
  • 重试失败的请求
  • JSON选项
  • 超时支持
  • URL前缀选项
  • 具有自定义默认值的实例
  • 钩子
  • TypeScript便利性(例如,.json()支持泛型并默认为unknown,而不是any

安装

npm install ky
下载
CDN

使用

import ky from 'ky'; const json = await ky.post('https://example.com', {json: {foo: true}}).json(); console.log(json); //=> `{data: '🦄'}`

使用普通的fetch,它将是:

class HTTPError extends Error {} const response = await fetch('https://example.com', { method: 'POST', body: JSON.stringify({foo: true}), headers: { 'content-type': 'application/json' } }); if (!response.ok) { throw new HTTPError(`Fetch error: ${response.statusText}`); } const json = await response.json(); console.log(json); //=> `{data: '🦄'}`

如果你使用的是Deno,从URL导入Ky。例如,使用CDN:

import ky from 'https://esm.sh/ky';

API

ky(input, options?)

inputoptionsfetch相同,还提供了额外的options(见下文)。

返回一个带有Body方法Response对象,以方便使用。因此,你可以直接调用ky.get(input).json(),而不必先等待Response。当这样调用时,将根据使用的body方法设置适当的Accept头。与window.FetchBody方法不同,如果响应状态不在200...299范围内,这些方法将抛出HTTPError。此外,如果body为空或响应状态为204.json()将返回空字符串,而不是因为空body而抛出解析错误。

import ky from 'ky'; const user = await ky('/api/user').json(); console.log(user);

⌨️ TypeScript: 接受一个可选的类型参数,默认为unknown,并传递给.json()的返回类型。

import ky from 'ky'; // user1是unknown类型 const user1 = await ky('/api/users/1').json(); // user2是User类型 const user2 = await ky<User>('/api/users/2').json(); // user3是User类型 const user3 = await ky('/api/users/3').json<User>(); console.log([user1, user2, user3]);

ky.get(input, options?)

ky.post(input, options?)

ky.put(input, options?)

ky.patch(input, options?)

ky.head(input, options?)

ky.delete(input, options?)

options.method设置为方法名并发起请求。

⌨️ TypeScript: 接受一个可选的类型参数,用于JSON响应(参见ky())。

input

类型:string | URL | Request

fetch input相同。

当使用Request实例作为input时,任何改变URL的选项(如prefixUrl)将被忽略。

options

类型:object

fetch options相同,外加以下额外选项:

method

类型:string
默认值:'get'

用于发起请求的HTTP方法。

内部会将标准方法(GETPOSTPUTPATCHHEADDELETE)转为大写,以避免由于大小写敏感性导致的服务器错误。

json

类型:objectJSON.stringify()接受的任何其他值

发送JSON的快捷方式。使用此选项代替body选项。接受任何普通对象或值,这些值将被JSON.stringify()处理并在正文中发送,同时设置正确的头部。

searchParams

类型:string | object<string, string | number | boolean> | Array<Array<string | number | boolean>> | URLSearchParams
默认值:''

要包含在请求URL中的搜索参数。设置此项将覆盖输入URL中的所有现有搜索参数。

接受URLSearchParams()支持的任何值。

prefixUrl

类型:string | URL

在发起请求时,要预先添加到input URL的前缀。它可以是任何有效的URL,相对或绝对。末尾的斜杠/是可选的,如果需要,在与input连接时会自动添加。仅当input是字符串时生效。使用此选项时,input参数不能以斜杠/开头。

在使用ky.extend()创建特定领域的Ky实例时非常有用。

import ky from 'ky'; // 在 https://example.com 上 const response = await ky('unicorn', {prefixUrl: '/api'}); //=> 'https://example.com/api/unicorn' const response2 = await ky('unicorn', {prefixUrl: 'https://cats.com'}); //=> 'https://cats.com/unicorn'

注意:

  • 在连接 prefixUrlinput 后,结果会根据页面的基础 URL(如果有)进行解析。
  • 使用此选项时,不允许 input 中有前导斜杠,以确保一致性并避免对 input URL 处理方式产生混淆。因为使用 prefixUrl 时,input 不会遵循正常的 URL 解析规则,这改变了前导斜杠的含义。
retry

类型:object | number 默认值:

  • limit2
  • methodsget put head delete options trace
  • statusCodes408 413 429 500 502 503 504
  • afterStatusCodes413429503
  • maxRetryAfterundefined
  • backoffLimitundefined
  • delayattemptCount => 0.3 * (2 ** (attemptCount - 1)) * 1000

一个对象,表示最大重试次数、允许的方法、允许的状态码、允许使用 Retry-After 时间的状态码,以及最大 Retry-After 时间的 limitmethodsstatusCodesafterStatusCodesmaxRetryAfter 字段。

如果 retry 是一个数字,它将被用作 limit,其他默认值保持不变。

如果响应提供的 HTTP 状态包含在 afterStatusCodes 中,Ky 将等待 Retry-After 头部给出的日期、超时或时间戳过去后再重试请求。如果缺少 Retry-After,则使用非标准的 RateLimit-Reset 头部作为备用。如果提供的状态码不在列表中,将忽略 Retry-After 头部。

如果 maxRetryAfter 设置为 undefined,它将使用 options.timeout。如果 Retry-After 头部大于 maxRetryAfter,它将使用 maxRetryAfter

backoffLimit 选项是每次重试延迟的上限(以毫秒为单位)。 要限制延迟,可以将 backoffLimit 设置为 1000,例如。 默认情况下,延迟使用 0.3 * (2 ** (attemptCount - 1)) * 1000 计算。延迟呈指数增长。

delay 选项可用于更改计算重试之间延迟的方式。该函数接收一个参数,即尝试次数,从 1 开始。

超时后不会触发重试。

import ky from 'ky'; const json = await ky('https://example.com', { retry: { limit: 10, methods: ['get'], statusCodes: [413], backoffLimit: 3000 } }).json();
timeout

类型:number | false 默认值:10000

获取响应的超时时间(毫秒),包括任何重试。不能大于 2147483647。 如果设置为 false,则不会有超时。

hooks

类型:object<string, Function[]> 默认值:{beforeRequest: [], beforeRetry: [], afterResponse: []}

钩子允许在请求生命周期中进行修改。钩子函数可以是异步的,并且按顺序运行。

hooks.beforeRequest

类型:Function[] 默认值:[]

此钩子使您能够在请求发送之前修改请求。在此之后,Ky 不会对请求做任何进一步的更改。钩子函数接收 requestoptions 作为参数。例如,您可以在这里修改 request.headers

钩子可以返回一个 Request 来替换即将发出的请求,或返回一个 Response 来完全避免发出 HTTP 请求。这可以用于模拟请求、检查内部缓存等。从此钩子返回请求或响应时的一个重要考虑因素是,任何剩余的 beforeRequest 钩子将被跳过,因此您可能只想从最后一个钩子返回它们。

import ky from 'ky'; const api = ky.extend({ hooks: { beforeRequest: [ request => { request.headers.set('X-Requested-With', 'ky'); } ] } }); const response = await api.get('https://example.com/api/users');
hooks.beforeRetry

类型:Function[] 默认值:[]

此钩子使您能够在重试之前修改请求。在此之后,Ky 不会对请求做任何进一步的更改。钩子函数接收一个包含规范化的请求和选项、错误实例以及重试次数的对象。例如,您可以在这里修改 request.headers

如果请求收到响应,错误将是 HTTPError 类型,并且 Response 对象将在 error.response 中可用。请注意,某些类型的错误(如网络错误)本质上意味着没有收到响应。在这种情况下,错误将不是 HTTPError 的实例。

您可以通过抛出错误来阻止 Ky 重试请求。Ky 不会以任何方式处理它,错误将传播给请求发起者。在这种情况下,剩余的 beforeRetry 钩子将不会被调用。或者,您可以返回 ky.stop 符号来做同样的事情,但不传播错误(这有一些限制,详见 ky.stop 文档)。

import ky from 'ky'; const response = await ky('https://example.com', { hooks: { beforeRetry: [ async ({request, options, error, retryCount}) => { const token = await ky('https://example.com/refresh-token'); request.headers.set('Authorization', `token ${token}`); } ] } });
hooks.beforeError

类型:Function[] 默认值:[]

此钩子使您能够在抛出 HTTPError 之前修改它。钩子函数接收一个 HTTPError 作为参数,并应返回一个 HTTPError 实例。

import ky from 'ky'; await ky('https://example.com', { hooks: { beforeError: [ error => { const {response} = error; if (response && response.body) { error.name = 'GitHubError'; error.message = `${response.body.message} (${response.status})`; } return error; } ] } });
hooks.afterResponse

类型:Function[] 默认值:[]

此钩子使您能够读取和可选地修改响应。钩子函数接收规范化的请求、选项和响应的克隆作为参数。如果钩子函数的返回值是 Response 的实例,Ky 将使用它作为响应对象。

import ky from 'ky'; const response = await ky('https://example.com', { hooks: { afterResponse: [ (_request, _options, response) => { // 你可以对响应做一些处理,比如记录日志 log(response); // 或者返回一个新的 Response 实例来覆盖原响应 return new Response('一个不同的响应', {status: 200}); }, // 或者在遇到 403 错误时使用新的 token 重试 async (request, options, response) => { if (response.status === 403) { // 获取新的 token const token = await ky('https://example.com/token').text(); // 使用新 token 重试 request.headers.set('Authorization', `token ${token}`); return ky(request); } } ] } });
throwHttpErrors

类型: boolean 默认值: true

当响应状态码非 2xx 时(在跟随重定向之后),抛出 HTTPError。如果要对重定向也抛出错误而不是跟随它们,请将 redirect 选项设置为 'manual'

将此选项设置为 false 可能在检查资源可用性并期望出现错误响应时有用。

注意:如果设为 false,错误响应将被视为成功,请求不会重试。

onDownloadProgress

类型: Function

下载进度事件处理函数。

该函数接收 progresschunk 参数:

  • progress 对象包含以下元素:percenttransferredBytestotalBytes。如果无法获取主体大小,totalBytes 将为 0
  • chunk 参数是 Uint8Array 的实例。第一次调用时为空。
import ky from 'ky'; const response = await ky('https://example.com', { onDownloadProgress: (progress, chunk) => { // 示例输出: // `0% - 0 of 1271 bytes` // `100% - 1271 of 1271 bytes` console.log(`${progress.percent * 100}% - ${progress.transferredBytes} of ${progress.totalBytes} bytes`); } });
parseJson

类型: Function 默认值: JSON.parse()

用户自定义 JSON 解析函数。

使用场景:

  1. 通过 bourne 解析 JSON 以防止原型污染。
  2. 使用 JSON.parse()reviver 选项 解析 JSON。
import ky from 'ky'; import bourne from '@hapijs/bourne'; const json = await ky('https://example.com', { parseJson: text => bourne(text) }).json();
stringifyJson

类型: Function 默认值: JSON.stringify()

用户自定义 JSON 字符串化函数。

使用场景:

  1. 使用自定义 replacer 函数字符串化 JSON。
import ky from 'ky'; import {DateTime} from 'luxon'; const json = await ky('https://example.com', { stringifyJson: data => JSON.stringify(data, (key, value) => { if (key.endsWith('_at')) { return DateTime.fromISO(value).toSeconds(); } return value; }) }).json();
fetch

类型: Function 默认值: fetch

用户自定义 fetch 函数。 必须完全兼容 Fetch API 标准。

使用场景:

  1. 使用自定义 fetch 实现,如 isomorphic-unfetch
  2. 使用某些使用服务器端渲染(SSR)的框架提供的 fetch 包装函数。
import ky from 'ky'; import fetch from 'isomorphic-unfetch'; const json = await ky('https://example.com', {fetch}).json();

ky.extend(defaultOptions)

创建一个新的 ky 实例,覆盖一些默认选项。

ky.create() 不同,ky.extend() 会继承其父实例的默认值。

你可以将 headers 作为 Headers 实例或普通对象传递。

你可以通过传递值为 undefined 的 header 来删除 header。 作为字符串传递 undefined 只有在 header 来自 Headers 实例时才会删除该 header。

类似地,你可以通过显式传递 undefined 来删除现有的 hooks 条目。

import ky from 'ky'; const url = 'https://sindresorhus.com'; const original = ky.create({ headers: { rainbow: 'rainbow', unicorn: 'unicorn' }, hooks: { beforeRequest: [ () => console.log('before 1') ], afterResponse: [ () => console.log('after 1') ], }, }); const extended = original.extend({ headers: { rainbow: undefined }, hooks: { beforeRequest: undefined, afterResponse: [ () => console.log('after 2') ], } }); const response = await extended(url).json(); //=> after 1 //=> after 2 console.log('rainbow' in response); //=> false console.log('unicorn' in response); //=> true

你也可以通过向 .extend() 提供函数来引用父实例的默认值。

import ky from 'ky'; const api = ky.create({prefixUrl: 'https://example.com/api'}); const usersApi = api.extend((options) => ({prefixUrl: `${options.prefixUrl}/users`})); const response = await usersApi.get('123'); //=> 'https://example.com/api/users/123' const response = await api.get('version'); //=> 'https://example.com/api/version'

ky.create(defaultOptions)

创建一个具有全新默认值的 Ky 实例。

import ky from 'ky'; // 在 https://my-site.com const api = ky.create({prefixUrl: 'https://example.com/api'}); const response = await api.get('users/123'); //=> 'https://example.com/api/users/123' const response = await api.get('/status', {prefixUrl: ''}); //=> 'https://my-site.com/status'

defaultOptions

类型: object

ky.stop

一个可以由 beforeRetry 钩子返回以停止重试的 Symbol。这也会短路剩余的 beforeRetry 钩子。

注意:返回此符号会使 Ky 中止并返回 undefined 响应。在访问响应的任何属性之前,请确保检查响应是否存在,或使用可选链。它也与 .json().text() 等主体方法不兼容,因为没有响应可供解析。一般来说,我们建议抛出错误而不是返回此符号,因为这会导致 Ky 中止然后抛出,从而避免这些限制。

ky.stop 的一个有效用例是在进行副作用请求时防止重试,这种情况下返回的数据并不重要。例如,向服务器记录客户端活动。

import ky from 'ky'; const options = { hooks: { beforeRetry: [ async ({request, options, error, retryCount}) => { const shouldStopRetry = await ky('https://example.com/api'); if (shouldStopRetry) { return ky.stop; } } ] } }; // 注意,如果返回 ky.stop,response 将为 `undefined`。 const response = await ky.post('https://example.com', options); // 不支持使用 `.text()` 或其他主体方法。 const text = await ky('https://example.com', options).text();

HTTPError

暴露用于 instanceof 检查。错误对象具有 response 属性(包含 Response 对象),request 属性(包含 Request 对象),以及 options 属性(包含规范化的选项,这些选项可能是在使用 ky.create() 创建实例时传递给 ky 的,或者是直接在执行请求时传递的)。

如果在发生 HTTPError 时需要读取实际响应,请在响应对象上调用相应的解析器方法。例如:

try { await ky('https://example.com').json(); } catch (error) { if (error.name === 'HTTPError') { const errorJson = await error.response.json(); } }

⌨️ TypeScript: 接受一个可选的类型参数,默认为unknown,并传递给error.response.json()的返回类型。

TimeoutError

请求超时时抛出的错误。它有一个request属性,包含Request对象

提示

发送表单数据

在Ky中发送表单数据与fetch相同。只需将FormData实例传递给body选项。Content-Type头部将自动设置为multipart/form-data

import ky from 'ky'; // `multipart/form-data` const formData = new FormData(); formData.append('food', 'fries'); formData.append('drink', 'icetea'); const response = await ky.post(url, {body: formData});

如果你想以application/x-www-form-urlencoded格式发送数据,你需要使用URLSearchParams对数据进行编码。

import ky from 'ky'; // `application/x-www-form-urlencoded` const searchParams = new URLSearchParams(); searchParams.set('food', 'fries'); searchParams.set('drink', 'icetea'); const response = await ky.post(url, {body: searchParams});

设置自定义Content-Type

Ky会根据请求体中的数据自动为每个请求设置适当的Content-Type头部。但是,有些API需要自定义的非标准内容类型,如application/x-amz-json-1.1。使用headers选项,你可以手动覆盖内容类型。

import ky from 'ky'; const json = await ky.post('https://example.com', { headers: { 'content-type': 'application/json' }, json: { foo: true }, }).json(); console.log(json); //=> `{data: '🦄'}`

取消请求

Fetch(因此也包括Ky)通过AbortController API内置支持请求取消。了解更多。

示例:

import ky from 'ky'; const controller = new AbortController(); const {signal} = controller; setTimeout(() => { controller.abort(); }, 5000); try { console.log(await ky(url, {signal}).text()); } catch (error) { if (error.name === 'AbortError') { console.log('Fetch aborted'); } else { console.error('Fetch error:', error); } }

常见问题

如何在Node.js中使用?

Node.js 18及更高版本原生支持fetch,所以你可以直接使用这个包。

如何在使用服务器端渲染(SSR)的Web应用(React、Vue.js等)中使用?

与上述相同。

如何测试使用这个库的浏览器库?

要么使用可以在浏览器中运行的测试运行器,如Mocha,要么使用AVAky-universal了解更多。

如何在不使用Webpack等打包工具的情况下使用?

确保你的代码作为JavaScript模块(ESM)运行,例如在HTML文档中使用<script type="module">标签。然后Ky可以直接被该模块导入,无需打包工具或其他工具。

<script type="module"> import ky from 'https://unpkg.com/ky/distribution/index.js'; const json = await ky('https://jsonplaceholder.typicode.com/todos/1').json(); console.log(json.title); //=> 'delectus aut autem' </script>

它与got有何不同?

请参阅我的回答这里。Got由与Ky相同的人维护。

它与axios有何不同?

请参阅我的回答这里

它与r2有何不同?

请参阅我在#10中的回答。

ky是什么意思?

这只是我设法获得的一个随机短npm包名。不过,它在日语中确实有意义:

一种可发短信的俚语,KY是空気読めない(kuuki yomenai)的缩写,字面意思是"无法读懂空气"。这个短语用于形容一个人无法理解暗示的含义。

浏览器支持

最新版本的Chrome、Firefox和Safari。

Node.js支持

Node.js 18及更高版本。

相关

维护者

编辑推荐精选

讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

模型训练热门AI工具内容创作智能问答AI开发讯飞星火大模型多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

热门AI工具生产力协作转型TraeAI IDE
咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

AI助手热门AI工具AI创作AI辅助写作讯飞绘文内容运营个性化文章多平台分发
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

Hunyuan3D-2

Hunyuan3D-2

高分辨率纹理 3D 资产生成

Hunyuan3D-2 是腾讯开发的用于 3D 资产生成的强大工具,支持从文本描述、单张图片或多视角图片生成 3D 模型,具备快速形状生成能力,可生成带纹理的高质量 3D 模型,适用于多个领域,为 3D 创作提供了高效解决方案。

3FS

3FS

一个具备存储、管理和客户端操作等多种功能的分布式文件系统相关项目。

3FS 是一个功能强大的分布式文件系统项目,涵盖了存储引擎、元数据管理、客户端工具等多个模块。它支持多种文件操作,如创建文件和目录、设置布局等,同时具备高效的事件循环、节点选择和协程池管理等特性。适用于需要大规模数据存储和管理的场景,能够提高系统的性能和可靠性,是分布式存储领域的优质解决方案。

TRELLIS

TRELLIS

用于可扩展和多功能 3D 生成的结构化 3D 潜在表示

TRELLIS 是一个专注于 3D 生成的项目,它利用结构化 3D 潜在表示技术,实现了可扩展且多功能的 3D 生成。项目提供了多种 3D 生成的方法和工具,包括文本到 3D、图像到 3D 等,并且支持多种输出格式,如 3D 高斯、辐射场和网格等。通过 TRELLIS,用户可以根据文本描述或图像输入快速生成高质量的 3D 资产,适用于游戏开发、动画制作、虚拟现实等多个领域。

下拉加载更多