diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 02d8968..33dff12 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,8 +1,313 @@ import { defineConfig } from 'vitepress'; // https://vitepress.dev/reference/site-config + +// ─── English ───────────────────────────────────────────────────────────────── + +const enNav = [ + { text: 'Guide', link: '/pages/getting-started/first-steps' }, + { text: 'API', link: '/pages/advanced/api-reference' }, + { text: 'Sponsors', link: '/pages/misc/sponsors' }, + { text: 'v1.x', link: '#' }, +]; + +const enSidebar = [ + { + text: 'Getting Started', + items: [ + { text: 'First steps', link: '/pages/getting-started/first-steps' }, + { text: 'Features', link: '/pages/getting-started/features' }, + { + text: 'Examples', + items: [ + { text: 'JavaScript', link: '/pages/getting-started/examples/commonjs' }, + { text: 'TypeScript', link: '/pages/getting-started/examples/typescript' }, + ], + }, + { text: 'Upgrade guide v0.x -> v1.x', link: '/pages/getting-started/upgrade-guide' }, + ], + }, + { + text: 'Advanced', + items: [ + { text: 'Public API', link: '/pages/advanced/api-reference' }, + { text: 'Request method aliases', link: '/pages/advanced/request-method-aliases' }, + { text: 'Creating an instance', link: '/pages/advanced/create-an-instance' }, + { text: 'Request config', link: '/pages/advanced/request-config' }, + { text: 'Adapters', link: '/pages/advanced/adapters' }, + { text: 'Response schema', link: '/pages/advanced/response-schema' }, + { text: 'Config defaults', link: '/pages/advanced/config-defaults' }, + { text: 'Interceptors', link: '/pages/advanced/interceptors' }, + { text: 'Error handling', link: '/pages/advanced/error-handling' }, + { text: 'Cancellation', link: '/pages/advanced/cancellation' }, + { text: 'Authentication', link: '/pages/advanced/authentication' }, + { text: 'Retry & error recovery', link: '/pages/advanced/retry' }, + { text: 'Testing', link: '/pages/advanced/testing' }, + { + text: 'x-www-form-urlencoded format', + link: '/pages/advanced/x-www-form-urlencoded-format', + }, + { text: 'Multipart/form-data format', link: '/pages/advanced/multipart-form-data-format' }, + { text: 'File posting', link: '/pages/advanced/file-posting' }, + { text: 'HTML form processing 🔥', link: '/pages/advanced/html-form-processing' }, + { text: 'Progress capturing 🔥', link: '/pages/advanced/progress-capturing' }, + { text: 'Rate limiting 🔥', link: '/pages/advanced/rate-limiting' }, + { + text: 'Headers 🔥', + items: [ + { text: 'General usage', link: '/pages/advanced/headers' }, + { text: 'Methods', link: '/pages/advanced/header-methods' }, + ], + }, + { text: 'Fetch adapter 🔥', link: '/pages/advanced/fetch-adapter' }, + { text: 'HTTP2 🔥', link: '/pages/advanced/http2' }, + { text: 'Promises', link: '/pages/advanced/promises' }, + { text: 'TypeScript', link: '/pages/advanced/type-script' }, + ], + }, + { + text: 'Miscellaneous', + items: [ + { text: 'SemVer', link: '/pages/misc/semver' }, + { text: 'Security', link: '/pages/misc/security' }, + ], + }, +]; + +// ─── Mandarin Chinese ───────────────────────────────────────────────────────── + +const zhNav = [ + { text: '指南', link: '/zh/pages/getting-started/first-steps' }, + { text: 'API', link: '/zh/pages/advanced/api-reference' }, + { text: '赞助商', link: '/zh/pages/misc/sponsors' }, + { text: 'v1.x', link: '#' }, +]; + +const zhSidebar = [ + { + text: '入门指南', + items: [ + { text: '第一步', link: '/zh/pages/getting-started/first-steps' }, + { text: '功能特性', link: '/zh/pages/getting-started/features' }, + { + text: '示例', + items: [ + { text: 'JavaScript', link: '/zh/pages/getting-started/examples/commonjs' }, + { text: 'TypeScript', link: '/zh/pages/getting-started/examples/typescript' }, + ], + }, + { text: '升级指南 v0.x -> v1.x', link: '/zh/pages/getting-started/upgrade-guide' }, + ], + }, + { + text: '进阶', + items: [ + { text: '公共 API', link: '/zh/pages/advanced/api-reference' }, + { text: '请求方法别名', link: '/zh/pages/advanced/request-method-aliases' }, + { text: '创建实例', link: '/zh/pages/advanced/create-an-instance' }, + { text: '请求配置', link: '/zh/pages/advanced/request-config' }, + { text: '适配器', link: '/zh/pages/advanced/adapters' }, + { text: '响应结构', link: '/zh/pages/advanced/response-schema' }, + { text: '默认配置', link: '/zh/pages/advanced/config-defaults' }, + { text: '拦截器', link: '/zh/pages/advanced/interceptors' }, + { text: '错误处理', link: '/zh/pages/advanced/error-handling' }, + { text: '取消请求', link: '/zh/pages/advanced/cancellation' }, + { text: '身份验证', link: '/zh/pages/advanced/authentication' }, + { text: '重试与错误恢复', link: '/zh/pages/advanced/retry' }, + { text: '测试', link: '/zh/pages/advanced/testing' }, + { + text: 'x-www-form-urlencoded 格式', + link: '/zh/pages/advanced/x-www-form-urlencoded-format', + }, + { text: 'Multipart/form-data 格式', link: '/zh/pages/advanced/multipart-form-data-format' }, + { text: '文件上传', link: '/zh/pages/advanced/file-posting' }, + { text: 'HTML 表单处理 🔥', link: '/zh/pages/advanced/html-form-processing' }, + { text: '进度捕获 🔥', link: '/zh/pages/advanced/progress-capturing' }, + { text: '速率限制 🔥', link: '/zh/pages/advanced/rate-limiting' }, + { + text: '请求头 🔥', + items: [ + { text: '基本用法', link: '/zh/pages/advanced/headers' }, + { text: '方法', link: '/zh/pages/advanced/header-methods' }, + ], + }, + { text: 'Fetch 适配器 🔥', link: '/zh/pages/advanced/fetch-adapter' }, + { text: 'HTTP2 🔥', link: '/zh/pages/advanced/http2' }, + { text: 'Promises', link: '/zh/pages/advanced/promises' }, + { text: 'TypeScript', link: '/zh/pages/advanced/type-script' }, + ], + }, + { + text: '其他', + items: [ + { text: '语义化版本', link: '/zh/pages/misc/semver' }, + { text: '安全', link: '/zh/pages/misc/security' }, + ], + }, +]; + +// ─── Spanish ────────────────────────────────────────────────────────────────── + +const esNav = [ + { text: 'Guía', link: '/es/pages/getting-started/first-steps' }, + { text: 'API', link: '/es/pages/advanced/api-reference' }, + { text: 'Patrocinadores', link: '/es/pages/misc/sponsors' }, + { text: 'v1.x', link: '#' }, +]; + +const esSidebar = [ + { + text: 'Primeros pasos', + items: [ + { text: 'Inicio', link: '/es/pages/getting-started/first-steps' }, + { text: 'Características', link: '/es/pages/getting-started/features' }, + { + text: 'Ejemplos', + items: [ + { text: 'JavaScript', link: '/es/pages/getting-started/examples/commonjs' }, + { text: 'TypeScript', link: '/es/pages/getting-started/examples/typescript' }, + ], + }, + { + text: 'Guía de actualización v0.x -> v1.x', + link: '/es/pages/getting-started/upgrade-guide', + }, + ], + }, + { + text: 'Avanzado', + items: [ + { text: 'API pública', link: '/es/pages/advanced/api-reference' }, + { text: 'Alias de métodos de solicitud', link: '/es/pages/advanced/request-method-aliases' }, + { text: 'Crear una instancia', link: '/es/pages/advanced/create-an-instance' }, + { text: 'Configuración de solicitud', link: '/es/pages/advanced/request-config' }, + { text: 'Adaptadores', link: '/es/pages/advanced/adapters' }, + { text: 'Esquema de respuesta', link: '/es/pages/advanced/response-schema' }, + { text: 'Configuración predeterminada', link: '/es/pages/advanced/config-defaults' }, + { text: 'Interceptores', link: '/es/pages/advanced/interceptors' }, + { text: 'Manejo de errores', link: '/es/pages/advanced/error-handling' }, + { text: 'Cancelación', link: '/es/pages/advanced/cancellation' }, + { text: 'Autenticación', link: '/es/pages/advanced/authentication' }, + { text: 'Reintento y recuperación de errores', link: '/es/pages/advanced/retry' }, + { text: 'Pruebas', link: '/es/pages/advanced/testing' }, + { + text: 'Formato x-www-form-urlencoded', + link: '/es/pages/advanced/x-www-form-urlencoded-format', + }, + { + text: 'Formato Multipart/form-data', + link: '/es/pages/advanced/multipart-form-data-format', + }, + { text: 'Publicación de archivos', link: '/es/pages/advanced/file-posting' }, + { + text: 'Procesamiento de formularios HTML 🔥', + link: '/es/pages/advanced/html-form-processing', + }, + { text: 'Captura de progreso 🔥', link: '/es/pages/advanced/progress-capturing' }, + { text: 'Limitación de velocidad 🔥', link: '/es/pages/advanced/rate-limiting' }, + { + text: 'Cabeceras 🔥', + items: [ + { text: 'Uso general', link: '/es/pages/advanced/headers' }, + { text: 'Métodos', link: '/es/pages/advanced/header-methods' }, + ], + }, + { text: 'Adaptador Fetch 🔥', link: '/es/pages/advanced/fetch-adapter' }, + { text: 'HTTP2 🔥', link: '/es/pages/advanced/http2' }, + { text: 'Promesas', link: '/es/pages/advanced/promises' }, + { text: 'TypeScript', link: '/es/pages/advanced/type-script' }, + ], + }, + { + text: 'Miscelánea', + items: [ + { text: 'SemVer', link: '/es/pages/misc/semver' }, + { text: 'Seguridad', link: '/es/pages/misc/security' }, + ], + }, +]; + +// ─── French ─────────────────────────────────────────────────────────────────── + +const frNav = [ + { text: 'Guide', link: '/fr/pages/getting-started/first-steps' }, + { text: 'API', link: '/fr/pages/advanced/api-reference' }, + { text: 'Sponsors', link: '/fr/pages/misc/sponsors' }, + { text: 'v1.x', link: '#' }, +]; + +const frSidebar = [ + { + text: 'Démarrage', + items: [ + { text: 'Premiers pas', link: '/fr/pages/getting-started/first-steps' }, + { text: 'Fonctionnalités', link: '/fr/pages/getting-started/features' }, + { + text: 'Exemples', + items: [ + { text: 'JavaScript', link: '/fr/pages/getting-started/examples/commonjs' }, + { text: 'TypeScript', link: '/fr/pages/getting-started/examples/typescript' }, + ], + }, + { + text: 'Guide de mise à niveau v0.x -> v1.x', + link: '/fr/pages/getting-started/upgrade-guide', + }, + ], + }, + { + text: 'Avancé', + items: [ + { text: 'API publique', link: '/fr/pages/advanced/api-reference' }, + { text: 'Alias des méthodes de requête', link: '/fr/pages/advanced/request-method-aliases' }, + { text: 'Créer une instance', link: '/fr/pages/advanced/create-an-instance' }, + { text: 'Configuration des requêtes', link: '/fr/pages/advanced/request-config' }, + { text: 'Adaptateurs', link: '/fr/pages/advanced/adapters' }, + { text: 'Schéma de réponse', link: '/fr/pages/advanced/response-schema' }, + { text: 'Configuration par défaut', link: '/fr/pages/advanced/config-defaults' }, + { text: 'Intercepteurs', link: '/fr/pages/advanced/interceptors' }, + { text: 'Gestion des erreurs', link: '/fr/pages/advanced/error-handling' }, + { text: 'Annulation', link: '/fr/pages/advanced/cancellation' }, + { text: 'Authentification', link: '/fr/pages/advanced/authentication' }, + { text: "Nouvelles tentatives et récupération d'erreurs", link: '/fr/pages/advanced/retry' }, + { text: 'Tests', link: '/fr/pages/advanced/testing' }, + { + text: 'Format x-www-form-urlencoded', + link: '/fr/pages/advanced/x-www-form-urlencoded-format', + }, + { text: 'Format Multipart/form-data', link: '/fr/pages/advanced/multipart-form-data-format' }, + { text: 'Envoi de fichiers', link: '/fr/pages/advanced/file-posting' }, + { + text: 'Traitement des formulaires HTML 🔥', + link: '/fr/pages/advanced/html-form-processing', + }, + { text: 'Capture de la progression 🔥', link: '/fr/pages/advanced/progress-capturing' }, + { text: 'Limitation du débit 🔥', link: '/fr/pages/advanced/rate-limiting' }, + { + text: 'En-têtes 🔥', + items: [ + { text: 'Utilisation générale', link: '/fr/pages/advanced/headers' }, + { text: 'Méthodes', link: '/fr/pages/advanced/header-methods' }, + ], + }, + { text: 'Adaptateur Fetch 🔥', link: '/fr/pages/advanced/fetch-adapter' }, + { text: 'HTTP2 🔥', link: '/fr/pages/advanced/http2' }, + { text: 'Promesses', link: '/fr/pages/advanced/promises' }, + { text: 'TypeScript', link: '/fr/pages/advanced/type-script' }, + ], + }, + { + text: 'Divers', + items: [ + { text: 'SemVer', link: '/fr/pages/misc/semver' }, + { text: 'Sécurité', link: '/fr/pages/misc/security' }, + ], + }, +]; + +// ─── Config ─────────────────────────────────────────────────────────────────── + export default defineConfig({ - lang: 'en-US', title: 'axios | Promise based HTTP client', description: 'Documentation for the axios HTTP project', head: [ @@ -12,113 +317,46 @@ export default defineConfig({ ['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' }], ['link', { rel: 'manifest', href: '/site.webmanifest' }], ], + locales: { + root: { + label: 'English', + lang: 'en-US', + themeConfig: { + nav: enNav, + sidebar: enSidebar, + }, + }, + zh: { + label: '中文', + lang: 'zh-CN', + themeConfig: { + nav: zhNav, + sidebar: zhSidebar, + }, + }, + es: { + label: 'Español', + lang: 'es-ES', + themeConfig: { + nav: esNav, + sidebar: esSidebar, + }, + }, + fr: { + label: 'Français', + lang: 'fr-FR', + themeConfig: { + nav: frNav, + sidebar: frSidebar, + }, + }, + }, themeConfig: { logo: { dark: '/words.svg', light: '/words-light.svg', }, siteTitle: false, - nav: [ - { text: 'Guide', link: '/pages/getting-started/first-steps' }, - { text: 'API', link: '/pages/advanced/api-reference' }, - { text: 'Sponsors', link: '/pages/misc/sponsors' }, - { text: 'v1.x', link: '#' }, - ], - sidebar: [ - { - text: 'Getting Started', - items: [ - { text: 'First steps', link: '/pages/getting-started/first-steps' }, - { text: 'Features', link: '/pages/getting-started/features' }, - { - text: 'Examples', - items: [ - { - text: 'JavaScript', - link: '/pages/getting-started/examples/commonjs', - }, - { - text: 'TypeScript', - link: '/pages/getting-started/examples/typescript', - }, - ], - }, - { - text: 'Upgrade guide v0.x -> v1.x', - link: '/pages/getting-started/upgrade-guide', - }, - ], - }, - { - text: 'Advanced', - items: [ - { text: 'Public API', link: '/pages/advanced/api-reference' }, - { - text: 'Request method aliases', - link: '/pages/advanced/request-method-aliases', - }, - { - text: 'Creating an instance', - link: '/pages/advanced/create-an-instance', - }, - { text: 'Request config', link: '/pages/advanced/request-config' }, - { text: 'Adapters', link: '/pages/advanced/adapters' }, - { text: 'Response schema', link: '/pages/advanced/response-schema' }, - { text: 'Config defaults', link: '/pages/advanced/config-defaults' }, - { text: 'Interceptors', link: '/pages/advanced/interceptors' }, - { text: 'Error handling', link: '/pages/advanced/error-handling' }, - { text: 'Cancellation', link: '/pages/advanced/cancellation' }, - { text: 'Authentication', link: '/pages/advanced/authentication' }, - { text: 'Retry & error recovery', link: '/pages/advanced/retry' }, - { text: 'Testing', link: '/pages/advanced/testing' }, - { - text: 'x-www-form-urlencoded format', - link: '/pages/advanced/x-www-form-urlencoded-format', - }, - { - text: 'Multipart/form-data format', - link: '/pages/advanced/multipart-form-data-format', - }, - { text: 'File posting', link: '/pages/advanced/file-posting' }, - { - text: 'HTML form processing 🔥', - link: '/pages/advanced/html-form-processing', - }, - { - text: 'Progress capturing 🔥', - link: '/pages/advanced/progress-capturing', - }, - { text: 'Rate limiting 🔥', link: '/pages/advanced/rate-limiting' }, - { - text: 'Headers 🔥', - items: [ - { - text: 'General usage', - link: '/pages/advanced/headers', - }, - { - text: 'Methods', - link: '/pages/advanced/header-methods', - }, - ], - }, - { - text: 'Fetch adapter 🔥', - link: '/pages/advanced/fetch-adapter', - }, - { text: 'HTTP2 🔥', link: '/pages/advanced/http2' }, - { text: 'Promises', link: '/pages/advanced/promises' }, - { text: 'TypeScript', link: '/pages/advanced/type-script' }, - ], - }, - { - text: 'Miscellaneous', - items: [ - { text: 'SemVer', link: '/pages/misc/semver' }, - { text: 'Security', link: '/pages/misc/security' }, - ], - }, - ], socialLinks: [{ icon: 'github', link: 'https://github.com/axios/axios' }], footer: { message: 'axios is provided under MIT license', diff --git a/docs/es/index.md b/docs/es/index.md new file mode 100644 index 0000000..53fd95d --- /dev/null +++ b/docs/es/index.md @@ -0,0 +1,329 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: 'axios docs' + text: 'axios es un cliente HTTP simple para el navegador y Node.js' + image: + dark: /logo.svg + light: /logo-light.svg + alt: axios + actions: + - theme: brand + text: Comenzar + link: /es/pages/getting-started/first-steps + - theme: alt + text: Referencia de API + link: /es/pages/advanced/api-reference + +features: + - title: Implementación sencilla + details: Comenzar con axios es tan simple como una sola línea de código. Las solicitudes API básicas se pueden realizar en 2 líneas de código. + - title: Interceptores potentes + details: Nuestro innovador sistema de interceptores le permite controlar el ciclo de vida de solicitudes y respuestas. Puede modificar solicitudes, respuestas y errores. + - title: Soporte para TypeScript + details: axios declara tipos y tiene soporte completo para TypeScript. Esto significa que puede usar axios con confianza en sus proyectos TypeScript. +--- + + + + +
+

Patrocinadores

+
+
+
+
+
+
+ +
+
+

{{ sponsor.name }}

+
+
+ {{ capitalizeFirstLetter(sponsor.tier) }} +
+
+
+
+ +
+
+
+
+
+ + diff --git a/docs/es/pages/advanced/adapters.md b/docs/es/pages/advanced/adapters.md new file mode 100644 index 0000000..86ace10 --- /dev/null +++ b/docs/es/pages/advanced/adapters.md @@ -0,0 +1,88 @@ +# Adaptadores + +Los adaptadores te permiten personalizar la forma en que axios maneja los datos de la solicitud. De forma predeterminada, axios usa una lista de prioridad ordenada de `['xhr', 'http', 'fetch']` y selecciona el primer adaptador que sea compatible con el entorno actual. En la práctica, esto significa que `xhr` se usa en los navegadores, `http` en Node.js y `fetch` en entornos donde ninguno de los dos está disponible (como Cloudflare Workers o Deno). + +Escribir tu propio adaptador te permite controlar completamente cómo axios realiza una solicitud y procesa la respuesta — útil para pruebas, transportes personalizados o entornos no estándar. + +## Adaptadores integrados + +Puedes seleccionar un adaptador integrado por nombre usando la opción de configuración `adapter`: + +```js +// Use the fetch adapter +const instance = axios.create({ adapter: "fetch" }); + +// Use the XHR adapter (browser default) +const instance = axios.create({ adapter: "xhr" }); + +// Use the HTTP adapter (Node.js default) +const instance = axios.create({ adapter: "http" }); +``` + +También puedes pasar un arreglo de nombres de adaptadores. axios usará el primero que sea compatible con el entorno actual: + +```js +const instance = axios.create({ adapter: ["fetch", "xhr", "http"] }); +``` + +Para más detalles sobre el adaptador `fetch`, consulta la página del [Adaptador Fetch](/pages/advanced/fetch-adapter). + +## Crear un adaptador personalizado + +Para crear un adaptador personalizado, escribe una función que acepte un objeto `config` y devuelva una Promise que se resuelva en un objeto de respuesta de axios válido. + +```js +import axios from "axios"; +import { settle } from "axios/unsafe/core/settle.js"; + +function myAdapter(config) { + /** + * At this point: + * - config has been merged with defaults + * - request transformers have run + * - request interceptors have run + * + * The adapter is now responsible for making the request + * and returning a valid response object. + */ + + return new Promise((resolve, reject) => { + // Perform your custom request logic here. + // This example uses the native fetch API as a starting point. + fetch(config.url, { + method: config.method?.toUpperCase() ?? "GET", + headers: config.headers?.toJSON() ?? {}, + body: config.data, + signal: config.signal, + }) + .then(async (fetchResponse) => { + const responseData = await fetchResponse.text(); + + const response = { + data: responseData, + status: fetchResponse.status, + statusText: fetchResponse.statusText, + headers: Object.fromEntries(fetchResponse.headers.entries()), + config, + request: null, + }; + + // settle resolves or rejects the promise based on the HTTP status + settle(resolve, reject, response); + + /** + * After this point: + * - response transformers will run + * - response interceptors will run + */ + }) + .catch(reject); + }); +} + +const instance = axios.create({ adapter: myAdapter }); +``` + +::: tip +El helper `settle` resuelve la Promise para códigos de estado 2xx y la rechaza para todo lo demás, siguiendo el comportamiento predeterminado de axios. Si deseas una validación de estado personalizada, usa la opción de configuración `validateStatus`. +::: diff --git a/docs/es/pages/advanced/api-reference.md b/docs/es/pages/advanced/api-reference.md new file mode 100644 index 0000000..70e36fe --- /dev/null +++ b/docs/es/pages/advanced/api-reference.md @@ -0,0 +1,331 @@ +# Referencia de la API + +A continuación se presenta una lista de todas las funciones y clases disponibles en el paquete axios. Estas funciones pueden usarse e importarse en tu proyecto. Todas ellas están protegidas por nuestro renovado compromiso de seguir el versionado semántico. Esto significa que puedes confiar en que estas funciones y clases permanecerán estables y sin cambios en futuras versiones, salvo que se realice un cambio de versión mayor. + +## Instancia + +La instancia `axios` es el objeto principal que usarás para realizar solicitudes HTTP. Es una función de fábrica que crea una nueva instancia de la clase `Axios`. La instancia `axios` cuenta con una serie de métodos para hacer solicitudes HTTP, los cuales están documentados en la [sección de alias de solicitud](/pages/advanced/request-method-aliases) de la documentación. + +## Clases + +### `Axios` + +La clase `Axios` es la clase principal que usarás para realizar solicitudes HTTP. Es una función de fábrica que crea una nueva instancia de la clase `Axios`. La clase `Axios` cuenta con una serie de métodos para hacer solicitudes HTTP, los cuales están documentados en la [sección de alias de solicitud](/pages/advanced/request-method-aliases) de la documentación. + +#### `constructor` + +Crea una nueva instancia de la clase `Axios`. El constructor acepta un objeto de configuración opcional como argumento. + +```ts +constructor(instanceConfig?: AxiosRequestConfig); +``` + +#### `request` + +Gestiona la invocación de la solicitud y la resolución de la respuesta. Este es el método principal que usarás para hacer solicitudes HTTP. Acepta un objeto de configuración como argumento y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +request(configOrUrl: string | AxiosRequestConfig, config: AxiosRequestConfig): Promise>; +``` + +### `CancelToken` + +La clase `CancelToken` estaba basada en la propuesta `tc39/proposal-cancelable-promises`. Se usaba para crear un token que permitiera cancelar una solicitud HTTP. La clase `CancelToken` está ahora obsoleta en favor de la API `AbortController`. + +A partir de la versión 0.22.0, la clase `CancelToken` está obsoleta y será eliminada en una versión futura. Se recomienda usar la API `AbortController` en su lugar. + +La clase se exporta principalmente por compatibilidad con versiones anteriores y será eliminada en una versión futura. Desaconsejamos fuertemente su uso en proyectos nuevos, por lo que no documentamos su API. + +## Funciones + +### `AxiosError` + +La clase `AxiosError` es una clase de error que se lanza cuando una solicitud HTTP falla. Extiende la clase `Error` y añade propiedades adicionales al objeto de error. + +#### `constructor` + +Crea una nueva instancia de la clase `AxiosError`. El constructor acepta opcionalmente un mensaje, un código, una configuración, una solicitud y una respuesta como argumentos. + +```ts +constructor(message?: string, code?: string, config?: InternalAxiosRequestConfig, request?: any, response?: AxiosResponse); +``` + +#### `properties` + +La clase `AxiosError` proporciona las siguientes propiedades: + +```ts +// Instancia de configuración. +config?: InternalAxiosRequestConfig; + +// Código de error. +code?: string; + +// Instancia de solicitud. +request?: any; + +// Instancia de respuesta. +response?: AxiosResponse; + +// Booleano que indica si el error es un `AxiosError`. +isAxiosError: boolean; + +// Código de estado HTTP del error. +status?: number; + +// Método auxiliar para convertir el error a un objeto JSON. +toJSON: () => object; + +// Causa del error. +cause?: Error; +``` + +### `AxiosHeaders` + +La clase `AxiosHeaders` es una clase de utilidad que se usa para gestionar encabezados HTTP. Provee métodos para manipular encabezados, como añadir, eliminar y obtener encabezados. + +Aquí solo se documentan los métodos principales. Para una lista completa de métodos, consulta el archivo de declaración de tipos. + +#### `constructor` + +Crea una nueva instancia de la clase `AxiosHeaders`. El constructor acepta opcionalmente un objeto de encabezados como argumento. + +```ts +constructor(headers?: RawAxiosHeaders | AxiosHeaders | string); +``` + +#### `set` + +Agrega un encabezado al objeto de encabezados. + +```ts +set(headerName?: string, value?: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders; +set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders; +``` + +#### `get` + +Obtiene un encabezado del objeto de encabezados. + +```ts +get(headerName: string, parser: RegExp): RegExpExecArray | null; +get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue; +``` + +#### `has` + +Verifica si un encabezado existe en el objeto de encabezados. + +```ts +has(header: string, matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `delete` + +Elimina un encabezado del objeto de encabezados. + +```ts +delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `clear` + +Elimina todos los encabezados del objeto de encabezados. + +```ts +clear(matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `normalize` + +Normaliza el objeto de encabezados. + +```ts +normalize(format: boolean): AxiosHeaders; +``` + +#### `concat` + +Concatena objetos de encabezados. + +```ts +concat(...targets: Array): AxiosHeaders; +``` + +#### `toJSON` + +Convierte el objeto de encabezados a un objeto JSON. + +```ts +toJSON(asStrings?: boolean): RawAxiosHeaders; +``` + +### `CanceledError` + +La clase `CanceledError` es una clase de error que se lanza cuando se cancela una solicitud HTTP. Extiende la clase `AxiosError`. + +### `Cancel` + +La clase `Cancel` es un alias de la clase `CanceledError`. Se exporta por compatibilidad con versiones anteriores y será eliminada en una versión futura. + +### `isCancel` + +Una función que verifica si un error es un `CanceledError`. Es útil para distinguir cancelaciones intencionales de errores inesperados. + +```ts +isCancel(value: any): boolean; +``` + +```js +import axios from "axios"; + +const controller = new AbortController(); + +axios.get("/api/data", { signal: controller.signal }).catch((error) => { + if (axios.isCancel(error)) { + console.log("Request was cancelled:", error.message); + } else { + console.error("Unexpected error:", error); + } +}); + +controller.abort("User navigated away"); +``` + +### `isAxiosError` + +Una función que verifica si un error es un `AxiosError`. Úsala en bloques `catch` para acceder de forma segura a las propiedades específicas de axios como `error.response` y `error.config`. + +```ts +isAxiosError(value: any): value is AxiosError; +``` + +```js +import axios from "axios"; + +try { + await axios.get("/api/resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + // error.response, error.config, error.code are all available + console.error("HTTP error", error.response?.status, error.message); + } else { + // A non-axios error (e.g. a programming mistake) + throw error; + } +} +``` + +### `all` + +La función `all` es una función de utilidad que acepta un arreglo de promises y devuelve una única Promise que se resuelve cuando todas las promises del arreglo se han resuelto. La función `all` está ahora obsoleta en favor del método `Promise.all`. Se recomienda usar el método `Promise.all` en su lugar. + +A partir de la versión 0.22.0, la función `all` está obsoleta y será eliminada en una versión futura. Se recomienda usar el método `Promise.all` en su lugar. + +### `spread` + +La función `spread` es una función de utilidad que puede usarse para distribuir un arreglo de argumentos en una llamada a función. Es útil cuando tienes un arreglo de argumentos que deseas pasar a una función que acepta múltiples argumentos. + +```ts +spread(callback: (...args: T[]) => R): (array: T[]) => R; +``` + +### `toFormData` + +Convierte un objeto JavaScript plano (o anidado) a una instancia de `FormData`. Es útil cuando deseas construir datos de formulario multipart de forma programática a partir de un objeto. + +```ts +toFormData(sourceObj: object, formData?: FormData, options?: FormSerializerOptions): FormData; +``` + +```js +import { toFormData } from "axios"; + +const data = { name: "Jay", avatar: fileBlob }; +const form = toFormData(data); +// form is now a FormData instance ready to post +await axios.post("/api/users", form); +``` + +### `formToJSON` + +Convierte una instancia de `FormData` de vuelta a un objeto JavaScript plano. Es útil para leer datos de formulario en un formato estructurado. + +```ts +formToJSON(form: FormData): object; +``` + +```js +import { formToJSON } from "axios"; + +const form = new FormData(); +form.append("name", "Jay"); +form.append("role", "admin"); + +const obj = formToJSON(form); +console.log(obj); // { name: "Jay", role: "admin" } +``` + +### `getAdapter` + +Resuelve y devuelve una función de adaptador por nombre o pasando un arreglo de nombres candidatos. axios usa esto internamente para seleccionar el mejor adaptador disponible para el entorno actual. + +```ts +getAdapter(adapters: string | string[]): AxiosAdapter; +``` + +```js +import { getAdapter } from "axios"; + +// Get the fetch adapter explicitly +const fetchAdapter = getAdapter("fetch"); + +// Get the best available adapter from a priority list +const adapter = getAdapter(["fetch", "xhr", "http"]); +``` + +### `mergeConfig` + +Combina dos objetos de configuración de axios, aplicando la misma estrategia de fusión profunda que axios usa internamente al combinar los valores predeterminados con las opciones por solicitud. Los valores posteriores tienen precedencia. + +```ts +mergeConfig(config1: AxiosRequestConfig, config2: AxiosRequestConfig): AxiosRequestConfig; +``` + +```js +import { mergeConfig } from "axios"; + +const base = { baseURL: "https://api.example.com", timeout: 5000 }; +const override = { timeout: 10000, headers: { "X-Custom": "value" } }; + +const merged = mergeConfig(base, override); +// { baseURL: "https://api.example.com", timeout: 10000, headers: { "X-Custom": "value" } } +``` + +## Constantes + +### `HttpStatusCode` + +Un objeto que contiene una lista de códigos de estado HTTP como constantes con nombre. Úsalo para escribir condicionales legibles en lugar de números directos. + +```js +import axios, { HttpStatusCode } from "axios"; + +try { + const response = await axios.get("/api/resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + if (error.response?.status === HttpStatusCode.NotFound) { + console.error("Resource not found"); + } else if (error.response?.status === HttpStatusCode.Unauthorized) { + console.error("Authentication required"); + } + } +} +``` + +## Miscelánea + +### `VERSION` + +La versión actual del paquete `axios`. Es una cadena que representa el número de versión del paquete. Se actualiza con cada nueva versión del paquete. diff --git a/docs/es/pages/advanced/authentication.md b/docs/es/pages/advanced/authentication.md new file mode 100644 index 0000000..7a2248a --- /dev/null +++ b/docs/es/pages/advanced/authentication.md @@ -0,0 +1,142 @@ +# Autenticación + +La mayoría de las APIs requieren alguna forma de autenticación. Esta página cubre los patrones más comunes para adjuntar credenciales a las solicitudes de axios. + +## Tokens Bearer (JWT) + +El enfoque más común es adjuntar un JWT en el encabezado `Authorization`. La forma más limpia de hacerlo es a través de un interceptor de solicitud en tu instancia de axios, de manera que el token se lea de nuevo en cada solicitud: + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +api.interceptors.request.use((config) => { + const token = localStorage.getItem("access_token"); + if (token) { + config.headers.set("Authorization", `Bearer ${token}`); + } + return config; +}); +``` + +## Autenticación HTTP Basic + +Para APIs que usan autenticación HTTP Basic, pasa la opción `auth`. axios codificará las credenciales y establecerá el encabezado `Authorization` automáticamente: + +```js +const response = await axios.get("https://api.example.com/data", { + auth: { + username: "myUser", + password: "myPassword", + }, +}); +``` + +::: tip +Para tokens Bearer y claves de API, usa un encabezado `Authorization` personalizado en lugar de la opción `auth` — `auth` es solo para HTTP Basic. +::: + +## Claves de API + +Las claves de API generalmente se pasan como un encabezado o como un parámetro de consulta, dependiendo de lo que espere la API: + +```js +// As a header +const api = axios.create({ + baseURL: "https://api.example.com", + headers: { "X-API-Key": "your-api-key-here" }, +}); + +// As a query parameter +const response = await axios.get("https://api.example.com/data", { + params: { apiKey: "your-api-key-here" }, +}); +``` + +## Renovación de token + +Cuando los tokens de acceso expiran, es necesario renovarlos de forma silenciosa y reintentar la solicitud fallida. Un interceptor de respuesta es el lugar adecuado para implementar esto: + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +// Track whether a refresh is already in progress to avoid parallel refresh calls +let isRefreshing = false; +let failedQueue = []; + +const processQueue = (error, token = null) => { + failedQueue.forEach((prom) => { + if (error) { + prom.reject(error); + } else { + prom.resolve(token); + } + }); + failedQueue = []; +}; + +api.interceptors.response.use( + (response) => response, + async (error) => { + const originalRequest = error.config; + + if (error.response?.status === 401 && !originalRequest._retry) { + if (isRefreshing) { + // Queue the request until the refresh completes + return new Promise((resolve, reject) => { + failedQueue.push({ resolve, reject }); + }) + .then((token) => { + originalRequest.headers["Authorization"] = `Bearer ${token}`; + return api(originalRequest); + }) + .catch((err) => Promise.reject(err)); + } + + originalRequest._retry = true; + isRefreshing = true; + + try { + const { data } = await axios.post("/auth/refresh", { + refreshToken: localStorage.getItem("refresh_token"), + }); + + const newToken = data.access_token; + localStorage.setItem("access_token", newToken); + api.defaults.headers.common["Authorization"] = `Bearer ${newToken}`; + + processQueue(null, newToken); + return api(originalRequest); + } catch (refreshError) { + processQueue(refreshError, null); + // Redirect to login or emit an event + localStorage.removeItem("access_token"); + window.location.href = "/login"; + return Promise.reject(refreshError); + } finally { + isRefreshing = false; + } + } + + return Promise.reject(error); + } +); +``` + +## Autenticación basada en cookies + +Para APIs basadas en sesiones que dependen de cookies, establece `withCredentials: true` para incluir cookies en solicitudes de origen cruzado: + +```js +const api = axios.create({ + baseURL: "https://api.example.com", + withCredentials: true, // send cookies with every request +}); +``` + +::: warning +`withCredentials: true` requiere que el servidor responda con `Access-Control-Allow-Credentials: true` y un valor específico (no comodín) en `Access-Control-Allow-Origin`. +::: diff --git a/docs/es/pages/advanced/cancellation.md b/docs/es/pages/advanced/cancellation.md new file mode 100644 index 0000000..8ef674c --- /dev/null +++ b/docs/es/pages/advanced/cancellation.md @@ -0,0 +1,70 @@ +# Cancelación + +A partir de la versión v0.22.0, Axios es compatible con AbortController para cancelar solicitudes de forma limpia. Esta característica está disponible en el navegador y en Node.js cuando se usa una versión de Axios que admite AbortController. Para cancelar una solicitud, debes crear una instancia de `AbortController` y pasar su `signal` a la opción `signal` de la solicitud. + +```js +const controller = new AbortController(); + +axios + .get("/foo/bar", { + signal: controller.signal, + }) + .then(function (response) { + //... + }); +// cancel the request +controller.abort(); +``` + +## CancelToken + +También puedes usar la API `CancelToken` para cancelar solicitudes. Esta API está obsoleta y será eliminada en la próxima versión mayor. Se recomienda usar `AbortController` en su lugar. Puedes crear un token de cancelación usando la fábrica `CancelToken.source` como se muestra a continuación: + +```js +const CancelToken = axios.CancelToken; +const source = CancelToken.source(); + +axios + .get("/user/12345", { + cancelToken: source.token, + }) + .catch(function (thrown) { + if (axios.isCancel(thrown)) { + console.log("Request canceled", thrown.message); + } else { + // handle error + } + }); + +axios.post( + "/user/12345", + { + name: "new name", + }, + { + cancelToken: source.token, + } +); + +// cancel the request (the message parameter is optional) +source.cancel("Operation canceled by the user."); +``` + +También puedes crear un token de cancelación pasando una función ejecutora al constructor de `CancelToken`: + +```js +const CancelToken = axios.CancelToken; +let cancel; + +axios.get("/user/12345", { + cancelToken: new CancelToken(function executor(c) { + // An executor function receives a cancel function as a parameter + cancel = c; + }), +}); + +// cancel the request +cancel(); +``` + +Puedes cancelar varias solicitudes con el mismo token de cancelación o controlador de cancelación. Si un token de cancelación ya fue cancelado en el momento en que se inicia una solicitud de Axios, la solicitud se cancela inmediatamente, sin intentar realizar ninguna solicitud real. diff --git a/docs/es/pages/advanced/config-defaults.md b/docs/es/pages/advanced/config-defaults.md new file mode 100644 index 0000000..ef1e7ec --- /dev/null +++ b/docs/es/pages/advanced/config-defaults.md @@ -0,0 +1,48 @@ +# Valores predeterminados de configuración + +axios te permite especificar valores predeterminados de configuración que se aplicarán a cada solicitud. Puedes definir valores predeterminados para `baseURL`, `headers`, `timeout` y otras propiedades. A continuación se muestra un ejemplo de cómo usar los valores predeterminados de configuración: + +```js +axios.defaults.baseURL = "https://jsonplaceholder.typicode.com/posts"; +axios.defaults.headers.common["Authorization"] = AUTH_TOKEN; +axios.defaults.headers.post["Content-Type"] = + "application/x-www-form-urlencoded"; +``` + +## Valores predeterminados personalizados por instancia + +Las instancias de axios se declaran con sus propios valores predeterminados al ser creadas. Estos valores pueden sobreescribirse estableciendo la propiedad `defaults` en la instancia. A continuación se muestra un ejemplo de cómo usar valores predeterminados personalizados por instancia: + +```js +var instance = axios.create({ + baseURL: "https://jsonplaceholder.typicode.com/posts", + timeout: 1000, + headers: { Authorization: "foobar" }, +}); + +instance.defaults.headers.common["Authorization"] = AUTH_TOKEN; +``` + +## Orden de precedencia de la configuración + +La configuración se combinará con un orden de precedencia. El orden es el siguiente: primero se establecen los valores predeterminados de la librería, luego las propiedades predeterminadas de la instancia y, finalmente, el argumento de configuración de la solicitud. A continuación se muestra un ejemplo del orden de precedencia. + +Primero, vamos a crear una instancia con los valores predeterminados que proporciona la librería. En este punto, el valor de configuración de timeout es `0`, que es el valor predeterminado de la librería. + +```js +const instance = axios.create(); +``` + +Ahora sobreescribiremos el timeout predeterminado de la instancia a `2500` milisegundos. A partir de ahora, todas las solicitudes que usen esta instancia esperarán 2.5 segundos antes de expirar. + +```js +instance.defaults.timeout = 2500; +``` + +Finalmente, haremos una solicitud con un timeout de `5000` milisegundos. Esta solicitud esperará 5 segundos antes de expirar. + +```js +instance.get("/longRequest", { + timeout: 5000, +}); +``` diff --git a/docs/es/pages/advanced/create-an-instance.md b/docs/es/pages/advanced/create-an-instance.md new file mode 100644 index 0000000..5e462e4 --- /dev/null +++ b/docs/es/pages/advanced/create-an-instance.md @@ -0,0 +1,87 @@ +# Crear una instancia + +`axios.create()` te permite crear una instancia de axios preconfigurada. La instancia comparte la misma API de solicitud y respuesta que el objeto `axios` predeterminado, pero utiliza la configuración que proporciones como base para cada solicitud. Esta es la forma recomendada de usar axios en cualquier aplicación que conste de más de un solo archivo. + +```ts +import axios from "axios"; + +const instance = axios.create({ + baseURL: "https://api.example.com", + timeout: 5000, + headers: { "X-Custom-Header": "foobar" }, +}); +``` + +El método `create` acepta el objeto completo de [Configuración de solicitud](/pages/advanced/request-config). Luego puedes usar la instancia igual que el objeto axios predeterminado: + +```js +const response = await instance.get("/users/1"); +``` + +## ¿Por qué usar una instancia? + +### URL base por servicio + +En la mayoría de las aplicaciones se interactúa con más de una API. Crear una instancia separada por servicio evita repetir la URL base en cada llamada: + +```js +const githubApi = axios.create({ baseURL: "https://api.github.com" }); +const internalApi = axios.create({ baseURL: "https://api.internal.example.com" }); + +const { data: repos } = await githubApi.get("/users/axios/repos"); +const { data: users } = await internalApi.get("/users"); +``` + +### Encabezados de autenticación compartidos + +Adjunta un token de autenticación a cada solicitud de una instancia sin afectar a las demás: + +```js +const authApi = axios.create({ + baseURL: "https://api.example.com", + headers: { + Authorization: `Bearer ${getToken()}`, + }, +}); +``` + +### Tiempos de espera y reintentos por servicio + +Los distintos servicios tienen características de fiabilidad diferentes. Define un tiempo de espera corto para servicios en tiempo real y uno más largo para trabajos por lotes: + +```js +const realtimeApi = axios.create({ baseURL: "https://realtime.example.com", timeout: 2000 }); +const batchApi = axios.create({ baseURL: "https://batch.example.com", timeout: 60000 }); +``` + +### Interceptores aislados + +Los interceptores añadidos a una instancia solo se aplican a esa instancia, manteniendo tus responsabilidades separadas: + +```js +const loggingApi = axios.create({ baseURL: "https://api.example.com" }); + +loggingApi.interceptors.request.use((config) => { + console.log(`→ ${config.method?.toUpperCase()} ${config.url}`); + return config; +}); +``` + +## Sobreescribir los valores predeterminados por solicitud + +La configuración pasada en el momento de la solicitud siempre tiene prioridad sobre los valores predeterminados de la instancia: + +```js +const api = axios.create({ timeout: 5000 }); + +// This specific request uses a 30-second timeout instead +await api.get("/slow-endpoint", { timeout: 30000 }); +``` + +::: tip +Los valores predeterminados de la instancia también pueden cambiarse después de su creación escribiendo en `instance.defaults`: + +```js +instance.defaults.headers.common["Authorization"] = `Bearer ${newToken}`; +``` +::: diff --git a/docs/es/pages/advanced/error-handling.md b/docs/es/pages/advanced/error-handling.md new file mode 100644 index 0000000..7822e41 --- /dev/null +++ b/docs/es/pages/advanced/error-handling.md @@ -0,0 +1,72 @@ +# Manejo de errores + +axios puede lanzar muchos tipos diferentes de errores. Algunos de estos errores son causados por el propio axios, mientras que otros son causados por el servidor o el cliente. La siguiente tabla lista la estructura general del error lanzado: + +| Propiedad | Definición | +| --------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| message | Un resumen rápido del mensaje de error y el estado con el que falló. | +| name | Define el origen del error. Para axios, siempre será un `AxiosError`. | +| stack | Proporciona el seguimiento de la pila (stack trace) del error. | +| config | Un objeto de configuración de axios con configuraciones específicas de la instancia definidas por el usuario al momento de realizar la solicitud. | +| code | Representa un error identificado por axios. La tabla a continuación lista definiciones específicas para errores internos de axios. | +| status | Código de estado HTTP de la respuesta. Consulta [aquí](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) para conocer los significados comunes de los códigos de estado HTTP. | + +A continuación se lista una relación de posibles errores identificados por axios: + +| Código | Definición | +| ------------------------- | --------------------------------------------------------------------------------------------- | +| ERR_BAD_OPTION_VALUE | Valor inválido o no compatible proporcionado en la configuración de axios. | +| ERR_BAD_OPTION | Opción inválida proporcionada en la configuración de axios. | +| ECONNABORTED | Generalmente indica que la solicitud ha expirado (salvo que `transitional.clarifyTimeoutError` esté activado) o fue abortada por el navegador o un complemento del mismo. | +| ETIMEDOUT | La solicitud expiró al superar el límite de tiempo predeterminado de axios. Se debe activar `transitional.clarifyTimeoutError` en `true`, de lo contrario se lanzará un error genérico `ECONNABORTED`. | +| ERR_NETWORK | Problema relacionado con la red. En el navegador, este error también puede ser causado por una violación de la política [CORS](https://developer.mozilla.org/ru/docs/Web/HTTP/Guides/CORS) o [Mixed Content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content). El navegador no permite que el código JS aclare la razón real del error por motivos de seguridad; por eso, revisa la consola. | +| ERR_FR_TOO_MANY_REDIRECTS | La solicitud fue redirigida demasiadas veces; supera el número máximo de redirecciones especificado en la configuración de axios. | +| ERR_DEPRECATED | Se usó una característica o método obsoleto en axios. | +| ERR_BAD_RESPONSE | La respuesta no puede ser analizada correctamente o tiene un formato inesperado. Generalmente relacionado con una respuesta con código de estado `5xx`. | +| ERR_BAD_REQUEST | La solicitud tiene un formato inesperado o le faltan parámetros requeridos. Generalmente relacionado con una respuesta con código de estado `4xx`. | +| ERR_CANCELED | La característica o método fue cancelado explícitamente por el usuario usando un AbortSignal (o un CancelToken). | +| ERR_NOT_SUPPORT | Característica o método no compatible en el entorno actual de axios. | +| ERR_INVALID_URL | URL inválida proporcionada para la solicitud de axios. | + +## Manejo de errores + +El comportamiento predeterminado de axios es rechazar la Promise si la solicitud falla. Sin embargo, también puedes capturar el error y manejarlo según lo consideres apropiado. A continuación se muestra un ejemplo de cómo capturar un error: + +```js +axios.get("/user/12345").catch(function (error) { + if (error.response) { + // The request was made and the server responded with a status code + // that falls out of the range of 2xx + console.log(error.response.data); + console.log(error.response.status); + console.log(error.response.headers); + } else if (error.request) { + // The request was made but no response was received + // `error.request` is an instance of XMLHttpRequest in the browser and an instance of + // http.ClientRequest in node.js + console.log(error.request); + } else { + // Something happened in setting up the request that triggered an Error + console.log("Error", error.message); + } + console.log(error.config); +}); +``` + +Usando la opción de configuración `validateStatus`, puedes sobreescribir la condición predeterminada (status >= 200 && status < 300) y definir los códigos HTTP que deben lanzar un error. + +```js +axios.get("/user/12345", { + validateStatus: function (status) { + return status < 500; // Resolve only if the status code is less than 500 + }, +}); +``` + +Usando el método `toJSON`, puedes obtener un objeto con más información sobre el error. + +```js +axios.get("/user/12345").catch(function (error) { + console.log(error.toJSON()); +}); +``` diff --git a/docs/es/pages/advanced/fetch-adapter.md b/docs/es/pages/advanced/fetch-adapter.md new file mode 100644 index 0000000..c548d70 --- /dev/null +++ b/docs/es/pages/advanced/fetch-adapter.md @@ -0,0 +1,81 @@ +# Adaptador Fetch + +El adaptador `fetch` es un nuevo adaptador que introdujimos a partir de la versión 1.7.0. Proporciona una forma de usar axios con la API `fetch`, dándote lo mejor de ambos mundos. De forma predeterminada, `fetch` se usará si los adaptadores `xhr` y `http` no están disponibles en la compilación o no son compatibles con el entorno. Para usarlo de forma predeterminada, debe seleccionarse explícitamente estableciendo la opción `adapter` en `fetch` al crear una instancia de axios. + +```js +import axios from 'axios'; + +const instance = axios.create({ + adapter: 'fetch', +}); +``` + +El adaptador admite la misma funcionalidad que el adaptador `xhr`, incluyendo la captura del progreso de carga y descarga. También admite tipos de respuesta adicionales como `stream` y `formdata` (si el entorno lo soporta). + +## Fetch personalizado + +A partir de `v1.12.0`, puedes personalizar el adaptador fetch para que use una función `fetch` personalizada en lugar de la global del entorno. Puedes pasar una función `fetch` personalizada, y los constructores `Request` y `Response` a través de la opción de configuración `env`. Esto es útil cuando trabajas con entornos personalizados o frameworks de aplicación que proporcionan su propia implementación de `fetch`. + +::: info +Al usar una función `fetch` personalizada, es posible que también necesites proporcionar constructores `Request` y `Response` correspondientes. Si los omites, se usarán los constructores globales. Si tu `fetch` personalizado es incompatible con los globales, pasa `null` para deshabilitarlos. + +**Nota:** Establecer `Request` y `Response` en `null` hará imposible que el adaptador fetch capture el progreso de carga y descarga. +::: + +### Ejemplo básico + +```js +import customFetchFunction from 'customFetchModule'; + +const instance = axios.create({ + adapter: 'fetch', + onDownloadProgress(e) { + console.log('downloadProgress', e); + }, + env: { + fetch: customFetchFunction, + Request: null, // null -> disable the constructor + Response: null, + }, +}); +``` + +### Usando con Tauri + +[Tauri](https://tauri.app/plugin/http-client/) proporciona una función `fetch` de plataforma que omite las restricciones CORS del navegador para las solicitudes realizadas desde la capa nativa. El ejemplo a continuación muestra una configuración mínima para usar axios dentro de una aplicación Tauri con ese fetch personalizado. + +```js +import { fetch } from '@tauri-apps/plugin-http'; +import axios from 'axios'; + +const instance = axios.create({ + adapter: 'fetch', + onDownloadProgress(e) { + console.log('downloadProgress', e); + }, + env: { + fetch, + }, +}); + +const { data } = await instance.get('https://google.com'); +``` + +### Usando con SvelteKit + +[SvelteKit](https://svelte.dev/docs/kit/web-standards#Fetch-APIs) proporciona una implementación personalizada de `fetch` para las funciones `load` del lado del servidor que gestiona el reenvío de cookies y URLs relativas. Dado que su `fetch` es incompatible con la API estándar de `URL`, axios debe configurarse para usarlo explícitamente, y los constructores globales `Request` y `Response` deben deshabilitarse. + +```js +export async function load({ fetch }) { + const { data: post } = await axios.get('https://jsonplaceholder.typicode.com/posts/1', { + adapter: 'fetch', + env: { + fetch, + Request: null, + Response: null, + }, + }); + + return { post }; +} +``` diff --git a/docs/es/pages/advanced/file-posting.md b/docs/es/pages/advanced/file-posting.md new file mode 100644 index 0000000..b03189d --- /dev/null +++ b/docs/es/pages/advanced/file-posting.md @@ -0,0 +1,99 @@ +# Publicación de archivos + +axios facilita la subida de archivos. Usa `postForm` o `FormData` cuando necesites subidas en formato `multipart/form-data`. + +## Archivo único (navegador) + +Pasa un objeto `File` directamente como valor de campo — axios lo detectará y usará automáticamente el tipo de contenido correcto: + +```js +await axios.postForm("https://httpbin.org/post", { + description: "My profile photo", + file: document.querySelector("#fileInput").files[0], +}); +``` + +## Múltiples archivos (navegador) + +Pasa un `FileList` para subir todos los archivos seleccionados a la vez. Todos se enviarán bajo el mismo nombre de campo (`files[]`): + +```js +await axios.postForm( + "https://httpbin.org/post", + document.querySelector("#fileInput").files +); +``` + +Para usar nombres de campo distintos para cada archivo, construye un objeto `FormData` manualmente: + +```js +const formData = new FormData(); +formData.append("avatar", avatarFile); +formData.append("cover", coverFile); + +await axios.post("https://httpbin.org/post", formData); +``` + +## Seguimiento del progreso de la carga (navegador) + +Usa el callback `onUploadProgress` para mostrar una barra de progreso o un porcentaje a tus usuarios: + +```js +await axios.postForm("https://httpbin.org/post", { + file: document.querySelector("#fileInput").files[0], +}, { + onUploadProgress: (progressEvent) => { + const percent = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log(`Upload progress: ${percent}%`); + }, +}); +``` + +Consulta [Captura de progreso](/pages/advanced/progress-capturing) para ver la lista completa de campos disponibles en el evento de progreso. + +## Archivos en Node.js + +En Node.js, usa `fs.createReadStream` para subir un archivo desde el sistema de archivos sin cargarlo completamente en memoria: + +```js +import fs from "fs"; +import FormData from "form-data"; +import axios from "axios"; + +const form = new FormData(); +form.append("file", fs.createReadStream("/path/to/file.jpg")); +form.append("description", "My uploaded file"); + +await axios.post("https://httpbin.org/post", form); +``` + +::: tip +El paquete npm `form-data` es necesario en entornos Node.js para crear objetos `FormData`. En versiones modernas de Node.js (v18+), el `FormData` global está disponible de forma nativa. +::: + +## Subir un Buffer (Node.js) + +También puedes subir un `Buffer` en memoria directamente: + +```js +const buffer = Buffer.from("Hello, world!"); + +const form = new FormData(); +form.append("file", buffer, { + filename: "hello.txt", + contentType: "text/plain", + knownLength: buffer.length, +}); + +await axios.post("https://httpbin.org/post", form); +``` + +::: warning +La captura del progreso de carga de `FormData` no está disponible actualmente en entornos Node.js. +::: + +::: danger +Al subir un stream legible en Node.js, establece `maxRedirects: 0` para evitar que el paquete `follow-redirects` almacene todo el stream en memoria RAM. +::: diff --git a/docs/es/pages/advanced/header-methods.md b/docs/es/pages/advanced/header-methods.md new file mode 100644 index 0000000..b197651 --- /dev/null +++ b/docs/es/pages/advanced/header-methods.md @@ -0,0 +1,188 @@ +# Métodos de encabezados + +Con la introducción de la nueva clase `AxiosHeaders`, Axios ofrece un conjunto de métodos para manipular encabezados. Estos métodos se usan para establecer, obtener y eliminar encabezados de una forma más conveniente que manipular directamente el objeto de encabezados. + +## Constructor `new AxiosHeaders(headers?)` + +El constructor de la clase `AxiosHeaders` acepta un objeto opcional con encabezados para inicializar la instancia. El objeto de encabezados puede contener cualquier número de encabezados, y las claves son insensibles a mayúsculas y minúsculas. + +```js +constructor(headers?: RawAxiosHeaders | AxiosHeaders | string); +``` + +Por conveniencia, puedes pasar una cadena de texto con encabezados separados por un carácter de nueva línea. Los encabezados se analizan y se añaden a la instancia. + +```js +const headers = new AxiosHeaders(` +Host: www.bing.com +User-Agent: curl/7.54.0 +Accept: */*`); + +console.log(headers); + +// Object [AxiosHeaders] { +// host: 'www.bing.com', +// 'user-agent': 'curl/7.54.0', +// accept: '*/*' +// } +``` + +## Set (Establecer) + +El método `set` se usa para establecer encabezados en la instancia de `AxiosHeaders`. El método puede ser llamado con un nombre de encabezado y un valor únicos, un objeto con múltiples encabezados, o una cadena de texto con encabezados separados por una nueva línea. El método también acepta un parámetro opcional `rewrite` que controla el comportamiento al establecer el encabezado. + +```js +set(headerName, value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher); +set(headerName, value, rewrite?: (this: AxiosHeaders, value: string, name: string) => boolean); +set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean); +``` + +El argumento `rewrite` controla el comportamiento de sobreescritura: + +- `false` - no sobreescribir si el valor del encabezado ya está definido (es decir, no es `undefined`) +- `undefined` (predeterminado) - sobreescribir el encabezado a menos que su valor esté establecido en `false` +- `true` - sobreescribir siempre + +La opción también puede aceptar una función definida por el usuario que determina si el valor debe ser sobreescrito o no. La función recibe el valor actual, el nombre del encabezado y el objeto de encabezados como argumentos. + +`AxiosHeaders` conserva el formato de la primera clave coincidente que encuentra. Puedes usar esto para preservar el formato específico de un encabezado inicializando una clave con `undefined` y luego estableciendo los valores posteriormente. Consulta [Preservar el formato de un encabezado específico](/pages/advanced/headers#preserving-a-specific-header-case). + +## Get (Obtener) + +El método `get` se usa para recuperar el valor de un encabezado. El método puede ser llamado con un nombre de encabezado único, un matcher opcional o un parser. El matcher tiene valor predeterminado `true`. El parser puede ser una expresión regular que se usa para extraer el valor del encabezado. + +```js +get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue; +get(headerName: string, parser: RegExp): RegExpExecArray | null; +``` + +A continuación se muestra un ejemplo de algunos de los posibles usos del método `get`: + +```js +const headers = new AxiosHeaders({ + 'Content-Type': 'multipart/form-data; boundary=Asrf456BGe4h', +}); + +console.log(headers.get('Content-Type')); +// multipart/form-data; boundary=Asrf456BGe4h + +console.log(headers.get('Content-Type', true)); // parse key-value pairs from a string separated with \s,;= delimiters: +// [Object: null prototype] { +// 'multipart/form-data': undefined, +// boundary: 'Asrf456BGe4h' +// } + +console.log( + headers.get('Content-Type', (value, name, headers) => { + return String(value).replace(/a/g, 'ZZZ'); + }) +); +// multipZZZrt/form-dZZZtZZZ; boundZZZry=Asrf456BGe4h + +console.log(headers.get('Content-Type', /boundary=(\w+)/)?.[0]); +// boundary=Asrf456BGe4h +``` + +## Has (Verificar existencia) + +El método `has` se usa para verificar si un encabezado existe en la instancia de `AxiosHeaders`. El método puede ser llamado con un nombre de encabezado único y un matcher opcional. + +```js +has(header: string, matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +Devuelve `true` si el encabezado está definido (tiene un valor que no es `undefined`). +::: + +## Delete (Eliminar) + +El método `delete` se usa para eliminar un encabezado de la instancia de `AxiosHeaders`. El método puede ser llamado con un nombre de encabezado único y un matcher opcional. + +```js +delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +Devuelve `true` si al menos un encabezado fue eliminado. +::: + +## Clear (Limpiar) + +El método `clear` se usa para eliminar todos los encabezados de la instancia de `AxiosHeaders` si no se pasa ningún argumento. Si se pasa un matcher, solo se eliminan los encabezados que coincidan con él; en este caso, el matcher se compara contra el nombre del encabezado en lugar del valor. + +```js +clear(matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +Devuelve `true` si al menos un encabezado fue eliminado. +::: + +## Normalize (Normalizar) + +Si el objeto de encabezados fue modificado directamente, puede generar duplicados con el mismo nombre pero en diferentes formatos. Este método normaliza el objeto de encabezados combinando claves duplicadas en una sola. Axios usa este método internamente después de llamar a cada interceptor. Establece `format` en `true` para convertir los nombres de los encabezados a minúsculas y capitalizar las letras iniciales (`cOntEnt-type` => `Content-Type`) o en `false` para mantener el formato original. + +```js +const headers = new AxiosHeaders({ + foo: '1', +}); + +headers.Foo = '2'; +headers.FOO = '3'; + +console.log(headers.toJSON()); // [Object: null prototype] { foo: '1', Foo: '2', FOO: '3' } +console.log(headers.normalize().toJSON()); // [Object: null prototype] { foo: '3' } +console.log(headers.normalize(true).toJSON()); // [Object: null prototype] { Foo: '3' } +``` + +::: info +Devuelve `this` para encadenamiento. +::: + +## Concat (Concatenar) + +Combina la instancia con los objetivos en una nueva instancia de `AxiosHeaders`. Si el objetivo es una cadena de texto, se analizará como encabezados HTTP en formato RAW. Si el objetivo es una instancia de `AxiosHeaders`, se combinará con la instancia actual. + +Esto es útil para formatos predefinidos de mayúsculas/minúsculas al componer encabezados. Por ejemplo: + +```js +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); +``` + +```js +concat(...targets: Array): AxiosHeaders; +``` + +::: info +Devuelve una nueva instancia de `AxiosHeaders`. +::: + +## toJSON + +Resuelve todos los valores de encabezados internos en un nuevo objeto de prototipo nulo. Establece `asStrings` en `true` para resolver los arreglos como una cadena que contiene todos los elementos, separados por comas. + +```js +toJSON(asStrings?: boolean): RawAxiosHeaders; +``` + +## From (Desde) + +Devuelve una nueva instancia de `AxiosHeaders` creada a partir de los encabezados en bruto pasados, o simplemente devuelve el objeto de encabezados dado si ya es una instancia de `AxiosHeaders`. + +```js +from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders; +``` + +## Atajos + +Los siguientes atajos están disponibles: + +- `setContentType`, `getContentType`, `hasContentType` +- `setContentLength`, `getContentLength`, `hasContentLength` +- `setAccept`, `getAccept`, `hasAccept` +- `setUserAgent`, `getUserAgent`, `hasUserAgent` +- `setContentEncoding`, `getContentEncoding`, `hasContentEncoding` diff --git a/docs/es/pages/advanced/headers.md b/docs/es/pages/advanced/headers.md new file mode 100644 index 0000000..ce4037d --- /dev/null +++ b/docs/es/pages/advanced/headers.md @@ -0,0 +1,153 @@ +# Encabezados + +Axios expone su propia clase `AxiosHeaders` para manipular encabezados usando una API similar a Map que garantiza claves insensibles a mayúsculas y minúsculas. Esta clase es usada internamente por Axios para gestionar encabezados, pero también está disponible para el usuario por conveniencia. Aunque los encabezados HTTP no son sensibles a mayúsculas y minúsculas, Axios conservará el formato original del encabezado por razones estéticas y como solución alternativa cuando los servidores consideran erróneamente el caso del encabezado. La forma antigua de manipular directamente el objeto de encabezados sigue disponible, pero está obsoleta y no se recomienda para uso futuro. + +## Trabajar con encabezados + +La instancia del objeto `AxiosHeaders` puede contener diferentes tipos de valores internos que controlan la lógica de configuración y combinación. El objeto de encabezados final es obtenido por Axios mediante la llamada al método `toJSON`. El objeto `AxiosHeaders` también es iterable, por lo que puedes usarlo en bucles o convertirlo en un arreglo u objeto. + +Los valores de los encabezados pueden ser de los siguientes tipos: + +- `string` - valor de cadena de texto normal que se enviará al servidor +- `null` - omitir el encabezado al convertir a JSON +- `false` - omitir el encabezado al convertir a JSON; indica además que el método `set` debe ser llamado con la opción `rewrite` en `true` para sobreescribir este valor (Axios usa esto internamente para permitir que los usuarios opten por no instalar ciertos encabezados como `User-Agent` o `Content-Type`) +- `undefined` - el valor no está definido + +::: warning +El valor del encabezado se considera definido si no es `undefined`. +::: + +El objeto de encabezados siempre se inicializa dentro de los interceptores y transformadores, como se muestra en el siguiente ejemplo: + +```js +axios.interceptors.request.use((request: InternalAxiosRequestConfig) => { + request.headers.set("My-header", "value"); + + request.headers.set({ + "My-set-header1": "my-set-value1", + "My-set-header2": "my-set-value2", + }); + + // Disable subsequent setting of this header by Axios + request.headers.set("User-Agent", false); + + request.headers.setContentType("text/plain"); + + // Direct access like this is deprecated + request.headers["My-set-header2"] = "newValue"; + + return request; +}); +``` + +Puedes iterar sobre un `AxiosHeaders` usando cualquier método iterable, como un bucle for-of, forEach o el operador spread: + +```js +const headers = new AxiosHeaders({ + foo: '1', + bar: '2', + baz: '3', +}); + +for (const [header, value] of headers) { + console.log(header, value); +} + +// foo 1 +// bar 2 +// baz 3 +``` + +## Establecer encabezados en una solicitud + +El lugar más común para establecer encabezados es la opción `headers` en la configuración de tu solicitud o en la configuración de la instancia: + +```js +// On a single request +await axios.get('/api/data', { + headers: { + 'Accept-Language': 'en-US', + 'X-Request-ID': 'abc123', + }, +}); + +// On an instance (applied to every request) +const api = axios.create({ + headers: { + 'X-App-Version': '2.0.0', + }, +}); +``` + +## Preservar el formato de un encabezado específico + +Los nombres de encabezados de Axios son insensibles a mayúsculas y minúsculas, pero `AxiosHeaders` conserva el formato de la primera clave coincidente que encuentra. Si necesitas un formato específico para un servidor con comportamiento sensible a mayúsculas y minúsculas no estándar, define un formato predeterminado en `defaults` y luego establece los valores normalmente. + +```js +const api = axios.create(); + +api.defaults.headers.common = { + 'content-type': undefined, + accept: undefined, +}; + +await api.put(url, data, { + headers: { + 'Content-Type': 'application/octet-stream', + Accept: 'application/json', + }, +}); +``` + +También puedes hacerlo directamente con `AxiosHeaders` al componer encabezados: + +```js +import axios, { AxiosHeaders } from 'axios'; + +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); + +await axios.put(url, data, { headers }); +``` + +## Establecer encabezados en un interceptor + +Los interceptores son el lugar adecuado para adjuntar encabezados dinámicos como tokens de autenticación, ya que el token puede no estar disponible cuando la instancia se crea por primera vez: + +```js +api.interceptors.request.use((config) => { + const token = getAuthToken(); // read at request time + config.headers.set('Authorization', `Bearer ${token}`); + return config; +}); +``` + +## Leer encabezados de respuesta + +Los encabezados de respuesta están disponibles en `response.headers` como una instancia de `AxiosHeaders`. Todos los nombres de encabezados están en minúsculas: + +```js +const response = await axios.get('/api/data'); + +console.log(response.headers['content-type']); +// application/json; charset=utf-8 + +console.log(response.headers.get('x-request-id')); +// abc123 +``` + +## Eliminar un encabezado predeterminado + +Para optar por no incluir un encabezado que axios establece por defecto (como `Content-Type` o `User-Agent`), establece su valor en `false`: + +```js +await axios.post('/api/data', payload, { + headers: { + 'Content-Type': false, // let the browser set it automatically (e.g. for FormData) + }, +}); +``` + +Para más detalles sobre la API completa de métodos de `AxiosHeaders`, consulta la página de [Métodos de encabezados](/pages/advanced/header-methods). diff --git a/docs/es/pages/advanced/html-form-processing.md b/docs/es/pages/advanced/html-form-processing.md new file mode 100644 index 0000000..6bed349 --- /dev/null +++ b/docs/es/pages/advanced/html-form-processing.md @@ -0,0 +1,57 @@ +# Envío de formularios HTML (navegador) + +También puedes enviar un formulario directamente desde un elemento de formulario HTML. Esto es útil cuando tienes un formulario en tu página y deseas enviarlo sin escribir código JavaScript adicional. + +```js +await axios.postForm('https://httpbin.org/post', document.querySelector('#htmlForm')); +``` + +Los objetos `FormData` y `HTMLForm` también pueden enviarse como `JSON` estableciendo explícitamente el encabezado `Content-Type` en `application/json`: + +```js +await axios.post('https://httpbin.org/post', document.querySelector('#htmlForm'), { + headers: { + 'Content-Type': 'application/json', + }, +}); +``` + +Un ejemplo de un formulario válido que puede ser enviado con el código anterior es: + +```html +
+ + + + + + + + + +
+``` + +El formulario anterior se enviará como: + +```json +{ + "foo": "1", + "deep": { + "prop": "2", + "prop spaced": "3" + }, + "baz": ["4", "5"], + "user": { + "age": "value2" + } +} +``` + +::: warning +Actualmente no se admite el envío de Blobs/Files como JSON (base64). +::: diff --git a/docs/es/pages/advanced/http2.md b/docs/es/pages/advanced/http2.md new file mode 100644 index 0000000..3eeca39 --- /dev/null +++ b/docs/es/pages/advanced/http2.md @@ -0,0 +1,72 @@ +# HTTP2 + +El soporte experimental de HTTP/2 fue añadido al adaptador `http` en la versión `1.13.0`. Solo está disponible en entornos Node.js. + +## Uso básico + +Usa la opción `httpVersion` para seleccionar la versión del protocolo para una solicitud. Establecerla en `2` habilita HTTP/2. + +```js +const { data, headers, status } = await axios.post( + "https://httpbin.org/post", + form, + { + httpVersion: 2, + }, +); +``` + +## `http2Options` + +Las opciones nativas adicionales para la llamada interna `session.request()` pueden pasarse a través del objeto de configuración `http2Options`. Esto también incluye el parámetro personalizado `sessionTimeout`, que controla cuánto tiempo (en milisegundos) una sesión HTTP/2 inactiva se mantiene viva antes de cerrarse. Su valor predeterminado es `1000ms`. + +```js +{ + httpVersion: 2, + http2Options: { + rejectUnauthorized: false, // accept self-signed certificates (dev only) + sessionTimeout: 5000, // keep idle session alive for 5 seconds + }, +} +``` + +::: warning +El soporte de HTTP/2 es actualmente experimental. La API puede cambiar en futuras versiones menores o de parche. +::: + +## Ejemplo completo + +El ejemplo a continuación envía una solicitud POST con `multipart/form-data` sobre HTTP/2 y rastrea tanto el progreso de carga como el de descarga. + +```js +const form = new FormData(); +form.append("foo", "123"); + +const { data, headers, status } = await axios.post( + "https://httpbin.org/post", + form, + { + httpVersion: 2, + http2Options: { + // rejectUnauthorized: false, + // sessionTimeout: 1000 + }, + onUploadProgress(e) { + console.log("upload progress", e); + }, + onDownloadProgress(e) { + console.log("download progress", e); + }, + responseType: "arraybuffer", + }, +); +``` + +## Referencia de configuración + +| Opción | Tipo | Predeterminado | Descripción | +|---|---|---|---| +| `httpVersion` | `number` | `1` | Versión del protocolo HTTP a usar. Establece en `2` para habilitar HTTP/2. | +| `http2Options.sessionTimeout` | `number` | `1000` | Tiempo en milisegundos antes de que una sesión HTTP/2 inactiva se cierre. | + +Todas las demás opciones nativas de `session.request()` compatibles con el módulo `http2` integrado de Node.js también pueden pasarse dentro de `http2Options`. diff --git a/docs/es/pages/advanced/interceptors.md b/docs/es/pages/advanced/interceptors.md new file mode 100644 index 0000000..b3f6754 --- /dev/null +++ b/docs/es/pages/advanced/interceptors.md @@ -0,0 +1,116 @@ +# Interceptores + +Los interceptores son un mecanismo poderoso que puede usarse para interceptar y modificar solicitudes y respuestas HTTP. Son muy similares al middleware en Express.js. Un interceptor es una función que se ejecuta antes de enviar una solicitud y antes de recibir una respuesta. Los interceptores son útiles para una variedad de tareas como el registro de eventos (logging), la modificación de encabezados de solicitud y la modificación de la respuesta. + +El uso básico de los interceptores es el siguiente: + +```js +// Add a request interceptor +axios.interceptors.request.use( + function (config) { + // Do something before request is sent + return config; + }, + function (error) { + // Do something with request error + return Promise.reject(error); + } +); + +// Add a response interceptor +axios.interceptors.response.use( + function (response) { + // Any status code that lie within the range of 2xx cause this function to trigger + // Do something with response data + return response; + }, + function (error) { + // Any status codes that falls outside the range of 2xx cause this function to trigger + // Do something with response error + return Promise.reject(error); + } +); +``` + +## Eliminar interceptores + +Puedes eliminar cualquier interceptor usando el método `eject` sobre el interceptor que deseas eliminar. También puedes eliminar todos los interceptores llamando al método `clear` sobre el objeto `axios.interceptors`. A continuación se muestra un ejemplo de cómo eliminar un interceptor: + +```js +// Eject the request interceptor +const myInterceptor = axios.interceptors.request.use(function () { + /*...*/ +}); +axios.interceptors.request.eject(myInterceptor); + +// Eject the response interceptor +const myInterceptor = axios.interceptors.response.use(function () { + /*...*/ +}); +axios.interceptors.response.eject(myInterceptor); +``` + +A continuación se muestra un ejemplo de cómo eliminar todos los interceptores: + +```js +const instance = axios.create(); +instance.interceptors.request.use(function () { + /*...*/ +}); +instance.interceptors.request.clear(); // Removes interceptors from requests +instance.interceptors.response.use(function () { + /*...*/ +}); +instance.interceptors.response.clear(); // Removes interceptors from responses +``` + +## Comportamiento predeterminado de los interceptores + +Cuando añades interceptores de solicitud, se asume que son asíncronos de forma predeterminada. Esto puede causar un retraso en la ejecución de tu solicitud axios cuando el hilo principal está bloqueado (se crea una Promise internamente para el interceptor y tu solicitud queda al final de la pila de llamadas). Si tus interceptores de solicitud son síncronos, puedes añadir un indicador al objeto de opciones que le indicará a axios que ejecute el código de forma síncrona y evite cualquier retraso en la ejecución de la solicitud. + +```js +axios.interceptors.request.use( + function (config) { + config.headers.test = "I am only a header!"; + return config; + }, + null, + { synchronous: true } +); +``` + +## Interceptores usando `runWhen` + +Si deseas ejecutar un interceptor particular basándote en una verificación en tiempo de ejecución, puedes añadir una función `runWhen` al objeto de opciones. El interceptor no se ejecutará si y solo si el retorno de `runWhen` es `false`. La función se llamará con el objeto de configuración (recuerda que también puedes vincularle tus propios argumentos). Esto puede ser útil cuando tienes un interceptor de solicitud asíncrono que solo necesita ejecutarse en ciertos momentos. + +```js +function onGetCall(config) { + return config.method === "get"; +} +axios.interceptors.request.use( + function (config) { + config.headers.test = "special get headers"; + return config; + }, + null, + { runWhen: onGetCall } +); +``` + +## Múltiples interceptores + +Puedes añadir múltiples interceptores a la misma solicitud o respuesta. Lo siguiente aplica para múltiples interceptores en la misma cadena, en el orden indicado a continuación: + +- Cada interceptor se ejecuta +- Los interceptores de solicitud se ejecutan en orden inverso (LIFO). +- Los interceptores de respuesta se ejecutan en el orden en que fueron añadidos (FIFO). +- Solo se devuelve el resultado del último interceptor +- Cada interceptor recibe el resultado de su predecesor +- Cuando el interceptor de cumplimiento lanza una excepción: + - El siguiente interceptor de cumplimiento no es llamado + - El siguiente interceptor de rechazo es llamado + - Una vez capturado, el siguiente interceptor de cumplimiento es llamado nuevamente (igual que en una cadena de promises). + +::: tip +Para obtener una comprensión profunda de cómo funcionan los interceptores, puedes leer los casos de prueba [aquí](https://github.com/axios/axios/blob/v1.x/test/specs/interceptors.spec.js). +::: diff --git a/docs/es/pages/advanced/multipart-form-data-format.md b/docs/es/pages/advanced/multipart-form-data-format.md new file mode 100644 index 0000000..4d4d376 --- /dev/null +++ b/docs/es/pages/advanced/multipart-form-data-format.md @@ -0,0 +1,120 @@ +# Formato multipart-form-data + +axios puede enviar solicitudes en el formato `multipart/form-data`. Este formato se usa comúnmente al subir archivos. Para enviar una solicitud en este formato, debes crear un objeto `FormData` y agregarle los datos. Luego puedes pasar el objeto `FormData` a la propiedad `data` de la configuración de solicitud de axios. + +```js +const formData = new FormData(); +formData.append("foo", "bar"); + +axios.post("https://httpbin.org/post", formData); +``` + +En Node.js, puedes usar la librería `form-data` de la siguiente manera: + +```js +const FormData = require("form-data"); + +const form = new FormData(); +form.append("my_field", "my value"); +form.append("my_buffer", Buffer.alloc(10)); +form.append("my_file", fs.createReadStream("/foo/bar.jpg")); + +axios.post("https://example.com", form); +``` + +## Serialización automática a FormData + +A partir de la versión v0.27.0, Axios admite la serialización automática de objetos a un objeto FormData si el encabezado `Content-Type` de la solicitud está establecido en `multipart/form-data`. Esto significa que puedes pasar un objeto JavaScript directamente a la propiedad `data` de la configuración de solicitud de axios. Por ejemplo, al pasar datos a una solicitud POST: + +```js +import axios from "axios"; + +axios + .post( + "https://httpbin.org/post", + { x: 1 }, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ) + .then(({ data }) => console.log(data)); +``` + +En el entorno de Node.js, el polyfill ([`form-data`](https://github.com/form-data/form-data)) se usa de forma predeterminada. Puedes sobrescribir la clase FormData estableciendo la variable de configuración `env.FormData`, aunque en la mayoría de los casos no lo necesitarás: + +```js +const axios = require("axios"); +var FormData = require("form-data"); + +axios + .post( + "https://httpbin.org/post", + { x: 1, buf: Buffer.alloc(10) }, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ) + .then(({ data }) => console.log(data)); +``` + +## Terminaciones admitidas + +El serializador de FormData de Axios admite algunas terminaciones especiales para realizar las siguientes operaciones: + +- `{}` - serializa el valor con JSON.stringify +- `[]` - desenvuelve el objeto tipo arreglo como campos separados con la misma clave + +::: warning +Nota: la operación de desenvolvimiento/expansión se usará de forma predeterminada en arreglos y objetos FileList. +::: + +## Configurar el serializador de FormData + +El serializador de FormData admite opciones adicionales a través de la propiedad de objeto `config.formSerializer` para manejar casos especiales: + +- `visitor: Function` - función de visitante definida por el usuario que se llamará de forma recursiva para serializar el objeto de datos a un objeto FormData siguiendo reglas personalizadas. +- `dots: boolean = false` - usa notación de punto en lugar de corchetes para serializar arreglos y objetos; +- `metaTokens: boolean = true` - añade la terminación especial (por ejemplo, `user{}: '{"name": "John"}'`) en la clave de FormData. El analizador de cuerpo del backend podría usar esta meta-información para analizar automáticamente el valor como JSON. +- `indexes: null|false|true = false` - controla cómo se añadirán los índices a las claves desenvueltas de objetos planos tipo arreglo: + - `null` - no añadir corchetes (`arr: 1`, `arr: 2`, `arr: 3`) + - `false` (predeterminado) - añadir corchetes vacíos (`arr[]: 1`, `arr[]: 2`, `arr[]: 3`) + - `true` - añadir corchetes con índices (`arr[0]: 1`, `arr[1]: 2`, `arr[2]: 3`) + +Por ejemplo, si tenemos un objeto como este: + +```js +const obj = { + x: 1, + arr: [1, 2, 3], + arr2: [1, [2], 3], + users: [ + { name: "Peter", surname: "Griffin" }, + { name: "Thomas", surname: "Anderson" }, + ], + "obj2{}": [{ x: 1 }], +}; +``` + +El serializador de Axios ejecutará internamente los siguientes pasos: + +```js +const formData = new FormData(); +formData.append("x", "1"); +formData.append("arr[]", "1"); +formData.append("arr[]", "2"); +formData.append("arr[]", "3"); +formData.append("arr2[0]", "1"); +formData.append("arr2[1][0]", "2"); +formData.append("arr2[2]", "3"); +formData.append("users[0][name]", "Peter"); +formData.append("users[0][surname]", "Griffin"); +formData.append("users[1][name]", "Thomas"); +formData.append("users[1][surname]", "Anderson"); +formData.append("obj2{}", '[{"x":1}]'); +``` + +Axios admite los siguientes métodos abreviados: `postForm`, `putForm`, `patchForm`, que son simplemente los métodos HTTP correspondientes con el encabezado `Content-Type` preestablecido en `multipart/form-data`. diff --git a/docs/es/pages/advanced/progress-capturing.md b/docs/es/pages/advanced/progress-capturing.md new file mode 100644 index 0000000..4ce46a3 --- /dev/null +++ b/docs/es/pages/advanced/progress-capturing.md @@ -0,0 +1,55 @@ +# Captura de progreso + +Axios admite la captura del progreso de carga y descarga en entornos de navegador y Node.js. La frecuencia de los eventos de progreso está limitada a 3 veces por segundo para evitar saturar el navegador con eventos de progreso. A continuación se muestra un ejemplo de cómo capturar eventos de progreso: + +```js +await axios.post(url, data, { + onUploadProgress: function (axiosProgressEvent) { + /*{ + loaded: number; + total?: number; + progress?: number; // in range [0..1] + bytes: number; // how many bytes have been transferred since the last trigger (delta) + estimated?: number; // estimated time in seconds + rate?: number; // upload speed in bytes + upload: true; // upload sign + }*/ + }, + + onDownloadProgress: function (axiosProgressEvent) { + /*{ + loaded: number; + total?: number; + progress?: number; + bytes: number; + estimated?: number; + rate?: number; // download speed in bytes + download: true; // download sign + }*/ + }, +}); +``` + +También puedes transmitir los eventos de progreso de carga y descarga a un stream legible en Node.js. Esto es útil cuando deseas mostrar el progreso de una forma personalizada. A continuación se muestra un ejemplo de cómo transmitir eventos de progreso: + +```js +const { data } = await axios.post(SERVER_URL, readableStream, { + onUploadProgress: ({ progress }) => { + console.log((progress * 100).toFixed(2)); + }, + + headers: { + "Content-Length": contentLength, + }, + + maxRedirects: 0, // avoid buffering the entire stream +}); +``` + +::: warning +La captura del progreso de carga de FormData no está disponible actualmente en entornos Node.js. +::: + +::: danger +Se recomienda deshabilitar las redirecciones estableciendo `maxRedirects: 0` para subir el stream en el entorno Node.js, ya que el paquete `follow-redirects` almacenará todo el stream en memoria RAM sin seguir el algoritmo de "backpressure". +::: diff --git a/docs/es/pages/advanced/promises.md b/docs/es/pages/advanced/promises.md new file mode 100644 index 0000000..5e745d4 --- /dev/null +++ b/docs/es/pages/advanced/promises.md @@ -0,0 +1,81 @@ +# Promises + +axios está construido sobre la API nativa de Promise de ES6. Cada solicitud de axios devuelve una Promise que se resuelve en un objeto de respuesta o se rechaza con un error. Si tu entorno no admite Promises de ES6, necesitarás añadir un polyfill — por ejemplo con [es6-promise](https://github.com/stefanpenner/es6-promise). + +## then / catch / finally + +Dado que axios devuelve una Promise estándar, puedes usar `.then()`, `.catch()` y `.finally()` para manejar el resultado: + +```js +axios.get("/api/users") + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error("Request failed:", error.message); + }) + .finally(() => { + console.log("Request finished"); + }); +``` + +## async / await + +El enfoque recomendado para la mayoría de las bases de código es `async/await`, que hace que el código asíncrono se lea como código síncrono: + +```js +async function fetchUser(id) { + try { + const response = await axios.get(`/api/users/${id}`); + return response.data; + } catch (error) { + console.error("Failed to fetch user:", error.message); + throw error; + } +} +``` + +## Solicitudes en paralelo + +Dado que axios devuelve una Promise estándar, puedes usar `Promise.all` para hacer múltiples solicitudes al mismo tiempo y esperar a que todas se completen: + +```js +const [users, posts] = await Promise.all([ + axios.get("/api/users"), + axios.get("/api/posts"), +]); + +console.log(users.data, posts.data); +``` + +::: tip +`Promise.all` se rechazará tan pronto como cualquiera de las solicitudes falle. Si deseas manejar fallos parciales, usa `Promise.allSettled` en su lugar. +::: + +```js +const results = await Promise.allSettled([ + axios.get("/api/users"), + axios.get("/api/posts"), +]); + +results.forEach((result) => { + if (result.status === "fulfilled") { + console.log(result.value.data); + } else { + console.error("Request failed:", result.reason.message); + } +}); +``` + +## Encadenar solicitudes + +Puedes encadenar llamadas `.then()` para ejecutar solicitudes secuencialmente, pasando datos de una a la siguiente: + +```js +axios.get("/api/user/1") + .then(({ data: user }) => axios.get(`/api/posts?userId=${user.id}`)) + .then(({ data: posts }) => { + console.log("Posts for user:", posts); + }) + .catch(console.error); +``` diff --git a/docs/es/pages/advanced/rate-limiting.md b/docs/es/pages/advanced/rate-limiting.md new file mode 100644 index 0000000..cfb5287 --- /dev/null +++ b/docs/es/pages/advanced/rate-limiting.md @@ -0,0 +1,62 @@ +# Limitación de velocidad + +axios admite la limitación del ancho de banda en el entorno Node.js a través del adaptador HTTP. Esto te permite controlar la velocidad de carga o descarga de datos, lo que es útil para operaciones masivas, trabajos en segundo plano o scraping educado que no debe saturar una conexión. + +## `maxRate` + +La opción `maxRate` acepta un número (bytes por segundo) o un arreglo donde el primer valor es el límite de carga y el segundo es el límite de descarga. Usa `[uploadRate]` para limitar solo la carga, o `[uploadRate, downloadRate]` para limitar ambas direcciones. Cuando se pasa un número único, el mismo límite se aplica tanto a la carga como a la descarga. + +```js +// Limit both upload and download to 100 KB/s +await axios.get(URL, { maxRate: 100 * 1024 }); + +// Limit upload to 100 KB/s, download to 500 KB/s +await axios.get(URL, { maxRate: [100 * 1024, 500 * 1024] }); +``` + +::: warning +`maxRate` solo es compatible con el adaptador HTTP de Node.js. No tiene efecto en entornos de navegador. +::: + +## Limitación de velocidad de carga + +Limita la velocidad de carga y registra el progreso al mismo tiempo: + +```js +const { data } = await axios.post(SERVER_URL, myBuffer, { + onUploadProgress: ({ progress, rate }) => { + const percent = (progress * 100).toFixed(1); + const kbps = (rate / 1024).toFixed(1); + console.log(`Upload [${percent}%] at ${kbps} KB/s`); + }, + + maxRate: [100 * 1024], // cap upload at 100 KB/s +}); +``` + +## Limitación de velocidad de descarga + +Limita la velocidad de descarga para respuestas de gran tamaño: + +```js +const { data } = await axios.get(FILE_URL, { + onDownloadProgress: ({ progress, rate }) => { + const percent = (progress * 100).toFixed(1); + const kbps = (rate / 1024).toFixed(1); + console.log(`Download [${percent}%] at ${kbps} KB/s`); + }, + + maxRate: [Infinity, 200 * 1024], // no upload limit, 200 KB/s download limit + responseType: "arraybuffer", +}); +``` + +## Limitación combinada de carga y descarga + +Pasa ambos límites como un arreglo para controlar ambas direcciones simultáneamente: + +```js +await axios.post(SERVER_URL, largeBuffer, { + maxRate: [50 * 1024, 500 * 1024], // 50 KB/s up, 500 KB/s down +}); +``` diff --git a/docs/es/pages/advanced/request-config.md b/docs/es/pages/advanced/request-config.md new file mode 100644 index 0000000..e1fb5f2 --- /dev/null +++ b/docs/es/pages/advanced/request-config.md @@ -0,0 +1,350 @@ +# Configuración de solicitud + +La configuración de solicitud se usa para configurar la solicitud. Existe una amplia gama de opciones disponibles, pero la única opción requerida es `url`. Si el objeto de configuración no contiene un campo `method`, el método predeterminado es `GET`. + +### `url` + +La `url` es la URL a la que se realiza la solicitud. Puede ser una cadena de texto o una instancia de `URL`. + +### `method` + +El `method` es el método HTTP a usar para la solicitud. El método predeterminado es `GET`. + +### `baseURL` + +La `baseURL` es la URL base que se antepondrá a la `url` a menos que la `url` sea una URL absoluta. Es útil para hacer solicitudes al mismo dominio sin tener que repetir el nombre de dominio, ni ningún prefijo de API o versión. + +### `allowAbsoluteUrls` + +`allowAbsoluteUrls` determina si las URLs absolutas sobrescribirán un `baseUrl` configurado. Cuando se establece en `true` (valor predeterminado), los valores absolutos para `url` sobrescribirán `baseUrl`. Cuando se establece en `false`, los valores absolutos para `url` siempre serán antepuestos por `baseUrl`. + +### `transformRequest` + +La función `transformRequest` te permite modificar los datos de la solicitud antes de enviarlos al servidor. Esta función se llama con los datos de la solicitud como único argumento. Solo aplica para los métodos de solicitud `PUT`, `POST`, `PATCH` y `DELETE`. La última función del arreglo debe devolver una cadena de texto o una instancia de Buffer, ArrayBuffer, FormData o Stream. + +### `transformResponse` + +La función `transformResponse` te permite modificar los datos de la respuesta antes de que sean pasados a las funciones `then` o `catch`. Esta función se llama con los datos de la respuesta como único argumento. + +### `headers` + +Los `headers` son los encabezados HTTP que se enviarán con la solicitud. El encabezado `Content-Type` se establece en `application/json` de forma predeterminada. + +### `params` + +Los `params` son los parámetros de URL que se enviarán con la solicitud. Debe ser un objeto plano o un objeto URLSearchParams. Si la `url` contiene parámetros de consulta, se combinarán con el objeto `params`. + +### `paramsSerializer` + +La función `paramsSerializer` te permite serializar el objeto `params` antes de enviarlo al servidor. Hay varias opciones disponibles para esta función; consulta el ejemplo completo de configuración de solicitud al final de esta página. + +### `data` + +El `data` son los datos que se enviarán como cuerpo de la solicitud. Puede ser una cadena de texto, un objeto plano, un Buffer, ArrayBuffer, FormData, Stream o URLSearchParams. Solo aplica para los métodos de solicitud `PUT`, `POST`, `DELETE` y `PATCH`. Cuando no se establece `transformRequest`, debe ser de uno de los siguientes tipos: + +- cadena de texto, objeto plano, ArrayBuffer, ArrayBufferView, URLSearchParams +- Solo en el navegador: FormData, File, Blob +- Solo en Node.js: Stream, Buffer, FormData (paquete form-data) + +### `timeout` + +El `timeout` es el número de milisegundos antes de que la solicitud expire. Si la solicitud tarda más que `timeout`, se abortará. + +### `withCredentials` + +La propiedad `withCredentials` indica si las solicitudes de Access-Control entre sitios deben hacerse usando credenciales como cookies, encabezados de autorización o certificados de cliente TLS. Establecer `withCredentials` no tiene efecto en solicitudes del mismo sitio. + +### `adapter` + +`adapter` permite el manejo personalizado de solicitudes, lo que facilita las pruebas. Devuelve una Promise y proporciona una respuesta válida; consulta los [adaptadores](/pages/advanced/adapters) para más información. También proporcionamos una serie de adaptadores integrados. El adaptador predeterminado es `http` para Node.js y `xhr` para navegadores. La lista completa de adaptadores integrados es la siguiente: + +- fetch +- http +- xhr + +También puedes pasar un arreglo de adaptadores. axios usará el primero que sea compatible con el entorno. + +### `auth` + +`auth` indica que se debe usar autenticación HTTP Basic y proporciona las credenciales. Esto establecerá un encabezado `Authorization`, sobrescribiendo cualquier encabezado `Authorization` personalizado que hayas definido usando `headers`. Ten en cuenta que solo la autenticación HTTP Basic es configurable a través de este parámetro. Para tokens Bearer y similares, usa encabezados `Authorization` personalizados. + +### `responseType` + +El `responseType` indica el tipo de datos con el que el servidor responderá. Puede ser uno de los siguientes: + +- arraybuffer +- document +- json +- text +- stream +- blob (solo en el navegador) +- formdata (solo con el adaptador fetch) + +### `responseEncoding` + +El `responseEncoding` indica la codificación a usar para decodificar las respuestas. Se admiten las siguientes opciones: + +- ascii +- ASCII +- ansi +- ANSI +- binary +- BINARY +- base64 +- BASE64 +- base64url +- BASE64URL +- hex +- HEX +- latin1 +- LATIN1 +- ucs-2 +- UCS-2 +- ucs2 +- UCS2 +- utf-8 +- UTF-8 +- utf8 +- UTF8 +- utf16le +- UTF16LE + +::: tip +Nota: Se ignora para `responseType` de tipo `stream` o solicitudes del lado del cliente. +::: + +### `xsrfCookieName` + +`xsrfCookieName` es el nombre de la cookie que se usará como valor para el token `XSRF`. + +### `xsrfHeaderName` + +`xsrfHeaderName` es el nombre del encabezado que se usará como valor para el token `XSRF`. + +### `withXSRFToken` + +La propiedad `withXSRFToken` indica si se debe enviar el token `XSRF` con la solicitud. Solo aplica para solicitudes del lado del cliente. El valor predeterminado es `undefined`. + +### `onUploadProgress` + +La función `onUploadProgress` te permite escuchar el progreso de una carga. + +### `onDownloadProgress` + +La función `onDownloadProgress` te permite escuchar el progreso de una descarga. + +### `maxContentLength` + +La propiedad `maxContentLength` define el número máximo de bytes que el servidor aceptará en la respuesta. + +### `maxBodyLength` + +La propiedad `maxBodyLength` define el número máximo de bytes que el servidor aceptará en la solicitud. + +### `validateStatus` + +La función `validateStatus` te permite sobreescribir la validación predeterminada del código de estado. Por defecto, axios rechazará la Promise si el código de estado no está en el rango 200-299. Puedes sobreescribir este comportamiento proporcionando una función `validateStatus` personalizada. La función debe devolver `true` si el código de estado está dentro del rango que deseas aceptar. + +### `maxRedirects` + +La propiedad `maxRedirects` define el número máximo de redirecciones a seguir. Si se establece en 0, no se seguirá ninguna redirección. + +### `beforeRedirect` + +La función `beforeRedirect` te permite modificar la solicitud antes de que sea redirigida. Úsala para ajustar las opciones de la solicitud al redirigir, para inspeccionar los últimos encabezados de respuesta, o para cancelar la solicitud lanzando un error. Si `maxRedirects` se establece en 0, `beforeRedirect` no se usa. + +### `socketPath` + +La propiedad `socketPath` define un socket UNIX que se usará en lugar de una conexión TCP. Por ejemplo, `/var/run/docker.sock` para enviar solicitudes al daemon de Docker. Solo se puede especificar `socketPath` o `proxy`. Si ambos se especifican, se usa `socketPath`. + +### `transport` + +La propiedad `transport` define el transporte a usar para la solicitud. Es útil para hacer solicitudes sobre un protocolo diferente, como `http2`. + +### `httpAgent` y `httpsAgent` + +`httpAgent` y `httpsAgent` definen un agente personalizado para usar al realizar solicitudes http y https respectivamente en Node.js. Esto permite añadir opciones como `keepAlive` que no están habilitadas por defecto. + +### `proxy` + +`proxy` define el nombre de host, puerto y protocolo del servidor proxy que deseas usar. También puedes definir tu proxy usando las variables de entorno convencionales `http_proxy` y `https_proxy`. + +Si usas variables de entorno para tu configuración de proxy, también puedes definir una variable de entorno `no_proxy` como una lista separada por comas de dominios que no deben ser enviados a través del proxy. + +Usa `false` para deshabilitar los proxies, ignorando las variables de entorno. `auth` indica que se debe usar autenticación HTTP Basic para conectarse al proxy, y proporciona las credenciales. Esto establecerá un encabezado `Proxy-Authorization`, sobrescribiendo cualquier encabezado `Proxy-Authorization` personalizado que hayas definido usando `headers`. Si el servidor proxy usa HTTPS, debes establecer el protocolo en `https`. + +```js +proxy: { + protocol: "https", + host: "127.0.0.1", + hostname: "localhost", // Takes precedence over "host" if both are defined + port: 9000, + auth: { + username: "mikeymike", + password: "rapunz3l" + } +}, +``` + +### `cancelToken` + +La propiedad `cancelToken` te permite crear un token de cancelación que puede usarse para cancelar la solicitud. Para más información, consulta la documentación de [cancelación](/pages/advanced/cancellation). + +### `signal` + +La propiedad `signal` te permite pasar una instancia de `AbortSignal` a la solicitud. Esto te permite cancelar la solicitud usando la API `AbortController`. + +### `decompress` + +La propiedad `decompress` indica si los datos de la respuesta deben descomprimirse automáticamente. El valor predeterminado es `true`. + +### `insecureHTTPParser` + +Indica si se debe usar un parser HTTP inseguro que acepta encabezados HTTP inválidos. Esto puede permitir la interoperabilidad con implementaciones HTTP no conformes. Se debe evitar el uso del parser inseguro. + +Ten en cuenta que la opción `insecureHTTPParser` solo está disponible en Node.js 12.10.0 y versiones posteriores. Consulta la [documentación de Node.js](https://nodejs.org/en/blog/vulnerability/february-2020-security-releases/#strict-http-header-parsing-none) para más información. Consulta el conjunto completo de opciones [aquí](https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_url_options_callback). + +### `transitional` + +La propiedad `transitional` te permite habilitar o deshabilitar ciertas características de transición. Las siguientes opciones están disponibles: + +- `silentJSONParsing`: Si se establece en `true`, axios no registrará una advertencia cuando encuentre respuestas JSON inválidas, estableciendo el valor de retorno en null. Es útil cuando trabajas con APIs que devuelven JSON inválido. +- `forcedJSONParsing`: Fuerza a axios a analizar las respuestas JSON como JSON, incluso si la respuesta no es JSON válido. Es útil cuando trabajas con APIs que devuelven JSON inválido. +- `clarifyTimeoutError`: Clarifica el mensaje de error cuando una solicitud expira. Es útil cuando depuras problemas de timeout. +- `legacyInterceptorReqResOrdering`: Cuando se establece en `true`, se usará el orden de solicitud/respuesta de interceptores heredado. + +### `env` + +La propiedad `env` te permite establecer algunas opciones de configuración. Por ejemplo, la clase FormData que se usa para serializar automáticamente el payload en un objeto FormData. + +- FormData: window?.FormData || global?.FormData + +### `formSerializer` + +La función `formSerializer` te permite serializar el objeto `data` antes de enviarlo al servidor. Hay varias opciones disponibles para esta función; consulta el ejemplo completo de configuración de solicitud al final de esta página. + +### `maxRate` + +La propiedad `maxRate` define el **ancho de banda** máximo (en bytes por segundo) para la carga y/o descarga. Acepta un número único (aplicado a ambas direcciones) o un arreglo de dos elementos `[uploadRate, downloadRate]` donde cada elemento es un límite en bytes por segundo. Por ejemplo, `100 * 1024` significa 100 KB/s. Consulta [Limitación de velocidad](/pages/advanced/rate-limiting) para ver ejemplos. + +## Ejemplo completo de configuración de solicitud + +```js +{ + url: "/posts", + method: "get", + baseURL: "https://jsonplaceholder.typicode.com", + allowAbsoluteUrls: true, + transformRequest: [function (data, headers) { + return data; + }], + transformResponse: [function (data) { + return data; + }], + headers: {"X-Requested-With": "XMLHttpRequest"}, + params: { + postId: 5 + }, + paramsSerializer: { + // Custom encoder function which sends key/value pairs in an iterative fashion. + encode?: (param: string): string => { /* Do custom operations here and return transformed string */ }, + + // Custom serializer function for the entire parameter. Allows user to mimic pre 1.x behaviour. + serialize?: (params: Record, options?: ParamsSerializerOptions ), + + // Configuration for formatting array indexes in the params. + // Three available options: + // (1) indexes: null (leads to no brackets) + // (2) (default) indexes: false (leads to empty brackets) + // (3) indexes: true (leads to brackets with indexes). + indexes: false + + }, + data: { + firstName: "Fred" + }, + // Syntax alternative to send data into the body method post only the value is sent, not the key + data: "Country=Brasil&City=Belo Horizonte", + timeout: 1000, + withCredentials: false, + adapter: function (config) { + // Do whatever you want + }, + adapter: "xhr", + auth: { + username: "janedoe", + password: "s00pers3cret" + }, + responseType: "json", + responseEncoding: "utf8", + xsrfCookieName: "XSRF-TOKEN", + xsrfHeaderName: "X-XSRF-TOKEN", + withXSRFToken: boolean | undefined | ((config: InternalAxiosRequestConfig) => boolean | undefined), + onUploadProgress: function ({loaded, total, progress, bytes, estimated, rate, upload = true}) { + // Do whatever you want with the Axios progress event + }, + onDownloadProgress: function ({loaded, total, progress, bytes, estimated, rate, download = true}) { + // Do whatever you want with the Axios progress event + }, + maxContentLength: 2000, + maxBodyLength: 2000, + validateStatus: function (status) { + return status >= 200 && status < 300; + }, + maxRedirects: 21, + beforeRedirect: (options, { headers }) => { + if (options.hostname === "typicode.com") { + options.auth = "user:password"; + } + }, + socketPath: null, + transport: undefined, + httpAgent: new http.Agent({ keepAlive: true }), + httpsAgent: new https.Agent({ keepAlive: true }), + proxy: { + protocol: "https", + host: "127.0.0.1", + // hostname: "127.0.0.1" // Takes precedence over "host" if both are defined + port: 9000, + auth: { + username: "mikeymike", + password: "rapunz3l" + } + }, + cancelToken: new CancelToken(function (cancel) { + cancel("Operation has been canceled."); + }), + signal: new AbortController().signal, + decompress: true, + insecureHTTPParser: undefined, + transitional: { + silentJSONParsing: true, + forcedJSONParsing: true, + clarifyTimeoutError: false, + legacyInterceptorReqResOrdering: true, + }, + env: { + FormData: window?.FormData || global?.FormData + }, + formSerializer: { + // Custom visitor function to serialize form values + visitor: (value, key, path, helpers) => {}; + + // Use dots instead of brackets format + dots: boolean; + + // Keep special endings like {} in parameter key + metaTokens: boolean; + + // Use array indexes format: + // null - no brackets + // false - empty brackets + // true - brackets with indexes + indexes: boolean; + }, + maxRate: [ + 100 * 1024, // 100KB/s upload limit, + 100 * 1024 // 100KB/s download limit + ] +} +``` diff --git a/docs/es/pages/advanced/request-method-aliases.md b/docs/es/pages/advanced/request-method-aliases.md new file mode 100644 index 0000000..0bb95be --- /dev/null +++ b/docs/es/pages/advanced/request-method-aliases.md @@ -0,0 +1,130 @@ +# Alias de solicitud + +axios proporciona un conjunto de alias para realizar solicitudes HTTP. Estos alias son atajos para hacer solicitudes usando el método `request`. Están diseñados para ser fáciles de usar y ofrecer una forma más conveniente de hacer solicitudes. + +axios se esfuerza por seguir las RFC 7231 y RFC 5789 de la manera más fiel posible. Los alias están diseñados para ser consistentes con los métodos HTTP definidos en dichas RFC. + +### `axios` + +axios puede usarse para hacer una solicitud HTTP pasando únicamente el objeto de configuración. El objeto de configuración completo está documentado [aquí](/pages/advanced/request-config). + +```ts +axios(url: string | AxiosRequestConfig, config?: AxiosRequestConfig); +``` + +## Alias de método + +Los siguientes alias están disponibles para hacer solicitudes: + +### `request` + +El método `request` es el método principal que usarás para hacer solicitudes HTTP. Acepta un objeto de configuración como argumento y devuelve una Promise que se resuelve en el objeto de respuesta. Es un método genérico que puede usarse para cualquier tipo de solicitud HTTP. + +```ts +axios.request(config: AxiosRequestConfig): AxiosResponse; +``` + +### `get` + +El método `get` se usa para hacer una solicitud GET. Acepta una URL y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.get(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `delete` + +El método `delete` se usa para hacer una solicitud DELETE. Acepta una URL y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.delete(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `head` + +El método `head` se usa para hacer una solicitud HEAD. Acepta una URL y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.head(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `options` + +El método `options` se usa para hacer una solicitud OPTIONS. Acepta una URL y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.options(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `post` + +El método `post` se usa para hacer una solicitud POST. Acepta una URL, un objeto de datos opcional y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.post(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `put` + +El método `put` se usa para hacer una solicitud PUT. Acepta una URL, un objeto de datos opcional y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.put(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `patch` + +El método `patch` se usa para hacer una solicitud PATCH. Acepta una URL, un objeto de datos opcional y un objeto de configuración opcional como argumentos, y devuelve una Promise que se resuelve en el objeto de respuesta. + +```ts +axios.patch(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +## Métodos abreviados para datos de formulario + +Estos métodos son equivalentes a sus contrapartes anteriores, pero predefinen `Content-Type` como `multipart/form-data`. Son la forma recomendada de subir archivos o enviar formularios HTML. + +### `postForm` + +```ts +axios.postForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// Upload a file from a browser file input +await axios.postForm("/api/upload", { + file: document.querySelector("#fileInput").files[0], + description: "Profile photo", +}); +``` + +### `putForm` + +```ts +axios.putForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// Replace a resource with form data +await axios.putForm("/api/users/1/avatar", { + avatar: document.querySelector("#avatarInput").files[0], +}); +``` + +### `patchForm` + +```ts +axios.patchForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// Update specific fields using form data +await axios.patchForm("/api/users/1", { + displayName: "New Name", + avatar: document.querySelector("#avatarInput").files[0], +}); +``` + +::: tip +`postForm`, `putForm` y `patchForm` aceptan los mismos tipos de datos que sus métodos base: objetos planos, `FormData`, `FileList` y `HTMLFormElement`. Consulta [Publicación de archivos](/pages/advanced/file-posting) para más ejemplos. +::: diff --git a/docs/es/pages/advanced/response-schema.md b/docs/es/pages/advanced/response-schema.md new file mode 100644 index 0000000..ab0b934 --- /dev/null +++ b/docs/es/pages/advanced/response-schema.md @@ -0,0 +1,64 @@ +# Esquema de respuesta + +Cada solicitud de axios se resuelve en un objeto de respuesta con la siguiente estructura. El esquema es consistente tanto en el entorno del navegador como en Node.js. + +```js +{ + // Los datos de respuesta proporcionados por el servidor. + // Al usar `transformResponse`, este será el resultado de la última transformación. + data: {}, + + // El código de estado HTTP de la respuesta del servidor (por ejemplo: 200, 404, 500). + status: 200, + + // El mensaje de estado HTTP correspondiente al código de estado (por ejemplo: "OK", "Not Found"). + statusText: "OK", + + // Los encabezados de respuesta enviados por el servidor. + // Los nombres de los encabezados están en minúsculas. Puedes acceder a ellos con notación de corchetes o de punto. + headers: {}, + + // La configuración de axios que se usó para esta solicitud, incluyendo baseURL, + // headers, timeout, params y cualquier otra opción que hayas proporcionado. + config: {}, + + // El objeto de solicitud subyacente. + // En Node.js: la última instancia de `http.ClientRequest` (después de cualquier redirección). + // En el navegador: la instancia de `XMLHttpRequest`. + request: {}, +} +``` + +## Acceder a los campos de la respuesta + +En la práctica, generalmente desestructurarás solo las partes que necesites: + +```js +const { data, status, headers } = await axios.get("/api/users/1"); + +console.log(status); // 200 +console.log(headers["content-type"]); // "application/json; charset=utf-8" +console.log(data); // { id: 1, name: "Jay", email: "jay@example.com" } +``` + +## Verificar el código de estado + +axios resuelve la Promise para cualquier respuesta 2xx y la rechaza para cualquier cosa fuera de ese rango de forma predeterminada. Puedes personalizar esto con la opción de configuración `validateStatus`: + +```js +const response = await axios.get("/api/resource", { + validateStatus: (status) => status < 500, // resolve for anything below 500 +}); +``` + +## Acceder a los encabezados de respuesta + +Todos los nombres de encabezados de respuesta están en minúsculas, independientemente de cómo los haya enviado el servidor: + +```js +const response = await axios.get("/api/resource"); + +// These are equivalent +const contentType = response.headers["content-type"]; +const contentType2 = response.headers.get("content-type"); +``` diff --git a/docs/es/pages/advanced/retry.md b/docs/es/pages/advanced/retry.md new file mode 100644 index 0000000..84eb868 --- /dev/null +++ b/docs/es/pages/advanced/retry.md @@ -0,0 +1,130 @@ +# Reintentos y recuperación de errores + +Las solicitudes de red pueden fallar por razones transitorias — una falla momentánea del servidor, una breve interrupción de la red o una respuesta de límite de tasa. Implementar una estrategia de reintento en un interceptor te permite manejar estos fallos de forma transparente, sin ensuciar el código de tu aplicación. + +## Reintento básico con un interceptor de respuesta + +El enfoque más sencillo es capturar códigos de estado de error específicos y reenviar inmediatamente la solicitud original un número limitado de veces: + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +const MAX_RETRIES = 3; + +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + // Only retry on network errors or 5xx server errors + const shouldRetry = + !error.response || (error.response.status >= 500 && error.response.status < 600); + + if (!shouldRetry) { + return Promise.reject(error); + } + + config._retryCount = config._retryCount ?? 0; + + if (config._retryCount >= MAX_RETRIES) { + return Promise.reject(error); + } + + config._retryCount += 1; + return api(config); + } +); +``` + +## Retroceso exponencial + +Reintentar inmediatamente después de un fallo puede sobrecargar a un servidor que ya tiene dificultades. El retroceso exponencial espera progresivamente más tiempo entre cada intento: + +```js +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + const shouldRetry = + !error.response || (error.response.status >= 500 && error.response.status < 600); + + if (!shouldRetry) return Promise.reject(error); + + config._retryCount = config._retryCount ?? 0; + + if (config._retryCount >= 3) return Promise.reject(error); + + config._retryCount += 1; + + // Wait 200ms, 400ms, 800ms, ... before each retry + const backoff = 100 * 2 ** config._retryCount; + await delay(backoff); + + return api(config); + } +); +``` + +## Reintento en 429 (límite de tasa) con Retry-After + +Cuando el servidor responde con `429 Too Many Requests`, a menudo incluye un encabezado `Retry-After` que indica exactamente cuánto tiempo esperar: + +```js +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + if (error.response?.status !== 429) return Promise.reject(error); + + config._retryCount = config._retryCount ?? 0; + if (config._retryCount >= 3) return Promise.reject(error); + + config._retryCount += 1; + + const retryAfterHeader = error.response.headers["retry-after"]; + const waitMs = retryAfterHeader + ? parseFloat(retryAfterHeader) * 1000 // header is in seconds + : 1000; // default to 1 second + + await new Promise((resolve) => setTimeout(resolve, waitMs)); + return api(config); + } +); +``` + +## Desactivar reintentos por solicitud + +Si algunas solicitudes nunca deben reintentarse (por ejemplo, mutaciones no idempotentes que no deseas duplicar), añade un indicador a la configuración de la solicitud: + +```js +// Add this to your interceptor before the retry logic: +if (config._noRetry) return Promise.reject(error); + +// Then opt out on specific calls: +await api.post("/payments/charge", body, { _noRetry: true }); +``` + +## Combinar reintentos con cancelación + +Usa un `AbortController` para cancelar una solicitud que está esperando un retardo de retroceso: + +```js +const controller = new AbortController(); + +try { + await api.get("/api/data", { signal: controller.signal }); +} catch (error) { + if (axios.isCancel(error)) { + console.log("Request aborted by user"); + } +} + +// Cancel the request (and any pending retry delay) from elsewhere: +controller.abort(); +``` diff --git a/docs/es/pages/advanced/testing.md b/docs/es/pages/advanced/testing.md new file mode 100644 index 0000000..af6ef99 --- /dev/null +++ b/docs/es/pages/advanced/testing.md @@ -0,0 +1,145 @@ +# Pruebas + +Probar código que realiza solicitudes HTTP con axios es sencillo. El enfoque recomendado es simular (mock) axios directamente, de modo que las pruebas se ejecuten sin acceder a la red real, dándote control total sobre las respuestas que recibe tu código. + +## Simulación con Vitest o Jest + +Tanto Vitest como Jest admiten la simulación de módulos con `vi.mock` / `jest.mock`. Puedes simular todo el módulo de axios y controlar lo que devuelve cada método: + +```js +// user-service.js +import axios from "axios"; + +export async function getUser(id) { + const { data } = await axios.get(`/api/users/${id}`); + return data; +} +``` + +```js +// user-service.test.js +import { describe, it, expect, vi } from "vitest"; +import axios from "axios"; +import { getUser } from "./user-service"; + +vi.mock("axios"); + +describe("getUser", () => { + it("returns user data on success", async () => { + const mockUser = { id: 1, name: "Jay" }; + + // Make axios.get resolve with our fake response + axios.get.mockResolvedValueOnce({ data: mockUser }); + + const result = await getUser(1); + + expect(result).toEqual(mockUser); + expect(axios.get).toHaveBeenCalledWith("/api/users/1"); + }); + + it("throws when the request fails", async () => { + axios.get.mockRejectedValueOnce(new Error("Network error")); + + await expect(getUser(1)).rejects.toThrow("Network error"); + }); +}); +``` + +## Simular un AxiosError + +Para probar rutas de manejo de errores que inspeccionan `error.response`, crea una instancia de `AxiosError` directamente: + +```js +import axios, { AxiosError } from "axios"; +import { vi } from "vitest"; + +const mockError = new AxiosError( + "Not Found", + "ERR_BAD_REQUEST", + {}, // config + {}, // request + { // response + status: 404, + statusText: "Not Found", + data: { message: "User not found" }, + headers: {}, + config: {}, + } +); + +axios.get.mockRejectedValueOnce(mockError); +``` + +## Usando axios-mock-adapter + +[axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter) es una librería que instala un adaptador personalizado en tu instancia de axios, interceptando las solicitudes a nivel del adaptador. Esto significa que tus interceptores siguen ejecutándose, lo que la hace más adecuada para pruebas de integración. + +```bash +npm install --save-dev axios-mock-adapter +``` + +```js +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; + +const mock = new MockAdapter(axios); + +// Mock a GET request +mock.onGet("/api/users/1").reply(200, { id: 1, name: "Jay" }); + +// Mock a POST request +mock.onPost("/api/users").reply(201, { id: 2, name: "New User" }); + +// Mock a network error +mock.onGet("/api/failing").networkError(); + +// Mock a timeout +mock.onGet("/api/slow").timeout(); +``` + +Reinicia los mocks entre pruebas: + +```js +afterEach(() => { + mock.reset(); // clear all registered handlers +}); +``` + +## Probar interceptores + +Para probar interceptores de forma aislada, crea una nueva instancia de axios en tu prueba: + +```js +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; + +describe("auth interceptor", () => { + it("attaches a Bearer token to every request", async () => { + const instance = axios.create(); + const mock = new MockAdapter(instance); + + // Add your interceptor + instance.interceptors.request.use((config) => { + config.headers.set("Authorization", "Bearer test-token"); + return config; + }); + + // Capture the request config by inspecting what mock received + let capturedConfig; + mock.onGet("/api/data").reply((config) => { + capturedConfig = config; + return [200, {}]; + }); + + await instance.get("/api/data"); + + expect(capturedConfig.headers["Authorization"]).toBe("Bearer test-token"); + }); +}); +``` + +## Consejos + +- Siempre simula a nivel de módulo (o usa `MockAdapter`) — evita simular métodos individuales en una instancia compartida, ya que el estado puede filtrarse entre pruebas. +- Usa `mockResolvedValueOnce` / `mockRejectedValueOnce` en lugar de `mockResolvedValue` para que las pruebas estén aisladas y no se afecten entre sí. +- Al probar lógica de reintento, usa `MockAdapter` para que el interceptor bajo prueba realmente se ejecute en cada intento. diff --git a/docs/es/pages/advanced/type-script.md b/docs/es/pages/advanced/type-script.md new file mode 100644 index 0000000..37fb08f --- /dev/null +++ b/docs/es/pages/advanced/type-script.md @@ -0,0 +1,8 @@ +# TypeScript + +`axios` incluye definiciones de tipos para TypeScript. Estas se encuentran en el paquete npm de `axios` mediante el archivo `index.d.ts`. Dado que axios publica de forma dual con una exportación por defecto ESM y un `module.exports` CJS, existen algunas consideraciones a tener en cuenta: + +- La configuración recomendada es usar `"moduleResolution": "node16"` (esto es implícito en `"module": "node16"`). Ten en cuenta que esto requiere TypeScript 4.7 o superior. +- Si usas ESM, tu configuración debería estar bien. +- Si compilas TypeScript a CJS y no puedes usar `"moduleResolution": "node16"`, debes habilitar `esModuleInterop`. +- Si usas TypeScript para verificar tipos en código JavaScript CJS, tu única opción es usar `"moduleResolution": "node16"`. diff --git a/docs/es/pages/advanced/x-www-form-urlencoded-format.md b/docs/es/pages/advanced/x-www-form-urlencoded-format.md new file mode 100644 index 0000000..29d3093 --- /dev/null +++ b/docs/es/pages/advanced/x-www-form-urlencoded-format.md @@ -0,0 +1,78 @@ +# Formato x-www-form-urlencoded + +## URLSearchParams + +De forma predeterminada, axios serializa los objetos JavaScript a `JSON`. Para enviar datos en el formato [`application/x-www-form-urlencoded`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) en su lugar, puedes usar la API [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams), que es [compatible](http://www.caniuse.com/#feat=urlsearchparams) con la gran mayoría de los navegadores, y con [Node.js](https://nodejs.org/api/url.html#url_class_urlsearchparams) a partir de la versión v10 (lanzada en 2018). + +```js +const params = new URLSearchParams({ foo: 'bar' }); +params.append('extraparam', 'value'); +axios.post('/foo', params); +``` + +## Cadena de consulta + +Para navegadores más antiguos o entornos sin `URLSearchParams`, puedes usar la librería [`qs`](https://github.com/ljharb/qs) para serializar objetos al formato `application/x-www-form-urlencoded`. + +```js +const qs = require('qs'); +axios.post('/foo', qs.stringify({ bar: 123 })); +``` + +En versiones muy antiguas de Node.js, puedes usar el módulo integrado `querystring` que viene con Node.js. Ten en cuenta que este módulo fue marcado como obsoleto en Node.js v16 — prefiere `URLSearchParams` o `qs` para código nuevo. + +```js +const querystring = require('querystring'); +axios.post('https://something.com/', querystring.stringify({ foo: 'bar' })); +``` + +## Serialización automática a URLSearchParams + +A partir de la versión v0.21.0, axios serializa automáticamente los objetos JavaScript a `URLSearchParams` si el encabezado `Content-Type` está establecido en `application/x-www-form-urlencoded`. Esto significa que puedes pasar un objeto JavaScript directamente a la propiedad `data` de la configuración de solicitud de axios. Por ejemplo, al pasar datos a una solicitud `POST`: + +```js +const data = { + x: 1, + arr: [1, 2, 3], + arr2: [1, [2], 3], + users: [ + { name: 'Peter', surname: 'Griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], +}; + +await axios.postForm('https://postman-echo.com/post', data, { + headers: { 'content-type': 'application/x-www-form-urlencoded' }, +}); +``` + +El objeto `data` será serializado automáticamente a `URLSearchParams` y enviado en el formato `application/x-www-form-urlencoded`. El servidor recibirá los siguientes datos: + +```json +{ + "x": "1", + "arr[]": ["1", "2", "3"], + "arr2[0]": "1", + "arr2[1][0]": "2", + "arr2[2]": "3", + "users[0][name]": "Peter", + "users[0][surname]": "Griffin", + "users[1][name]": "Thomas", + "users[1][surname]": "Anderson" +} +``` + +Si el analizador de cuerpo de tu backend (como `body-parser` de `express.js`) admite la decodificación de objetos anidados, recibirás el mismo objeto en el lado del servidor automáticamente. + +```js +var app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies + +app.post('/', function (req, res, next) { + // echo body as JSON + res.send(JSON.stringify(req.body)); +}); + +server = app.listen(3000); +``` diff --git a/docs/es/pages/getting-started/examples/commonjs.md b/docs/es/pages/getting-started/examples/commonjs.md new file mode 100644 index 0000000..a866ee1 --- /dev/null +++ b/docs/es/pages/getting-started/examples/commonjs.md @@ -0,0 +1,226 @@ +# Ejemplos en JavaScript + +## Importar la librería + +Para importar la librería en un entorno CommonJS, puedes usar la función `require`, o la declaración `import` si estás usando un empaquetador como Webpack o Rollup. + +#### Sin empaquetador + +```js +const axios = require("axios"); +``` + +#### Con empaquetador (webpack, rollup, vite, etc) + +```js +import axios from "axios"; +``` + +## Usando then/catch/finally + +Dado que axios devuelve una Promise en su núcleo, puedes optar por usar callbacks con `then`, `catch` y `finally` para manejar los datos de la respuesta, los errores y la finalización. + +### Solicitud Get + +```js +axios + .get("https://jsonplaceholder.typicode.com/posts", { + params: { + postId: 5, + }, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Solicitud Post + +```js +axios + .post("https://jsonplaceholder.typicode.com/posts", { + title: "foo", + body: "bar", + userId: 1, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Solicitud Put + +```js +axios + .put("https://jsonplaceholder.typicode.com/posts/1", { + title: "foo", + body: "bar", + userId: 1, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Solicitud Patch + +```js +axios + .patch("https://jsonplaceholder.typicode.com/posts/1", { + title: "foo", + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Solicitud Delete + +```js +axios + .delete("https://jsonplaceholder.typicode.com/posts/1") + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +## Usando async/await + +Otra forma de manejar promises es mediante `async` y `await`. Esto te permite usar bloques try/catch/finally para manejar errores y la finalización. Esto puede hacer tu código más legible y fácil de entender, y también ayuda a evitar el llamado "callback hell". + +::: tip +Nota: async/await forma parte de ECMAScript 2017 y no está disponible en Internet Explorer ni en navegadores más antiguos, así que úsalo con precaución. +::: + +### Solicitud Get + +```js +const getPosts = async () => { + try { + const response = await axios.get( + "https://jsonplaceholder.typicode.com/posts", + { + params: { + postId: 5, + }, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Solicitud Post + +```js +const createPost = async () => { + try { + const response = await axios.post( + "https://jsonplaceholder.typicode.com/posts", + { + title: "foo", + body: "bar", + userId: 1, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Solicitud Put + +```js +const updatePost = async () => { + try { + const response = await axios.put( + "https://jsonplaceholder.typicode.com/posts/1", + { + title: "foo", + body: "bar", + userId: 1, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Solicitud Patch + +```js +const updatePost = async () => { + try { + const response = await axios.patch( + "https://jsonplaceholder.typicode.com/posts/1", + { + title: "foo", + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Solicitud Delete + +```js +const deletePost = async () => { + try { + const response = await axios.delete( + "https://jsonplaceholder.typicode.com/posts/1" + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` diff --git a/docs/es/pages/getting-started/examples/typescript.md b/docs/es/pages/getting-started/examples/typescript.md new file mode 100644 index 0000000..80f4805 --- /dev/null +++ b/docs/es/pages/getting-started/examples/typescript.md @@ -0,0 +1,139 @@ +# Ejemplo en TypeScript + +## Importar tipos + +axios incluye definiciones de TypeScript de forma nativa. Puedes importar los tipos que necesites directamente desde `"axios"`: + +```ts +import axios from "axios"; +import type { AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"; +``` + +## Tipar una solicitud + +Usa un parámetro de tipo genérico en la respuesta para indicarle a TypeScript la forma que tendrán tus datos: + +```ts +import axios from "axios"; + +type Post = { + userId: number; + id: number; + title: string; + body: string; +}; + +const response = await axios.get("https://jsonplaceholder.typicode.com/posts/1"); + +console.log(response.data.title); // TypeScript knows this is a string +``` + +## Tipar una función + +Envuelve las solicitudes en funciones con tipos de retorno explícitos para maximizar la seguridad de tipos: + +```ts +import axios, { AxiosResponse } from "axios"; + +type Post = { + userId: number; + id: number; + title: string; + body: string; +}; + +const getPost = async (id: number): Promise => { + const response = await axios.get( + `https://jsonplaceholder.typicode.com/posts/${id}` + ); + return response.data; +}; +``` + +## Tipar una solicitud POST + +Puedes tipar tanto el cuerpo de la solicitud como la respuesta esperada: + +```ts +type CreatePostBody = { + title: string; + body: string; + userId: number; +}; + +type CreatePostResponse = CreatePostBody & { id: number }; + +const createPost = async (data: CreatePostBody): Promise => { + const response = await axios.post( + "https://jsonplaceholder.typicode.com/posts", + data + ); + return response.data; +}; +``` + +## Instancia de axios tipada + +Crea una instancia tipada para que la URL base y los encabezados queden definidos desde el inicio: + +```ts +import axios from "axios"; +import type { AxiosInstance } from "axios"; + +const api: AxiosInstance = axios.create({ + baseURL: "https://api.example.com", + timeout: 5000, +}); +``` + +## Interceptores tipados + +Usa `InternalAxiosRequestConfig` (no `AxiosRequestConfig`) para los interceptores de solicitud en v1.x: + +```ts +import axios from "axios"; +import type { InternalAxiosRequestConfig, AxiosResponse } from "axios"; + +api.interceptors.request.use((config: InternalAxiosRequestConfig) => { + config.headers.set("Authorization", `Bearer ${getToken()}`); + return config; +}); + +api.interceptors.response.use( + (response: AxiosResponse) => response, + (error) => Promise.reject(error) +); +``` + +## Tipar errores + +Usa `axios.isAxiosError()` para acotar el tipo de un error capturado: + +```ts +import axios, { AxiosError } from "axios"; + +type ApiError = { + message: string; + code: number; +}; + +try { + await axios.get("/api/protected-resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + // error.response?.data is typed as ApiError + console.error(error.response?.data.message); + console.error(error.response?.status); + } else { + throw error; + } +} +``` + +## Notas sobre la configuración de TypeScript + +Dado que axios publica tanto en formato ESM como CJS, hay algunas consideraciones según tu configuración: + +- La configuración recomendada es `"moduleResolution": "node16"` (implícita en `"module": "node16"`). Esto requiere TypeScript 4.7 o superior. +- Si compilas TypeScript a CJS y no puedes usar `"moduleResolution": "node16"`, habilita `"esModuleInterop": true`. +- Si usas TypeScript para verificar tipos en código JavaScript CJS, tu única opción es `"moduleResolution": "node16"`. diff --git a/docs/es/pages/getting-started/features.md b/docs/es/pages/getting-started/features.md new file mode 100644 index 0000000..eca3003 --- /dev/null +++ b/docs/es/pages/getting-started/features.md @@ -0,0 +1,42 @@ +# Características + +axios es un potente cliente HTTP que proporciona una API simple y fácil de usar para realizar solicitudes HTTP. Es compatible con todos los navegadores modernos y es ampliamente utilizado en la comunidad JavaScript. A continuación se presentan algunas de las características que hacen de axios una excelente opción para tu próximo proyecto. + +## Isomórfico + +axios es un cliente HTTP universal que puede usarse tanto en el navegador como en Node.js. Esto significa que puedes utilizar axios para hacer solicitudes a APIs desde tu código frontend y también desde tu código backend. Esto convierte a axios en una gran opción para construir progressive web apps, aplicaciones de una sola página (SPA) y aplicaciones con renderizado del lado del servidor. + +axios también es una excelente opción para equipos que trabajan tanto en frontend como en backend. Al usar axios en ambos lados, puedes contar con una API consistente para realizar solicitudes HTTP, lo que ayuda a reducir la complejidad de tu base de código. + +## Soporte para Fetch + +axios ofrece soporte de primera clase para la Fetch API, que es un reemplazo moderno de la API XHR. El adaptador es opcional y puede habilitarse mediante configuración. Se mantiene la misma API tanto para el adaptador XHR como para el adaptador Fetch, lo que facilita adoptar la Fetch API en tu base de código sin necesidad de modificar el código existente. + +## Soporte de navegadores + +axios es compatible con todos los navegadores modernos y algunos más antiguos, incluyendo Chrome, Firefox, Safari y Edge. axios es una excelente opción para construir aplicaciones web que necesiten soportar una amplia variedad de navegadores. + +## Soporte de Node.js + +axios también es compatible con una amplia gama de versiones de Node.js, con compatibilidad probada hasta la versión v12.x, lo que lo convierte en una buena opción en entornos donde actualizar a la última versión de Node.js puede no ser posible o práctico. + +Además de Node.js, axios cuenta con pruebas de humo para Bun y Deno que validan comportamientos clave en tiempo de ejecución y mejoran la confianza en la compatibilidad entre distintos entornos. + +## Características adicionales + +- Compatible con la API de Promise +- Interceptar solicitudes y respuestas +- Transformar datos de solicitudes y respuestas +- Controlador de cancelación (Abort controller) +- Tiempos de espera (timeouts) +- Serialización de parámetros de consulta con soporte para entradas anidadas +- Serialización automática del cuerpo de la solicitud a: + - JSON (application/json) + - Multipart / FormData (multipart/form-data) + - Formulario codificado en URL (application/x-www-form-urlencoded) +- Envío de formularios HTML como JSON +- Manejo automático de datos JSON en la respuesta +- Captura de progreso para navegadores y Node.js con información adicional (velocidad de transferencia, tiempo restante) +- Configuración de límites de ancho de banda para Node.js +- Compatible con FormData y Blob conformes a la especificación (incluyendo Node.js) +- Soporte del lado del cliente para protección contra XSRF diff --git a/docs/es/pages/getting-started/first-steps.md b/docs/es/pages/getting-started/first-steps.md new file mode 100644 index 0000000..956ab56 --- /dev/null +++ b/docs/es/pages/getting-started/first-steps.md @@ -0,0 +1,73 @@ +# Primeros pasos + +¡Bienvenido a la documentación de axios! Esta guía te ayudará a comenzar con axios y a realizar tu primera solicitud a una API. Si eres nuevo en axios, te recomendamos empezar aquí. + +## Instalación + +Puedes usar axios en tu proyecto de varias formas. La más común es instalarlo desde npm e incluirlo en tu proyecto. También ofrecemos soporte para jsDelivr, unpkg y más. + +#### Usando npm + +```bash +npm install axios +``` + +#### Usando pnpm + +```bash +pnpm install axios +``` + +#### Usando yarn + +```bash +yarn add axios +``` + +#### Usando bun + +```bash +bun add axios +``` + +#### Usando deno + +```bash +deno install npm:axios +``` + +#### Usando jsDelivr + +Al usar jsDelivr, recomendamos utilizar la versión minificada y fijar el número de versión para evitar cambios inesperados. Si deseas usar la última versión, puedes hacerlo omitiendo el número de versión. Esto está fuertemente desaconsejado para uso en producción, ya que puede ocasionar cambios inesperados en tu aplicación. + +```html + +``` + +#### Usando unpkg + +Al usar unpkg, recomendamos utilizar la versión minificada y fijar el número de versión para evitar cambios inesperados. Si deseas usar la última versión, puedes hacerlo omitiendo el número de versión. Esto está fuertemente desaconsejado para uso en producción, ya que puede ocasionar cambios inesperados en tu aplicación. + +```html + +``` + +## Tu primera solicitud + +Una solicitud con axios puede realizarse en tan solo dos líneas de código. Hacer tu primera solicitud con axios es muy sencillo. Puedes hacer una solicitud a cualquier API indicando la URL y el método. Por ejemplo, para hacer una solicitud GET a la API de JSONPlaceholder, puedes usar el siguiente código: + +```js +import axios from "axios"; + +const response = await axios.get( + "https://jsonplaceholder.typicode.com/posts/1" +); + +console.log(response.data); +``` + +axios ofrece una API sencilla para realizar solicitudes. Puedes usar el método `axios.get` para hacer una solicitud GET, el método `axios.post` para hacer una solicitud POST, y así sucesivamente. También puedes usar el método `axios.request` para hacer una solicitud con cualquier método. + +## Próximos pasos + +Ahora que has realizado tu primera solicitud con axios, estás listo para explorar el resto de la documentación. Puedes aprender más sobre cómo hacer solicitudes, manejar respuestas y usar axios en tus proyectos. Consulta el resto de la documentación para saber más. diff --git a/docs/es/pages/getting-started/upgrade-guide.md b/docs/es/pages/getting-started/upgrade-guide.md new file mode 100644 index 0000000..f4d7a02 --- /dev/null +++ b/docs/es/pages/getting-started/upgrade-guide.md @@ -0,0 +1,92 @@ +# Guía de actualización + +Esta guía tiene como objetivo ayudarte a actualizar tu proyecto de una versión del framework a otra. Se recomienda leer las notas de la versión de cada versión mayor desde la que estás migrando, ya que pueden contener información importante sobre cambios que rompen la compatibilidad. + +## Actualización de v0.x a v1.x + +### Cambios en la declaración de importación + +En v1.x, la declaración de importación fue modificada para usar la exportación `default`. Esto significa que deberás actualizar tus importaciones para usar la exportación `default`. + +```diff +- import { axios } from "axios"; ++ import axios from "axios"; +``` + +### Cambios en el sistema de interceptores + +En v1.x debes usar el tipo `InternalAxiosRequestConfig` para tipar el parámetro `config` en el interceptor de `request`. Esto se debe a que el parámetro `config` ahora es del tipo `InternalAxiosRequestConfig` en lugar del tipo público `AxiosRequestConfig`. + +```diff +- axios.interceptors.request.use((config: AxiosRequestConfig) => { ++ axios.interceptors.request.use((config: InternalAxiosRequestConfig) => { + return config; + }); +``` + +### Cambios en la estructura de los encabezados de solicitud + +En v1.x, la estructura de los encabezados de solicitud fue modificada para eliminar la propiedad `common`. Esto significa que deberás actualizar tu código para usar la nueva estructura de encabezados de solicitud de la siguiente manera: + +```diff +- if (request.headers?.common?.Authorization) { +- request.headers.common.Authorization = ... ++ if (request.headers?.Authorization) { ++ request.headers.Authorization = ... +``` + +Los encabezados predeterminados que antes estaban bajo `common`, `get`, `post`, etc., ahora se definen directamente en `axios.defaults.headers`: + +```diff +- axios.defaults.headers.common["Accept"] = "application/json"; ++ axios.defaults.headers["Accept"] = "application/json"; +``` + +### Datos multipart en formularios + +Si una solicitud incluye un payload de tipo `FormData`, el encabezado `Content-Type: multipart/form-data` ahora se establece automáticamente. Elimina cualquier encabezado manual para evitar duplicados: + +```diff +- axios.post("/upload", formData, { +- headers: { "Content-Type": "multipart/form-data" }, +- }); ++ axios.post("/upload", formData); +``` + +Si defines explícitamente `Content-Type: application/json`, axios ahora serializará automáticamente los datos a JSON. + +### Serialización de parámetros + +v1.x introdujo varios cambios que rompen la compatibilidad en la forma en que se serializan los parámetros de URL. Los más importantes son: + +**Los `params` ahora se codifican por porcentaje (percent-encoded) de forma predeterminada.** Si tu backend esperaba corchetes sin codificar al estilo qs, puede que necesites configurar un serializador personalizado: + +```js +import qs from 'qs'; + +axios.create({ + paramsSerializer: { + serialize: (params) => qs.stringify(params, { arrayFormat: 'brackets' }), + }, +}); +``` + +**Los objetos anidados en `params` ahora se serializan con notación de corchetes** (`foo[bar]=1`) en lugar de notación de punto. Si tu backend esperaba notación de punto, usa un serializador personalizado. + +**Los parámetros con valor `null` o `undefined`** ahora se manejan de forma consistente: los valores `null` se serializan como cadenas vacías, mientras que los valores `undefined` se omiten completamente. + +Para ver todas las opciones de configuración de serialización de parámetros, consulta la página de [Configuración de solicitud](/pages/advanced/request-config). + +### Los internos ya no se exportan + +Hemos decidido dejar de exportar los internos de axios. Esto significa que deberás actualizar tu código para usar únicamente la API pública de axios. Este cambio se realizó para simplificar la API y reducir la superficie expuesta de axios, permitiéndonos modificar los internos sin declararlos como cambios que rompen la compatibilidad. + +Consulta la [Referencia de la API](/pages/advanced/api-reference) en este sitio para obtener la información más actualizada sobre la API pública de axios. + +### Configuración de solicitud + +Hemos realizado cambios en el objeto de configuración de solicitud. Consulta la [referencia de configuración](/pages/advanced/request-config) en este sitio para obtener la información más actualizada. + +### Cambios que rompen la compatibilidad no cubiertos + +Esta guía no es exhaustiva y puede no cubrir todos los cambios que rompen la compatibilidad. Si encuentras algún problema, por favor abre un issue en el [repositorio GitHub de la documentación](https://github.com/axios/docs) con la etiqueta `breaking change`. diff --git a/docs/es/pages/misc/security.md b/docs/es/pages/misc/security.md new file mode 100644 index 0000000..c86ad6d --- /dev/null +++ b/docs/es/pages/misc/security.md @@ -0,0 +1,24 @@ +# Política de seguridad + +## Reportar una vulnerabilidad + +Si crees haber encontrado una vulnerabilidad de seguridad en el proyecto, por favor repórtanosla como se describe a continuación. Tomamos todas las vulnerabilidades de seguridad con seriedad. Si has encontrado una vulnerabilidad en una librería de terceros, por favor repórtala a los responsables de esa librería. + +## Proceso de reporte + +Por favor, no reportes vulnerabilidades de seguridad a través de los issues públicos de GitHub. Usa el canal oficial de seguridad en GitHub enviando un [aviso de seguridad](https://github.com/axios/axios/security). + +## Política de divulgación + +Cuando recibamos un reporte de vulnerabilidad de seguridad, asignaremos un responsable principal. Esta persona se encargará del reporte de la vulnerabilidad. El responsable confirmará el problema y determinará las versiones afectadas. Luego evaluará el problema y determinará la gravedad del mismo. El responsable desarrollará una solución para el problema y preparará una versión. El responsable notificará al reportante cuando la solución esté lista para ser anunciada. + +## Actualizaciones de seguridad + +Las actualizaciones de seguridad se publicarán tan pronto como sea posible después de que el parche haya sido desarrollado y probado. Notificaremos a los usuarios de la versión a través del repositorio GitHub del proyecto. También publicaremos las notas de la versión y los avisos de seguridad en la página de versiones de GitHub del proyecto. Además, marcaremos como obsoletas todas las versiones que contengan la vulnerabilidad de seguridad. + +## Colaboradores y reconocimientos de seguridad + +Nos gustaría agradecer a los siguientes investigadores de seguridad por trabajar con nosotros para ayudar a que el proyecto sea seguro para todos: + +- [Socket Dev](https://socket.dev/) +- [GitHub Security Lab](https://securitylab.github.com/) diff --git a/docs/es/pages/misc/semver.md b/docs/es/pages/misc/semver.md new file mode 100644 index 0000000..d44f140 --- /dev/null +++ b/docs/es/pages/misc/semver.md @@ -0,0 +1,44 @@ +# Versionado semántico + +El versionado semántico es un esquema de versionado que se usa para comunicar la naturaleza de los cambios en un paquete de software. Es un conjunto simple de reglas y requisitos que dictan cómo se asignan e incrementan los números de versión. + +## Versionado de axios + +axios sigue el esquema de versionado semántico. Esto significa que cada versión de axios se asigna con un número de versión compuesto por tres partes: mayor, menor y parche. El número de versión se incrementa según la naturaleza de los cambios en la versión. + +En el pasado, axios puede que no haya seguido estrictamente el versionado semántico en todo momento; sin embargo, de aquí en adelante se adoptará una adherencia mucho más estricta al esquema de versionado semántico para garantizar que los usuarios puedan confiar en los números de versión para comunicar la naturaleza de los cambios en la librería. + +A continuación se proporciona un breve resumen del esquema de versionado. + +## Formato de versión + +Un número de versión semántico consta de tres partes: + +1. Versión mayor +2. Versión menor +3. Versión de parche + +El número de versión se escribe como `MAYOR.MENOR.PARCHE`. Cada parte del número de versión tiene un significado específico: + +- **Versión mayor**: Se incrementa cuando se realizan cambios incompatibles en la API. +- **Versión menor**: Se incrementa cuando se añade funcionalidad de manera retrocompatible. +- **Versión de parche**: Se incrementa cuando se realizan correcciones de errores retrocompatibles. + +## Versiones de prelanzamiento + +Además de las tres partes del número de versión, puedes añadir una versión de prelanzamiento. Esto se hace añadiendo un guion y una serie de identificadores separados por puntos inmediatamente después de la versión de parche. Por ejemplo, `1.0.0-alpha.1`. + +Las versiones de prelanzamiento se usan para indicar que una versión es inestable y puede no satisfacer los requisitos de compatibilidad indicados por el número de versión. Las versiones de prelanzamiento se ordenan según el orden de los identificadores. Por ejemplo, `1.0.0-alpha.1` viene antes de `1.0.0-alpha.2`. + +## Rangos de versiones + +Cuando especificas un rango de versiones para un paquete, puedes usar una variedad de operadores para indicar el rango de versiones aceptables. Los siguientes operadores están disponibles: + +- `>`: Mayor que +- `<`: Menor que +- `>=`: Mayor o igual que +- `<=`: Menor o igual que +- `~`: Aproximadamente igual a +- `^`: Compatible con + +Por ejemplo, `^1.0.0` significa que cualquier versión mayor o igual a `1.0.0` y menor que `2.0.0` es aceptable. diff --git a/docs/es/pages/misc/sponsors.md b/docs/es/pages/misc/sponsors.md new file mode 100644 index 0000000..e2fc3dd --- /dev/null +++ b/docs/es/pages/misc/sponsors.md @@ -0,0 +1,185 @@ +--- +layout: page +--- + + + +
+

Patrocinadores

+

Axios cuenta con el apoyo de las siguientes organizaciones. Si deseas patrocinar Axios, visita nuestra página de Open Collective para más información.

+ +
+
+
+
+ +
+
+ {{ capitalizeFirstLetter(sponsor.tier) }} +
+
+ {{ sponsor.name }} +
+
+
+
+
+ + diff --git a/docs/fr/index.md b/docs/fr/index.md new file mode 100644 index 0000000..0200333 --- /dev/null +++ b/docs/fr/index.md @@ -0,0 +1,329 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: 'axios docs' + text: 'axios est un client HTTP simple pour le navigateur et Node.js' + image: + dark: /logo.svg + light: /logo-light.svg + alt: axios + actions: + - theme: brand + text: Démarrer + link: /fr/pages/getting-started/first-steps + - theme: alt + text: Référence API + link: /fr/pages/advanced/api-reference + +features: + - title: Implémentation simple + details: Démarrer avec axios est aussi simple qu'une seule ligne de code. Les requêtes API basiques peuvent être effectuées en 2 lignes de code. + - title: Intercepteurs puissants + details: Notre système d'intercepteurs innovant vous permet de contrôler le cycle de vie des requêtes et des réponses. Vous pouvez modifier les requêtes, les réponses et les erreurs. + - title: Support TypeScript + details: axios déclare des types et supporte pleinement TypeScript. Vous pouvez utiliser axios en toute confiance dans vos projets TypeScript. +--- + + + + +
+

Sponsors

+
+
+
+
+
+
+ +
+
+

{{ sponsor.name }}

+
+
+ {{ capitalizeFirstLetter(sponsor.tier) }} +
+
+
+
+ +
+
+
+
+
+ + diff --git a/docs/fr/pages/advanced/adapters.md b/docs/fr/pages/advanced/adapters.md new file mode 100644 index 0000000..cccaa27 --- /dev/null +++ b/docs/fr/pages/advanced/adapters.md @@ -0,0 +1,88 @@ +# Adaptateurs + +Les adaptateurs vous permettent de personnaliser la façon dont axios gère les données de la requête. Par défaut, axios utilise une liste de priorité ordonnée `['xhr', 'http', 'fetch']` et sélectionne le premier adaptateur pris en charge par l'environnement actuel. En pratique, cela signifie que `xhr` est utilisé dans les navigateurs, `http` dans Node.js, et `fetch` dans les environnements où ni l'un ni l'autre n'est disponible (comme Cloudflare Workers ou Deno). + +Écrire votre propre adaptateur vous donne un contrôle total sur la façon dont axios effectue une requête et traite la réponse — utile pour les tests, les transports personnalisés ou les environnements non standard. + +## Adaptateurs intégrés + +Vous pouvez sélectionner un adaptateur intégré par nom en utilisant l'option de configuration `adapter` : + +```js +// Utiliser l'adaptateur fetch +const instance = axios.create({ adapter: "fetch" }); + +// Utiliser l'adaptateur XHR (par défaut dans les navigateurs) +const instance = axios.create({ adapter: "xhr" }); + +// Utiliser l'adaptateur HTTP (par défaut dans Node.js) +const instance = axios.create({ adapter: "http" }); +``` + +Vous pouvez également passer un tableau de noms d'adaptateurs. axios utilisera le premier pris en charge par l'environnement actuel : + +```js +const instance = axios.create({ adapter: ["fetch", "xhr", "http"] }); +``` + +Pour plus de détails sur l'adaptateur `fetch`, consultez la page [Adaptateur Fetch](/pages/advanced/fetch-adapter). + +## Créer un adaptateur personnalisé + +Pour créer un adaptateur personnalisé, écrivez une fonction qui accepte un objet `config` et retourne une Promise qui se résout vers un objet de réponse axios valide. + +```js +import axios from "axios"; +import { settle } from "axios/unsafe/core/settle.js"; + +function myAdapter(config) { + /** + * À ce stade : + * - la configuration a été fusionnée avec les valeurs par défaut + * - les transformateurs de requête ont été exécutés + * - les intercepteurs de requête ont été exécutés + * + * L'adaptateur est maintenant responsable de l'exécution de la requête + * et du retour d'un objet de réponse valide. + */ + + return new Promise((resolve, reject) => { + // Effectuez votre logique de requête personnalisée ici. + // Cet exemple utilise l'API native fetch comme point de départ. + fetch(config.url, { + method: config.method?.toUpperCase() ?? "GET", + headers: config.headers?.toJSON() ?? {}, + body: config.data, + signal: config.signal, + }) + .then(async (fetchResponse) => { + const responseData = await fetchResponse.text(); + + const response = { + data: responseData, + status: fetchResponse.status, + statusText: fetchResponse.statusText, + headers: Object.fromEntries(fetchResponse.headers.entries()), + config, + request: null, + }; + + // settle résout ou rejette la promise selon le statut HTTP + settle(resolve, reject, response); + + /** + * Après ce point : + * - les transformateurs de réponse seront exécutés + * - les intercepteurs de réponse seront exécutés + */ + }) + .catch(reject); + }); +} + +const instance = axios.create({ adapter: myAdapter }); +``` + +::: tip +Le helper `settle` résout la promise pour les codes de statut 2xx et la rejette pour tout le reste, conformément au comportement par défaut d'axios. Si vous souhaitez une validation de statut personnalisée, utilisez plutôt l'option de configuration `validateStatus`. +::: diff --git a/docs/fr/pages/advanced/api-reference.md b/docs/fr/pages/advanced/api-reference.md new file mode 100644 index 0000000..440a06b --- /dev/null +++ b/docs/fr/pages/advanced/api-reference.md @@ -0,0 +1,331 @@ +# Référence API + +Vous trouverez ci-dessous la liste de toutes les fonctions et classes disponibles dans le package axios. Ces fonctions peuvent être utilisées et importées dans votre projet. Elles sont toutes protégées par notre engagement renouvelé à respecter le versionnage sémantique. Vous pouvez donc compter sur leur stabilité dans les versions futures, sauf en cas de changement de version majeure. + +## Instance + +L'instance `axios` est l'objet principal que vous utiliserez pour effectuer des requêtes HTTP. C'est une fonction fabrique qui crée une nouvelle instance de la classe `Axios`. L'instance `axios` dispose d'un certain nombre de méthodes pour effectuer des requêtes HTTP. Ces méthodes sont documentées dans la [section Alias de requête](/pages/advanced/request-method-aliases) de la documentation. + +## Classes + +### `Axios` + +La classe `Axios` est la classe principale que vous utiliserez pour effectuer des requêtes HTTP. C'est une fonction fabrique qui crée une nouvelle instance de la classe `Axios`. La classe `Axios` dispose d'un certain nombre de méthodes pour effectuer des requêtes HTTP. Ces méthodes sont documentées dans la [section Alias de requête](/pages/advanced/request-method-aliases) de la documentation. + +#### `constructor` + +Crée une nouvelle instance de la classe `Axios`. Le constructeur accepte un objet de configuration optionnel en argument. + +```ts +constructor(instanceConfig?: AxiosRequestConfig); +``` + +#### `request` + +Gère l'invocation de la requête et la résolution de la réponse. C'est la méthode principale pour effectuer des requêtes HTTP. Elle accepte un objet de configuration en argument et retourne une promise qui se résout vers l'objet de réponse. + +```ts +request(configOrUrl: string | AxiosRequestConfig, config: AxiosRequestConfig): Promise>; +``` + +### `CancelToken` + +La classe `CancelToken` était basée sur la proposition `tc39/proposal-cancelable-promises`. Elle était utilisée pour créer un token permettant d'annuler une requête HTTP. La classe `CancelToken` est désormais dépréciée en faveur de l'API `AbortController`. + +Depuis la version 0.22.0, la classe `CancelToken` est dépréciée et sera supprimée dans une prochaine version. Il est recommandé d'utiliser l'API `AbortController` à la place. + +La classe est exportée principalement pour des raisons de rétrocompatibilité et sera supprimée dans une prochaine version. Nous déconseillons fortement son utilisation dans de nouveaux projets et ne documentons donc pas cette API. + +## Fonctions + +### `AxiosError` + +La classe `AxiosError` est une classe d'erreur levée lorsqu'une requête HTTP échoue. Elle étend la classe `Error` et ajoute des propriétés supplémentaires à l'objet d'erreur. + +#### `constructor` + +Crée une nouvelle instance de la classe `AxiosError`. Le constructeur accepte en argument un message, un code, une configuration, une requête et une réponse optionnels. + +```ts +constructor(message?: string, code?: string, config?: InternalAxiosRequestConfig, request?: any, response?: AxiosResponse); +``` + +#### `properties` + +La classe `AxiosError` fournit les propriétés suivantes : + +```ts +// Instance de config. +config?: InternalAxiosRequestConfig; + +// Code d'erreur. +code?: string; + +// Instance de requête. +request?: any; + +// Instance de réponse. +response?: AxiosResponse; + +// Booléen indiquant si l'erreur est une `AxiosError`. +isAxiosError: boolean; + +// Code de statut HTTP de l'erreur. +status?: number; + +// Méthode utilitaire pour convertir l'erreur en objet JSON. +toJSON: () => object; + +// Cause de l'erreur. +cause?: Error; +``` + +### `AxiosHeaders` + +La classe `AxiosHeaders` est une classe utilitaire permettant de gérer les en-têtes HTTP. Elle fournit des méthodes pour manipuler les en-têtes, comme l'ajout, la suppression et la récupération d'en-têtes. + +Seules les méthodes principales sont documentées ici. Pour la liste complète des méthodes, référez-vous au fichier de déclaration de types. + +#### `constructor` + +Crée une nouvelle instance de la classe `AxiosHeaders`. Le constructeur accepte un objet d'en-têtes optionnel en argument. + +```ts +constructor(headers?: RawAxiosHeaders | AxiosHeaders | string); +``` + +#### `set` + +Ajoute un en-tête à l'objet d'en-têtes. + +```ts +set(headerName?: string, value?: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders; +set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders; +``` + +#### `get` + +Récupère un en-tête depuis l'objet d'en-têtes. + +```ts +get(headerName: string, parser: RegExp): RegExpExecArray | null; +get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue; +``` + +#### `has` + +Vérifie si un en-tête existe dans l'objet d'en-têtes. + +```ts +has(header: string, matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `delete` + +Supprime un en-tête de l'objet d'en-têtes. + +```ts +delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `clear` + +Supprime tous les en-têtes de l'objet d'en-têtes. + +```ts +clear(matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `normalize` + +Normalise l'objet d'en-têtes. + +```ts +normalize(format: boolean): AxiosHeaders; +``` + +#### `concat` + +Concatène des objets d'en-têtes. + +```ts +concat(...targets: Array): AxiosHeaders; +``` + +#### `toJSON` + +Convertit l'objet d'en-têtes en objet JSON. + +```ts +toJSON(asStrings?: boolean): RawAxiosHeaders; +``` + +### `CanceledError` + +La classe `CanceledError` est une classe d'erreur levée lorsqu'une requête HTTP est annulée. Elle étend la classe `AxiosError`. + +### `Cancel` + +La classe `Cancel` est un alias de la classe `CanceledError`. Elle est exportée pour des raisons de rétrocompatibilité et sera supprimée dans une prochaine version. + +### `isCancel` + +Une fonction qui vérifie si une erreur est une `CanceledError`. Utile pour distinguer les annulations intentionnelles des erreurs inattendues. + +```ts +isCancel(value: any): boolean; +``` + +```js +import axios from "axios"; + +const controller = new AbortController(); + +axios.get("/api/data", { signal: controller.signal }).catch((error) => { + if (axios.isCancel(error)) { + console.log("Request was cancelled:", error.message); + } else { + console.error("Unexpected error:", error); + } +}); + +controller.abort("User navigated away"); +``` + +### `isAxiosError` + +Une fonction qui vérifie si une erreur est une `AxiosError`. Utilisez-la dans les blocs `catch` pour accéder en toute sécurité aux propriétés spécifiques d'axios comme `error.response` et `error.config`. + +```ts +isAxiosError(value: any): value is AxiosError; +``` + +```js +import axios from "axios"; + +try { + await axios.get("/api/resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + // error.response, error.config, error.code sont tous disponibles + console.error("HTTP error", error.response?.status, error.message); + } else { + // Une erreur non-axios (ex. une erreur de programmation) + throw error; + } +} +``` + +### `all` + +La fonction `all` est une fonction utilitaire qui prend un tableau de promises et retourne une promise unique qui se résout lorsque toutes les promises du tableau sont résolues. La fonction `all` est désormais dépréciée en faveur de la méthode `Promise.all`. Il est recommandé d'utiliser `Promise.all` à la place. + +Depuis la version 0.22.0, la fonction `all` est dépréciée et sera supprimée dans une prochaine version. + +### `spread` + +La fonction `spread` est une fonction utilitaire qui peut être utilisée pour décomposer un tableau d'arguments dans un appel de fonction. Utile lorsque vous avez un tableau d'arguments à passer à une fonction qui en accepte plusieurs. + +```ts +spread(callback: (...args: T[]) => R): (array: T[]) => R; +``` + +### `toFormData` + +Convertit un objet JavaScript simple (ou imbriqué) en instance `FormData`. Utile pour construire programmatiquement des données de formulaire multipart à partir d'un objet. + +```ts +toFormData(sourceObj: object, formData?: FormData, options?: FormSerializerOptions): FormData; +``` + +```js +import { toFormData } from "axios"; + +const data = { name: "Jay", avatar: fileBlob }; +const form = toFormData(data); +// form est maintenant une instance FormData prête à être envoyée +await axios.post("/api/users", form); +``` + +### `formToJSON` + +Convertit une instance `FormData` en objet JavaScript simple. Utile pour lire les données d'un formulaire dans un format structuré. + +```ts +formToJSON(form: FormData): object; +``` + +```js +import { formToJSON } from "axios"; + +const form = new FormData(); +form.append("name", "Jay"); +form.append("role", "admin"); + +const obj = formToJSON(form); +console.log(obj); // { name: "Jay", role: "admin" } +``` + +### `getAdapter` + +Résout et retourne une fonction d'adaptateur par nom ou en passant un tableau de noms candidats. axios utilise ceci en interne pour sélectionner le meilleur adaptateur disponible pour l'environnement actuel. + +```ts +getAdapter(adapters: string | string[]): AxiosAdapter; +``` + +```js +import { getAdapter } from "axios"; + +// Obtenir explicitement l'adaptateur fetch +const fetchAdapter = getAdapter("fetch"); + +// Obtenir le meilleur adaptateur disponible depuis une liste de priorité +const adapter = getAdapter(["fetch", "xhr", "http"]); +``` + +### `mergeConfig` + +Fusionne deux objets de configuration axios, en appliquant la même stratégie de fusion profonde qu'axios utilise en interne lors de la combinaison des valeurs par défaut avec les options par requête. Les valeurs ultérieures ont la priorité. + +```ts +mergeConfig(config1: AxiosRequestConfig, config2: AxiosRequestConfig): AxiosRequestConfig; +``` + +```js +import { mergeConfig } from "axios"; + +const base = { baseURL: "https://api.example.com", timeout: 5000 }; +const override = { timeout: 10000, headers: { "X-Custom": "value" } }; + +const merged = mergeConfig(base, override); +// { baseURL: "https://api.example.com", timeout: 10000, headers: { "X-Custom": "value" } } +``` + +## Constantes + +### `HttpStatusCode` + +Un objet contenant une liste de codes de statut HTTP sous forme de constantes nommées. Utilisez-le pour écrire des conditions lisibles plutôt que des nombres bruts. + +```js +import axios, { HttpStatusCode } from "axios"; + +try { + const response = await axios.get("/api/resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + if (error.response?.status === HttpStatusCode.NotFound) { + console.error("Resource not found"); + } else if (error.response?.status === HttpStatusCode.Unauthorized) { + console.error("Authentication required"); + } + } +} +``` + +## Divers + +### `VERSION` + +La version actuelle du package `axios`. Il s'agit d'une chaîne représentant le numéro de version du package, mise à jour à chaque nouvelle version. diff --git a/docs/fr/pages/advanced/authentication.md b/docs/fr/pages/advanced/authentication.md new file mode 100644 index 0000000..d0691fc --- /dev/null +++ b/docs/fr/pages/advanced/authentication.md @@ -0,0 +1,142 @@ +# Authentification + +La plupart des APIs requièrent une forme d'authentification. Cette page couvre les schémas les plus courants pour attacher des identifiants aux requêtes axios. + +## Tokens Bearer (JWT) + +L'approche la plus courante consiste à attacher un JWT dans l'en-tête `Authorization`. La façon la plus propre de procéder est via un intercepteur de requête sur votre instance axios, afin que le token soit lu à jour à chaque requête : + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +api.interceptors.request.use((config) => { + const token = localStorage.getItem("access_token"); + if (token) { + config.headers.set("Authorization", `Bearer ${token}`); + } + return config; +}); +``` + +## Authentification HTTP Basic + +Pour les APIs utilisant l'authentification HTTP Basic, passez l'option `auth`. axios encodera les identifiants et définira automatiquement l'en-tête `Authorization` : + +```js +const response = await axios.get("https://api.example.com/data", { + auth: { + username: "myUser", + password: "myPassword", + }, +}); +``` + +::: tip +Pour les tokens Bearer et les clés API, utilisez un en-tête `Authorization` personnalisé plutôt que l'option `auth` — `auth` est réservé à l'authentification HTTP Basic. +::: + +## Clés API + +Les clés API sont généralement passées sous forme d'en-tête ou de paramètre de requête, selon ce qu'attend l'API : + +```js +// En tant qu'en-tête +const api = axios.create({ + baseURL: "https://api.example.com", + headers: { "X-API-Key": "your-api-key-here" }, +}); + +// En tant que paramètre de requête +const response = await axios.get("https://api.example.com/data", { + params: { apiKey: "your-api-key-here" }, +}); +``` + +## Renouvellement de token + +Lorsque les tokens d'accès expirent, vous devez les renouveler silencieusement et réessayer la requête échouée. Un intercepteur de réponse est l'endroit idéal pour implémenter cela : + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +// Suivre si un renouvellement est déjà en cours pour éviter des appels parallèles +let isRefreshing = false; +let failedQueue = []; + +const processQueue = (error, token = null) => { + failedQueue.forEach((prom) => { + if (error) { + prom.reject(error); + } else { + prom.resolve(token); + } + }); + failedQueue = []; +}; + +api.interceptors.response.use( + (response) => response, + async (error) => { + const originalRequest = error.config; + + if (error.response?.status === 401 && !originalRequest._retry) { + if (isRefreshing) { + // Mettre la requête en file d'attente jusqu'à la fin du renouvellement + return new Promise((resolve, reject) => { + failedQueue.push({ resolve, reject }); + }) + .then((token) => { + originalRequest.headers["Authorization"] = `Bearer ${token}`; + return api(originalRequest); + }) + .catch((err) => Promise.reject(err)); + } + + originalRequest._retry = true; + isRefreshing = true; + + try { + const { data } = await axios.post("/auth/refresh", { + refreshToken: localStorage.getItem("refresh_token"), + }); + + const newToken = data.access_token; + localStorage.setItem("access_token", newToken); + api.defaults.headers.common["Authorization"] = `Bearer ${newToken}`; + + processQueue(null, newToken); + return api(originalRequest); + } catch (refreshError) { + processQueue(refreshError, null); + // Rediriger vers la connexion ou émettre un événement + localStorage.removeItem("access_token"); + window.location.href = "/login"; + return Promise.reject(refreshError); + } finally { + isRefreshing = false; + } + } + + return Promise.reject(error); + } +); +``` + +## Authentification par cookie + +Pour les APIs basées sur les sessions qui s'appuient sur les cookies, définissez `withCredentials: true` pour inclure les cookies dans les requêtes cross-origin : + +```js +const api = axios.create({ + baseURL: "https://api.example.com", + withCredentials: true, // envoyer les cookies avec chaque requête +}); +``` + +::: warning +`withCredentials: true` exige que le serveur réponde avec `Access-Control-Allow-Credentials: true` et un `Access-Control-Allow-Origin` spécifique (pas de joker). +::: diff --git a/docs/fr/pages/advanced/cancellation.md b/docs/fr/pages/advanced/cancellation.md new file mode 100644 index 0000000..0328650 --- /dev/null +++ b/docs/fr/pages/advanced/cancellation.md @@ -0,0 +1,70 @@ +# Annulation + +À partir de la version v0.22.0, Axios prend en charge AbortController pour annuler les requêtes de manière propre. Cette fonctionnalité est disponible dans le navigateur et dans Node.js lorsque vous utilisez une version d'Axios qui prend en charge AbortController. Pour annuler une requête, vous devez créer une instance d'`AbortController` et passer son `signal` à l'option `signal` de la requête. + +```js +const controller = new AbortController(); + +axios + .get("/foo/bar", { + signal: controller.signal, + }) + .then(function (response) { + //... + }); +// annuler la requête +controller.abort(); +``` + +## CancelToken + +Vous pouvez également utiliser l'API `CancelToken` pour annuler les requêtes. Cette API est dépréciée et sera supprimée dans la prochaine version majeure. Il est recommandé d'utiliser `AbortController` à la place. Vous pouvez créer un token d'annulation en utilisant la factory `CancelToken.source` comme indiqué ci-dessous : + +```js +const CancelToken = axios.CancelToken; +const source = CancelToken.source(); + +axios + .get("/user/12345", { + cancelToken: source.token, + }) + .catch(function (thrown) { + if (axios.isCancel(thrown)) { + console.log("Request canceled", thrown.message); + } else { + // gérer l'erreur + } + }); + +axios.post( + "/user/12345", + { + name: "new name", + }, + { + cancelToken: source.token, + } +); + +// annuler la requête (le paramètre message est optionnel) +source.cancel("Operation canceled by the user."); +``` + +Vous pouvez également créer un token d'annulation en passant une fonction d'exécution au constructeur `CancelToken` : + +```js +const CancelToken = axios.CancelToken; +let cancel; + +axios.get("/user/12345", { + cancelToken: new CancelToken(function executor(c) { + // Une fonction d'exécution reçoit une fonction d'annulation comme paramètre + cancel = c; + }), +}); + +// annuler la requête +cancel(); +``` + +Vous pouvez annuler plusieurs requêtes avec le même token d'annulation ou le même abort controller. Si un token d'annulation est déjà annulé au moment où une requête Axios démarre, alors la requête est annulée immédiatement, sans aucune tentative d'effectuer une vraie requête. diff --git a/docs/fr/pages/advanced/config-defaults.md b/docs/fr/pages/advanced/config-defaults.md new file mode 100644 index 0000000..3bcec7b --- /dev/null +++ b/docs/fr/pages/advanced/config-defaults.md @@ -0,0 +1,48 @@ +# Valeurs par défaut de configuration + +axios vous permet de spécifier des valeurs par défaut de configuration qui seront appliquées à toutes les requêtes. Vous pouvez définir des valeurs par défaut pour `baseURL`, `headers`, `timeout` et d'autres propriétés. Voici un exemple d'utilisation des valeurs par défaut de configuration : + +```js +axios.defaults.baseURL = "https://jsonplaceholder.typicode.com/posts"; +axios.defaults.headers.common["Authorization"] = AUTH_TOKEN; +axios.defaults.headers.post["Content-Type"] = + "application/x-www-form-urlencoded"; +``` + +## Valeurs par défaut d'une instance personnalisée + +Les instances axios sont déclarées avec leurs propres valeurs par défaut lors de leur création. Ces valeurs par défaut peuvent être remplacées en définissant la propriété `defaults` de l'instance. Voici un exemple d'utilisation des valeurs par défaut d'une instance personnalisée : + +```js +var instance = axios.create({ + baseURL: "https://jsonplaceholder.typicode.com/posts", + timeout: 1000, + headers: { Authorization: "foobar" }, +}); + +instance.defaults.headers.common["Authorization"] = AUTH_TOKEN; +``` + +## Ordre de priorité de la configuration + +La configuration est fusionnée selon un ordre de priorité. L'ordre est le suivant : d'abord les valeurs par défaut de la bibliothèque, puis les propriétés par défaut de l'instance, et enfin l'argument de configuration de la requête. Voici un exemple de cet ordre de priorité : + +Créons d'abord une instance avec les valeurs par défaut fournies par la bibliothèque. À ce stade, la valeur de configuration du timeout est `0`, valeur par défaut de la bibliothèque. + +```js +const instance = axios.create(); +``` + +Nous allons maintenant remplacer la valeur par défaut du timeout pour l'instance par `2500` millisecondes. Désormais, toutes les requêtes utilisant cette instance attendront 2,5 secondes avant d'expirer. + +```js +instance.defaults.timeout = 2500; +``` + +Enfin, nous allons effectuer une requête avec un timeout de `5000` millisecondes. Cette requête attendra 5 secondes avant d'expirer. + +```js +instance.get("/longRequest", { + timeout: 5000, +}); +``` diff --git a/docs/fr/pages/advanced/create-an-instance.md b/docs/fr/pages/advanced/create-an-instance.md new file mode 100644 index 0000000..13e3e15 --- /dev/null +++ b/docs/fr/pages/advanced/create-an-instance.md @@ -0,0 +1,87 @@ +# Créer une instance + +`axios.create()` vous permet de créer une instance axios préconfigurée. L'instance partage la même API de requête et de réponse que l'objet `axios` par défaut, mais utilise la configuration que vous fournissez comme base pour chaque requête. C'est la façon recommandée d'utiliser axios dans toute application dépassant un seul fichier. + +```ts +import axios from "axios"; + +const instance = axios.create({ + baseURL: "https://api.example.com", + timeout: 5000, + headers: { "X-Custom-Header": "foobar" }, +}); +``` + +La méthode `create` accepte l'objet complet de [Configuration de requête](/pages/advanced/request-config). Vous pouvez ensuite utiliser l'instance exactement comme l'objet axios par défaut : + +```js +const response = await instance.get("/users/1"); +``` + +## Pourquoi utiliser une instance ? + +### URL de base par service + +Dans la plupart des applications, vous communiquez avec plusieurs API. Créer une instance distincte par service évite de répéter l'URL de base à chaque appel : + +```js +const githubApi = axios.create({ baseURL: "https://api.github.com" }); +const internalApi = axios.create({ baseURL: "https://api.internal.example.com" }); + +const { data: repos } = await githubApi.get("/users/axios/repos"); +const { data: users } = await internalApi.get("/users"); +``` + +### En-têtes d'authentification partagés + +Attachez un token d'authentification à chaque requête d'une instance sans toucher aux autres : + +```js +const authApi = axios.create({ + baseURL: "https://api.example.com", + headers: { + Authorization: `Bearer ${getToken()}`, + }, +}); +``` + +### Délais d'attente et nouvelles tentatives par service + +Différents services ont des caractéristiques de fiabilité différentes. Définissez un délai court pour les services temps réel et un délai long pour les traitements par lots : + +```js +const realtimeApi = axios.create({ baseURL: "https://realtime.example.com", timeout: 2000 }); +const batchApi = axios.create({ baseURL: "https://batch.example.com", timeout: 60000 }); +``` + +### Intercepteurs isolés + +Les intercepteurs ajoutés à une instance ne s'appliquent qu'à cette instance, ce qui permet de bien séparer les responsabilités : + +```js +const loggingApi = axios.create({ baseURL: "https://api.example.com" }); + +loggingApi.interceptors.request.use((config) => { + console.log(`→ ${config.method?.toUpperCase()} ${config.url}`); + return config; +}); +``` + +## Surcharger les valeurs par défaut par requête + +La configuration passée au moment de la requête remplace toujours les valeurs par défaut de l'instance : + +```js +const api = axios.create({ timeout: 5000 }); + +// Cette requête spécifique utilise un délai de 30 secondes à la place +await api.get("/slow-endpoint", { timeout: 30000 }); +``` + +::: tip +Les valeurs par défaut de l'instance peuvent également être modifiées après sa création en écrivant dans `instance.defaults` : + +```js +instance.defaults.headers.common["Authorization"] = `Bearer ${newToken}`; +``` +::: diff --git a/docs/fr/pages/advanced/error-handling.md b/docs/fr/pages/advanced/error-handling.md new file mode 100644 index 0000000..f6232f1 --- /dev/null +++ b/docs/fr/pages/advanced/error-handling.md @@ -0,0 +1,72 @@ +# Gestion des erreurs + +axios peut lever de nombreux types d'erreurs différents. Certaines de ces erreurs sont causées par axios lui-même, tandis que d'autres sont causées par le serveur ou le client. Le tableau suivant liste la structure générale de l'erreur levée : + +| Propriété | Définition | +| --------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| message | Un résumé rapide du message d'erreur et du statut avec lequel elle a échoué. | +| name | Définit l'origine de l'erreur. Pour axios, ce sera toujours une `AxiosError`. | +| stack | Fournit la trace de pile de l'erreur. | +| config | Un objet de configuration axios avec les configurations d'instance spécifiques définies par l'utilisateur au moment de la requête. | +| code | Représente une erreur identifiée par axios. Le tableau ci-dessous liste les définitions spécifiques des erreurs internes d'axios. | +| status | Code de statut de la réponse HTTP. Consultez [ici](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) pour la signification des codes de statut HTTP courants. | + +Voici une liste des erreurs potentielles identifiées par axios : + +| Code | Définition | +| ------------------------- | --------------------------------------------------------------------------------------------- | +| ERR_BAD_OPTION_VALUE | Valeur invalide ou non supportée fournie dans la configuration axios. | +| ERR_BAD_OPTION | Option invalide fournie dans la configuration axios. | +| ECONNABORTED | Indique généralement que la requête a expiré (sauf si `transitional.clarifyTimeoutError` est défini) ou a été abandonnée par le navigateur ou son plugin. | +| ETIMEDOUT | La requête a expiré en dépassant la limite de temps par défaut d'axios. `transitional.clarifyTimeoutError` doit être défini à `true`, sinon une erreur générique `ECONNABORTED` sera levée à la place. | +| ERR_NETWORK | Problème lié au réseau. Dans le navigateur, cette erreur peut également être causée par une violation de politique [CORS](https://developer.mozilla.org/ru/docs/Web/HTTP/Guides/CORS) ou de [contenu mixte](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content). Le navigateur ne permet pas au code JS de clarifier la raison réelle de l'erreur pour des raisons de sécurité ; veuillez vérifier la console. | +| ERR_FR_TOO_MANY_REDIRECTS | La requête est redirigée trop de fois ; dépasse le nombre maximum de redirections spécifié dans la configuration axios. | +| ERR_DEPRECATED | Fonctionnalité ou méthode dépréciée utilisée dans axios. | +| ERR_BAD_RESPONSE | La réponse ne peut pas être analysée correctement ou est dans un format inattendu. Généralement lié à une réponse avec un code de statut `5xx`. | +| ERR_BAD_REQUEST | La requête a un format inattendu ou des paramètres requis manquants. Généralement lié à une réponse avec un code de statut `4xx`. | +| ERR_CANCELED | Fonctionnalité ou méthode annulée explicitement par l'utilisateur via un AbortSignal (ou un CancelToken). | +| ERR_NOT_SUPPORT | Fonctionnalité ou méthode non supportée dans l'environnement axios actuel. | +| ERR_INVALID_URL | URL invalide fournie pour la requête axios. | + +## Gérer les erreurs + +Le comportement par défaut d'axios est de rejeter la promise si la requête échoue. Cependant, vous pouvez également capturer l'erreur et la gérer comme bon vous semble. Voici un exemple de capture d'une erreur : + +```js +axios.get("/user/12345").catch(function (error) { + if (error.response) { + // La requête a été effectuée et le serveur a répondu avec un code de statut + // qui n'est pas dans la plage 2xx + console.log(error.response.data); + console.log(error.response.status); + console.log(error.response.headers); + } else if (error.request) { + // La requête a été effectuée mais aucune réponse n'a été reçue + // `error.request` est une instance de XMLHttpRequest dans le navigateur et une instance de + // http.ClientRequest dans Node.js + console.log(error.request); + } else { + // Quelque chose s'est produit lors de la configuration de la requête qui a déclenché une erreur + console.log("Error", error.message); + } + console.log(error.config); +}); +``` + +En utilisant l'option de configuration `validateStatus`, vous pouvez remplacer la condition par défaut (status >= 200 && status < 300) et définir le ou les codes HTTP qui doivent lever une erreur. + +```js +axios.get("/user/12345", { + validateStatus: function (status) { + return status < 500; // Résoudre uniquement si le code de statut est inférieur à 500 + }, +}); +``` + +En utilisant la méthode `toJSON`, vous pouvez obtenir un objet avec plus d'informations sur l'erreur. + +```js +axios.get("/user/12345").catch(function (error) { + console.log(error.toJSON()); +}); +``` diff --git a/docs/fr/pages/advanced/fetch-adapter.md b/docs/fr/pages/advanced/fetch-adapter.md new file mode 100644 index 0000000..df724ae --- /dev/null +++ b/docs/fr/pages/advanced/fetch-adapter.md @@ -0,0 +1,81 @@ +# Adaptateur Fetch + +L'adaptateur `fetch` est un nouvel adaptateur introduit à partir de la version 1.7.0. Il permet d'utiliser axios avec l'API `fetch`, vous offrant ainsi le meilleur des deux mondes. Par défaut, `fetch` sera utilisé si les adaptateurs `xhr` et `http` ne sont pas disponibles dans le build, ou non supportés par l'environnement. Pour l'utiliser par défaut, il doit être sélectionné explicitement en définissant l'option `adapter` à `fetch` lors de la création d'une instance axios. + +```js +import axios from 'axios'; + +const instance = axios.create({ + adapter: 'fetch', +}); +``` + +L'adaptateur supporte les mêmes fonctionnalités que l'adaptateur `xhr`, notamment la capture de la progression des envois et téléchargements. Il supporte également des types de réponse supplémentaires tels que `stream` et `formdata` (si l'environnement les prend en charge). + +## Fetch personnalisé + +À partir de `v1.12.0`, vous pouvez personnaliser l'adaptateur fetch pour utiliser une fonction `fetch` personnalisée au lieu de celle de l'environnement global. Vous pouvez passer une fonction `fetch`, ainsi que des constructeurs `Request` et `Response` personnalisés via l'option de configuration `env`. Cela est utile lorsque vous travaillez avec des environnements personnalisés ou des frameworks d'application qui fournissent leur propre implémentation de `fetch`. + +::: info +Lorsque vous utilisez une fonction `fetch` personnalisée, vous devrez peut-être également fournir des constructeurs `Request` et `Response` correspondants. Si vous les omettez, les constructeurs globaux seront utilisés. Si votre `fetch` personnalisé est incompatible avec les constructeurs globaux, passez `null` pour les désactiver. + +**Remarque :** Définir `Request` et `Response` à `null` rendra impossible pour l'adaptateur fetch de capturer la progression des envois et téléchargements. +::: + +### Exemple de base + +```js +import customFetchFunction from 'customFetchModule'; + +const instance = axios.create({ + adapter: 'fetch', + onDownloadProgress(e) { + console.log('downloadProgress', e); + }, + env: { + fetch: customFetchFunction, + Request: null, // null -> désactiver le constructeur + Response: null, + }, +}); +``` + +### Utilisation avec Tauri + +[Tauri](https://tauri.app/plugin/http-client/) fournit une fonction `fetch` de plateforme qui contourne les restrictions CORS du navigateur pour les requêtes effectuées depuis la couche native. L'exemple ci-dessous montre une configuration minimale pour utiliser axios dans une application Tauri avec ce fetch personnalisé. + +```js +import { fetch } from '@tauri-apps/plugin-http'; +import axios from 'axios'; + +const instance = axios.create({ + adapter: 'fetch', + onDownloadProgress(e) { + console.log('downloadProgress', e); + }, + env: { + fetch, + }, +}); + +const { data } = await instance.get('https://google.com'); +``` + +### Utilisation avec SvelteKit + +[SvelteKit](https://svelte.dev/docs/kit/web-standards#Fetch-APIs) fournit une implémentation `fetch` personnalisée pour les fonctions `load` côté serveur qui gère la transmission des cookies et les URLs relatives. Comme son `fetch` est incompatible avec l'API `URL` standard, axios doit être configuré pour l'utiliser explicitement, et les constructeurs `Request` et `Response` globaux doivent être désactivés. + +```js +export async function load({ fetch }) { + const { data: post } = await axios.get('https://jsonplaceholder.typicode.com/posts/1', { + adapter: 'fetch', + env: { + fetch, + Request: null, + Response: null, + }, + }); + + return { post }; +} +``` diff --git a/docs/fr/pages/advanced/file-posting.md b/docs/fr/pages/advanced/file-posting.md new file mode 100644 index 0000000..977e261 --- /dev/null +++ b/docs/fr/pages/advanced/file-posting.md @@ -0,0 +1,99 @@ +# Envoi de fichiers + +axios simplifie l'envoi de fichiers. Utilisez `postForm` ou `FormData` lorsque vous avez besoin d'envois `multipart/form-data`. + +## Fichier unique (navigateur) + +Passez un objet `File` directement comme valeur de champ — axios le détectera et utilisera automatiquement le type de contenu correct : + +```js +await axios.postForm("https://httpbin.org/post", { + description: "My profile photo", + file: document.querySelector("#fileInput").files[0], +}); +``` + +## Plusieurs fichiers (navigateur) + +Passez une `FileList` pour envoyer tous les fichiers sélectionnés en une seule fois. Ils seront tous envoyés sous le même nom de champ (`files[]`) : + +```js +await axios.postForm( + "https://httpbin.org/post", + document.querySelector("#fileInput").files +); +``` + +Pour utiliser des noms de champs distincts pour chaque fichier, construisez un objet `FormData` manuellement : + +```js +const formData = new FormData(); +formData.append("avatar", avatarFile); +formData.append("cover", coverFile); + +await axios.post("https://httpbin.org/post", formData); +``` + +## Suivi de la progression de l'envoi (navigateur) + +Utilisez le callback `onUploadProgress` pour afficher une barre de progression ou un pourcentage à vos utilisateurs : + +```js +await axios.postForm("https://httpbin.org/post", { + file: document.querySelector("#fileInput").files[0], +}, { + onUploadProgress: (progressEvent) => { + const percent = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log(`Upload progress: ${percent}%`); + }, +}); +``` + +Consultez [Capture de progression](/pages/advanced/progress-capturing) pour la liste complète des champs disponibles sur l'événement de progression. + +## Fichiers dans Node.js + +Dans Node.js, utilisez `fs.createReadStream` pour envoyer un fichier depuis le système de fichiers sans le charger entièrement en mémoire : + +```js +import fs from "fs"; +import FormData from "form-data"; +import axios from "axios"; + +const form = new FormData(); +form.append("file", fs.createReadStream("/path/to/file.jpg")); +form.append("description", "My uploaded file"); + +await axios.post("https://httpbin.org/post", form); +``` + +::: tip +Le package npm `form-data` est nécessaire dans les environnements Node.js pour créer des objets `FormData`. Dans Node.js moderne (v18+), le `FormData` global est disponible nativement. +::: + +## Envoi d'un Buffer (Node.js) + +Vous pouvez également envoyer directement un `Buffer` en mémoire : + +```js +const buffer = Buffer.from("Hello, world!"); + +const form = new FormData(); +form.append("file", buffer, { + filename: "hello.txt", + contentType: "text/plain", + knownLength: buffer.length, +}); + +await axios.post("https://httpbin.org/post", form); +``` + +::: warning +La capture de la progression d'envoi de `FormData` n'est actuellement pas supportée dans les environnements Node.js. +::: + +::: danger +Lors de l'envoi d'un stream lisible dans Node.js, définissez `maxRedirects: 0` pour empêcher le package `follow-redirects` de buffériser l'intégralité du stream en RAM. +::: diff --git a/docs/fr/pages/advanced/header-methods.md b/docs/fr/pages/advanced/header-methods.md new file mode 100644 index 0000000..b43af21 --- /dev/null +++ b/docs/fr/pages/advanced/header-methods.md @@ -0,0 +1,188 @@ +# Méthodes d'en-têtes + +Avec l'introduction de la nouvelle classe `AxiosHeaders`, Axios fournit un ensemble de méthodes pour manipuler les en-têtes. Ces méthodes sont utilisées pour définir, récupérer et supprimer des en-têtes de manière plus pratique que la manipulation directe de l'objet d'en-têtes. + +## Constructeur `new AxiosHeaders(headers?)` + +Le constructeur de la classe `AxiosHeaders` accepte un objet optionnel avec des en-têtes pour initialiser l'instance. L'objet d'en-têtes peut contenir un nombre quelconque d'en-têtes, et les clés sont insensibles à la casse. + +```js +constructor(headers?: RawAxiosHeaders | AxiosHeaders | string); +``` + +Pour plus de commodité, vous pouvez passer une chaîne avec des en-têtes séparés par un caractère de nouvelle ligne. Les en-têtes sont alors analysés et ajoutés à l'instance. + +```js +const headers = new AxiosHeaders(` +Host: www.bing.com +User-Agent: curl/7.54.0 +Accept: */*`); + +console.log(headers); + +// Object [AxiosHeaders] { +// host: 'www.bing.com', +// 'user-agent': 'curl/7.54.0', +// accept: '*/*' +// } +``` + +## Set + +La méthode `set` est utilisée pour définir des en-têtes sur l'instance d'`AxiosHeaders`. La méthode peut être appelée avec un seul nom d'en-tête et une valeur, un objet avec plusieurs en-têtes, ou une chaîne avec des en-têtes séparés par un caractère de nouvelle ligne. La méthode accepte également un paramètre optionnel `rewrite` qui contrôle le comportement de définition de l'en-tête. + +```js +set(headerName, value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher); +set(headerName, value, rewrite?: (this: AxiosHeaders, value: string, name: string) => boolean); +set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean); +``` + +L'argument `rewrite` contrôle le comportement d'écrasement : + +- `false` - ne pas écraser si la valeur de l'en-tête est définie (n'est pas undefined) +- `undefined` (défaut) - écraser l'en-tête sauf si sa valeur est définie à false +- `true` - écraser dans tous les cas + +L'option peut également accepter une fonction définie par l'utilisateur qui détermine si la valeur doit être écrasée ou non. La fonction reçoit la valeur actuelle, le nom de l'en-tête et l'objet d'en-têtes comme arguments. + +`AxiosHeaders` conserve la casse de la première clé correspondante qu'il voit. Vous pouvez utiliser cela pour préserver la casse spécifique d'un en-tête en initialisant une clé avec `undefined` puis en définissant les valeurs ultérieurement. Voir [Préserver la casse d'un en-tête spécifique](/pages/advanced/headers#preserving-a-specific-header-case). + +## Get + +La méthode `get` est utilisée pour récupérer la valeur d'un en-tête. La méthode peut être appelée avec un seul nom d'en-tête, un matcher optionnel ou un analyseur. Le matcher est par défaut `true`. L'analyseur peut être une expression régulière utilisée pour extraire la valeur de l'en-tête. + +```js +get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue; +get(headerName: string, parser: RegExp): RegExpExecArray | null; +``` + +Voici un exemple de quelques-unes des utilisations possibles de la méthode `get` : + +```js +const headers = new AxiosHeaders({ + 'Content-Type': 'multipart/form-data; boundary=Asrf456BGe4h', +}); + +console.log(headers.get('Content-Type')); +// multipart/form-data; boundary=Asrf456BGe4h + +console.log(headers.get('Content-Type', true)); // analyser les paires clé-valeur depuis une chaîne séparée par des délimiteurs \s,;= : +// [Object: null prototype] { +// 'multipart/form-data': undefined, +// boundary: 'Asrf456BGe4h' +// } + +console.log( + headers.get('Content-Type', (value, name, headers) => { + return String(value).replace(/a/g, 'ZZZ'); + }) +); +// multipZZZrt/form-dZZZtZZZ; boundZZZry=Asrf456BGe4h + +console.log(headers.get('Content-Type', /boundary=(\w+)/)?.[0]); +// boundary=Asrf456BGe4h +``` + +## Has + +La méthode `has` est utilisée pour vérifier si un en-tête existe dans l'instance d'`AxiosHeaders`. La méthode peut être appelée avec un seul nom d'en-tête et un matcher optionnel. + +```js +has(header: string, matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +Retourne true si l'en-tête est défini (n'a pas de valeur undefined). +::: + +## Delete + +La méthode `delete` est utilisée pour supprimer un en-tête de l'instance d'`AxiosHeaders`. La méthode peut être appelée avec un seul nom d'en-tête et un matcher optionnel. + +```js +delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +Retourne true si au moins un en-tête a été supprimé. +::: + +## Clear + +La méthode `clear` est utilisée pour supprimer tous les en-têtes de l'instance d'`AxiosHeaders` si rien n'est passé. Si un matcher est passé, seuls les en-têtes correspondant au matcher sont supprimés ; dans ce cas, le matcher est utilisé pour correspondre au nom de l'en-tête plutôt qu'à sa valeur. + +```js +clear(matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +Retourne true si au moins un en-tête a été effacé. +::: + +## Normalize + +Si l'objet d'en-têtes a été modifié directement, cela peut créer des doublons avec le même nom mais dans des casses différentes. Cette méthode normalise l'objet d'en-têtes en combinant les clés dupliquées en une seule. Axios utilise cette méthode en interne après l'appel de chaque intercepteur. Définissez `format` à `true` pour convertir les noms d'en-têtes en minuscules et capitaliser les premières lettres (cOntEnt-type => Content-Type) ou `false` pour conserver le format original. + +```js +const headers = new AxiosHeaders({ + foo: '1', +}); + +headers.Foo = '2'; +headers.FOO = '3'; + +console.log(headers.toJSON()); // [Object: null prototype] { foo: '1', Foo: '2', FOO: '3' } +console.log(headers.normalize().toJSON()); // [Object: null prototype] { foo: '3' } +console.log(headers.normalize(true).toJSON()); // [Object: null prototype] { Foo: '3' } +``` + +::: info +Retourne `this` pour le chaînage. +::: + +## Concat + +Fusionne l'instance avec des cibles dans une nouvelle instance AxiosHeaders. Si la cible est une chaîne, elle sera analysée comme des en-têtes HTTP bruts. Si la cible est une instance AxiosHeaders, elle sera fusionnée avec l'instance actuelle. + +Utile pour les préréglages de casse lors de la composition d'en-têtes. Par exemple : + +```js +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); +``` + +```js +concat(...targets: Array): AxiosHeaders; +``` + +::: info +Retourne une nouvelle instance AxiosHeaders. +::: + +## toJSON + +Résout toutes les valeurs d'en-têtes internes dans un nouvel objet à prototype null. Définissez `asStrings` à true pour résoudre les tableaux en une chaîne contenant tous les éléments, séparés par des virgules. + +```js +toJSON(asStrings?: boolean): RawAxiosHeaders; +``` + +## From + +Retourne une nouvelle instance d'`AxiosHeaders` créée à partir des en-têtes bruts passés, ou retourne simplement l'objet d'en-têtes donné s'il s'agit déjà d'une instance d'`AxiosHeaders`. + +```js +from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders; +``` + +## Raccourcis + +Les raccourcis suivants sont disponibles : + +- `setContentType`, `getContentType`, `hasContentType` +- `setContentLength`, `getContentLength`, `hasContentLength` +- `setAccept`, `getAccept`, `hasAccept` +- `setUserAgent`, `getUserAgent`, `hasUserAgent` +- `setContentEncoding`, `getContentEncoding`, `hasContentEncoding` diff --git a/docs/fr/pages/advanced/headers.md b/docs/fr/pages/advanced/headers.md new file mode 100644 index 0000000..f60ca00 --- /dev/null +++ b/docs/fr/pages/advanced/headers.md @@ -0,0 +1,153 @@ +# En-têtes + +Axios expose sa propre classe AxiosHeaders pour manipuler les en-têtes en utilisant une API de type Map qui garantit des clés insensibles à la casse. Cette classe est utilisée en interne par Axios pour gérer les en-têtes, mais elle est également exposée à l'utilisateur pour plus de commodité. Bien que les en-têtes HTTP soient insensibles à la casse, Axios conservera la casse de l'en-tête original pour des raisons stylistiques et comme solution de contournement lorsque des serveurs tiennent incorrectement compte de la casse des en-têtes. L'ancienne méthode de manipulation directe de l'objet d'en-têtes est toujours disponible, mais dépréciée et non recommandée pour un usage futur. + +## Travailler avec les en-têtes + +L'instance d'objet AxiosHeaders peut contenir différents types de valeurs internes qui contrôlent la logique de définition et de fusion. L'objet d'en-têtes final est obtenu par Axios en appelant la méthode toJSON. L'objet AxiosHeaders est également itérable, vous pouvez donc l'utiliser dans des boucles ou le convertir en tableau ou en objet. + +Les valeurs d'en-tête peuvent être de l'un des types suivants : + +- `string` - valeur de chaîne normale qui sera envoyée au serveur +- `null` - ignorer l'en-tête lors de la conversion en JSON +- `false` - ignorer l'en-tête lors de la conversion en JSON, indique également que la méthode set doit être appelée avec l'option rewrite définie à true pour écraser cette valeur (Axios l'utilise en interne pour permettre aux utilisateurs de refuser l'installation de certains en-têtes comme User-Agent ou Content-Type) +- `undefined` - la valeur n'est pas définie + +::: warning +La valeur de l'en-tête est considérée comme définie si elle n'est pas undefined. +::: + +L'objet d'en-têtes est toujours initialisé à l'intérieur des intercepteurs et des transformateurs, comme illustré dans l'exemple suivant : + +```js +axios.interceptors.request.use((request: InternalAxiosRequestConfig) => { + request.headers.set("My-header", "value"); + + request.headers.set({ + "My-set-header1": "my-set-value1", + "My-set-header2": "my-set-value2", + }); + + // Désactiver la définition ultérieure de cet en-tête par Axios + request.headers.set("User-Agent", false); + + request.headers.setContentType("text/plain"); + + // L'accès direct comme celui-ci est déprécié + request.headers["My-set-header2"] = "newValue"; + + return request; +}); +``` + +Vous pouvez itérer sur un AxiosHeaders en utilisant n'importe quelle méthode itérable, comme une boucle for-of, forEach, ou l'opérateur spread : + +```js +const headers = new AxiosHeaders({ + foo: '1', + bar: '2', + baz: '3', +}); + +for (const [header, value] of headers) { + console.log(header, value); +} + +// foo 1 +// bar 2 +// baz 3 +``` + +## Définir des en-têtes sur une requête + +L'endroit le plus courant pour définir des en-têtes est l'option `headers` dans votre configuration de requête ou de configuration d'instance : + +```js +// Sur une seule requête +await axios.get('/api/data', { + headers: { + 'Accept-Language': 'en-US', + 'X-Request-ID': 'abc123', + }, +}); + +// Sur une instance (appliqué à chaque requête) +const api = axios.create({ + headers: { + 'X-App-Version': '2.0.0', + }, +}); +``` + +## Préserver la casse d'un en-tête spécifique + +Les noms d'en-têtes Axios sont insensibles à la casse, mais `AxiosHeaders` conserve la casse de la première clé correspondante qu'il voit. Si vous avez besoin d'une casse spécifique pour un serveur avec un comportement non standard sensible à la casse, définissez un préréglage de casse dans les valeurs par défaut puis définissez les valeurs normalement. + +```js +const api = axios.create(); + +api.defaults.headers.common = { + 'content-type': undefined, + accept: undefined, +}; + +await api.put(url, data, { + headers: { + 'Content-Type': 'application/octet-stream', + Accept: 'application/json', + }, +}); +``` + +Vous pouvez également le faire avec `AxiosHeaders` directement lors de la composition d'en-têtes : + +```js +import axios, { AxiosHeaders } from 'axios'; + +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); + +await axios.put(url, data, { headers }); +``` + +## Définir des en-têtes dans un intercepteur + +Les intercepteurs sont l'endroit approprié pour attacher des en-têtes dynamiques comme les tokens d'authentification, car le token peut ne pas être disponible au moment où l'instance est créée : + +```js +api.interceptors.request.use((config) => { + const token = getAuthToken(); // lire au moment de la requête + config.headers.set('Authorization', `Bearer ${token}`); + return config; +}); +``` + +## Lire les en-têtes de réponse + +Les en-têtes de réponse sont disponibles sur `response.headers` en tant qu'instance d'`AxiosHeaders`. Tous les noms d'en-têtes sont en minuscules : + +```js +const response = await axios.get('/api/data'); + +console.log(response.headers['content-type']); +// application/json; charset=utf-8 + +console.log(response.headers.get('x-request-id')); +// abc123 +``` + +## Supprimer un en-tête par défaut + +Pour refuser un en-tête qu'axios définit par défaut (comme `Content-Type` ou `User-Agent`), définissez sa valeur à `false` : + +```js +await axios.post('/api/data', payload, { + headers: { + 'Content-Type': false, // laisser le navigateur le définir automatiquement (ex. pour FormData) + }, +}); +``` + +Pour plus de détails sur l'API complète des méthodes `AxiosHeaders`, consultez la page [Méthodes d'en-têtes](/pages/advanced/header-methods). diff --git a/docs/fr/pages/advanced/html-form-processing.md b/docs/fr/pages/advanced/html-form-processing.md new file mode 100644 index 0000000..1aecbf8 --- /dev/null +++ b/docs/fr/pages/advanced/html-form-processing.md @@ -0,0 +1,57 @@ +# Traitement de formulaires HTML (navigateur) + +Vous pouvez également envoyer un formulaire directement depuis un élément de formulaire HTML. Cela est utile lorsque vous avez un formulaire dans votre page et que vous souhaitez le soumettre sans aucun code JavaScript. + +```js +await axios.postForm('https://httpbin.org/post', document.querySelector('#htmlForm')); +``` + +Les objets `FormData` et `HTMLForm` peuvent également être envoyés en `JSON` en définissant explicitement l'en-tête `Content-Type` à `application/json` : + +```js +await axios.post('https://httpbin.org/post', document.querySelector('#htmlForm'), { + headers: { + 'Content-Type': 'application/json', + }, +}); +``` + +Voici un exemple de formulaire valide pouvant être soumis par le code ci-dessus : + +```html +
+ + + + + + + + + +
+``` + +Le formulaire ci-dessus sera soumis sous la forme : + +```json +{ + "foo": "1", + "deep": { + "prop": "2", + "prop spaced": "3" + }, + "baz": ["4", "5"], + "user": { + "age": "value2" + } +} +``` + +::: warning +L'envoi de Blobs/Fichiers en JSON (base64) n'est actuellement pas supporté. +::: diff --git a/docs/fr/pages/advanced/http2.md b/docs/fr/pages/advanced/http2.md new file mode 100644 index 0000000..86b7ffc --- /dev/null +++ b/docs/fr/pages/advanced/http2.md @@ -0,0 +1,72 @@ +# HTTP2 + +Le support expérimental de HTTP/2 a été ajouté à l'adaptateur `http` dans la version `1.13.0`. Il est disponible uniquement dans les environnements Node.js. + +## Utilisation de base + +Utilisez l'option `httpVersion` pour sélectionner la version du protocole pour une requête. En la définissant à `2`, vous activez HTTP/2. + +```js +const { data, headers, status } = await axios.post( + "https://httpbin.org/post", + form, + { + httpVersion: 2, + }, +); +``` + +## `http2Options` + +Des options natives supplémentaires pour l'appel interne `session.request()` peuvent être passées via l'objet de configuration `http2Options`. Cela inclut également le paramètre personnalisé `sessionTimeout`, qui contrôle la durée (en millisecondes) pendant laquelle une session HTTP/2 inactive est maintenue avant d'être fermée. La valeur par défaut est `1000ms`. + +```js +{ + httpVersion: 2, + http2Options: { + rejectUnauthorized: false, // accepter les certificats auto-signés (développement uniquement) + sessionTimeout: 5000, // maintenir la session inactive pendant 5 secondes + }, +} +``` + +::: warning +Le support HTTP/2 est actuellement expérimental. L'API peut changer dans les prochaines versions mineures ou de correctifs. +::: + +## Exemple complet + +L'exemple ci-dessous envoie une requête POST `multipart/form-data` via HTTP/2 et suit à la fois la progression de l'envoi et du téléchargement. + +```js +const form = new FormData(); +form.append("foo", "123"); + +const { data, headers, status } = await axios.post( + "https://httpbin.org/post", + form, + { + httpVersion: 2, + http2Options: { + // rejectUnauthorized: false, + // sessionTimeout: 1000 + }, + onUploadProgress(e) { + console.log("upload progress", e); + }, + onDownloadProgress(e) { + console.log("download progress", e); + }, + responseType: "arraybuffer", + }, +); +``` + +## Référence de configuration + +| Option | Type | Défaut | Description | +|---|---|---|---| +| `httpVersion` | `number` | `1` | Version du protocole HTTP à utiliser. Définissez à `2` pour activer HTTP/2. | +| `http2Options.sessionTimeout` | `number` | `1000` | Durée en millisecondes avant qu'une session HTTP/2 inactive soit fermée. | + +Toutes les autres options natives de `session.request()` supportées par le module `http2` intégré de Node.js peuvent également être passées dans `http2Options`. diff --git a/docs/fr/pages/advanced/interceptors.md b/docs/fr/pages/advanced/interceptors.md new file mode 100644 index 0000000..46685dc --- /dev/null +++ b/docs/fr/pages/advanced/interceptors.md @@ -0,0 +1,116 @@ +# Intercepteurs + +Les intercepteurs sont un mécanisme puissant permettant d'intercepter et de modifier les requêtes et réponses HTTP. Ils sont très similaires aux middlewares dans Express.js. Un intercepteur est une fonction exécutée avant l'envoi d'une requête et avant la réception d'une réponse. Les intercepteurs sont utiles pour de nombreuses tâches telles que la journalisation, la modification des en-têtes de requête et la modification de la réponse. + +L'utilisation de base des intercepteurs est la suivante : + +```js +// Ajouter un intercepteur de requête +axios.interceptors.request.use( + function (config) { + // Effectuez une action avant l'envoi de la requête + return config; + }, + function (error) { + // Traitez l'erreur de requête + return Promise.reject(error); + } +); + +// Ajouter un intercepteur de réponse +axios.interceptors.response.use( + function (response) { + // Tout code de statut dans la plage 2xx déclenchera cette fonction + // Traitez les données de réponse + return response; + }, + function (error) { + // Tout code de statut en dehors de la plage 2xx déclenchera cette fonction + // Traitez l'erreur de réponse + return Promise.reject(error); + } +); +``` + +## Supprimer des intercepteurs + +Vous pouvez supprimer n'importe quel intercepteur en utilisant la méthode `eject` sur l'intercepteur que vous souhaitez supprimer. Vous pouvez également supprimer tous les intercepteurs en appelant la méthode `clear` sur l'objet `axios.interceptors`. Voici un exemple de suppression d'un intercepteur : + +```js +// Éjecter l'intercepteur de requête +const myInterceptor = axios.interceptors.request.use(function () { + /*...*/ +}); +axios.interceptors.request.eject(myInterceptor); + +// Éjecter l'intercepteur de réponse +const myInterceptor = axios.interceptors.response.use(function () { + /*...*/ +}); +axios.interceptors.response.eject(myInterceptor); +``` + +Voici un exemple de suppression de tous les intercepteurs : + +```js +const instance = axios.create(); +instance.interceptors.request.use(function () { + /*...*/ +}); +instance.interceptors.request.clear(); // Supprime les intercepteurs des requêtes +instance.interceptors.response.use(function () { + /*...*/ +}); +instance.interceptors.response.clear(); // Supprime les intercepteurs des réponses +``` + +## Comportement par défaut des intercepteurs + +Lorsque vous ajoutez des intercepteurs de requête, ils sont considérés comme asynchrones par défaut. Cela peut provoquer un délai dans l'exécution de votre requête axios lorsque le thread principal est bloqué (une promise est créée en coulisses pour l'intercepteur et votre requête est placée en bas de la pile d'appels). Si vos intercepteurs de requête sont synchrones, vous pouvez ajouter un indicateur à l'objet d'options qui indiquera à axios d'exécuter le code de manière synchrone et d'éviter tout délai dans l'exécution des requêtes. + +```js +axios.interceptors.request.use( + function (config) { + config.headers.test = "I am only a header!"; + return config; + }, + null, + { synchronous: true } +); +``` + +## Intercepteurs avec `runWhen` + +Si vous souhaitez exécuter un intercepteur particulier en fonction d'une vérification au moment de l'exécution, vous pouvez ajouter une fonction `runWhen` à l'objet d'options. L'intercepteur ne sera pas exécuté si et seulement si le résultat de `runWhen` est `false`. La fonction sera appelée avec l'objet de configuration (n'oubliez pas que vous pouvez également y lier vos propres arguments). Cela peut être utile lorsque vous avez un intercepteur de requête asynchrone qui ne doit s'exécuter que dans certaines conditions. + +```js +function onGetCall(config) { + return config.method === "get"; +} +axios.interceptors.request.use( + function (config) { + config.headers.test = "special get headers"; + return config; + }, + null, + { runWhen: onGetCall } +); +``` + +## Intercepteurs multiples + +Vous pouvez ajouter plusieurs intercepteurs à la même requête ou réponse. Les règles suivantes s'appliquent pour plusieurs intercepteurs dans la même chaîne, dans l'ordre indiqué ci-dessous : + +- Chaque intercepteur est exécuté +- Les intercepteurs de requête sont exécutés dans l'ordre inverse (LIFO). +- Les intercepteurs de réponse sont exécutés dans l'ordre où ils ont été ajoutés (FIFO). +- Seul le résultat du dernier intercepteur est retourné +- Chaque intercepteur reçoit le résultat de son prédécesseur +- Lorsqu'un intercepteur de réussite lève une exception : + - L'intercepteur de réussite suivant n'est pas appelé + - L'intercepteur d'échec suivant est appelé + - Une fois capturée, un autre intercepteur de réussite suivant est à nouveau appelé (comme dans une chaîne de promises). + +::: tip +Pour une compréhension approfondie du fonctionnement des intercepteurs, vous pouvez lire les cas de test disponibles [ici](https://github.com/axios/axios/blob/v1.x/test/specs/interceptors.spec.js). +::: diff --git a/docs/fr/pages/advanced/multipart-form-data-format.md b/docs/fr/pages/advanced/multipart-form-data-format.md new file mode 100644 index 0000000..5119cf4 --- /dev/null +++ b/docs/fr/pages/advanced/multipart-form-data-format.md @@ -0,0 +1,120 @@ +# Format multipart/form-data + +axios peut envoyer des requêtes au format `multipart/form-data`. Ce format est couramment utilisé lors de l'envoi de fichiers. Pour envoyer une requête dans ce format, vous devez créer un objet `FormData` et y ajouter les données. Vous pouvez ensuite passer l'objet `FormData` à la propriété `data` de la configuration de requête axios. + +```js +const formData = new FormData(); +formData.append("foo", "bar"); + +axios.post("https://httpbin.org/post", formData); +``` + +Dans Node.js, vous pouvez utiliser la bibliothèque `form-data` comme suit : + +```js +const FormData = require("form-data"); + +const form = new FormData(); +form.append("my_field", "my value"); +form.append("my_buffer", Buffer.alloc(10)); +form.append("my_file", fs.createReadStream("/foo/bar.jpg")); + +axios.post("https://example.com", form); +``` + +## Sérialisation automatique vers FormData + +À partir de la version v0.27.0, Axios prend en charge la sérialisation automatique d'objets en objet FormData si l'en-tête Content-Type de la requête est défini à multipart/form-data. Cela signifie que vous pouvez passer directement un objet JavaScript à la propriété data de la configuration de requête axios. Par exemple lors de l'envoi de données vers une requête POST : + +```js +import axios from "axios"; + +axios + .post( + "https://httpbin.org/post", + { x: 1 }, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ) + .then(({ data }) => console.log(data)); +``` + +Dans la version Node.js, le polyfill ([`form-data`](https://github.com/form-data/form-data)) est utilisé par défaut. Vous pouvez remplacer la classe FormData en définissant la variable de configuration env.FormData, mais vous n'en aurez probablement pas besoin dans la plupart des cas : + +```js +const axios = require("axios"); +var FormData = require("form-data"); + +axios + .post( + "https://httpbin.org/post", + { x: 1, buf: Buffer.alloc(10) }, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ) + .then(({ data }) => console.log(data)); +``` + +## Terminaisons supportées + +Le sérialiseur FormData d'Axios supporte quelques terminaisons spéciales pour effectuer les opérations suivantes : + +- `{}` - sérialiser la valeur avec JSON.stringify +- `[]` - décomposer l'objet de type tableau en champs séparés avec la même clé + +::: warning +Remarque : l'opération de décomposition/expansion sera utilisée par défaut sur les tableaux et les objets FileList +::: + +## Configurer le sérialiseur FormData + +Le sérialiseur FormData supporte des options supplémentaires via la propriété d'objet config.formSerializer pour gérer les cas particuliers : + +- `visitor: Function` - fonction visiteur définie par l'utilisateur qui sera appelée récursivement pour sérialiser l'objet de données en objet FormData en suivant des règles personnalisées. +- `dots: boolean = false` - utiliser la notation pointée au lieu de crochets pour sérialiser les tableaux et les objets ; +- `metaTokens: boolean = true` - ajouter la terminaison spéciale (ex. `user{}: '{"name": "John"}'`) dans la clé FormData. Le body-parser du backend pourrait potentiellement utiliser ces méta-informations pour analyser automatiquement la valeur en JSON. +- `indexes: null|false|true = false` - contrôle comment les index seront ajoutés aux clés décomposées d'objets de type tableau plat + - `null` - ne pas ajouter de crochets (`arr: 1`, `arr: 2`, `arr: 3`) + - `false` (défaut) - ajouter des crochets vides (`arr[]: 1`, `arr[]: 2`, `arr[]: 3`) + - `true` - ajouter des crochets avec index (`arr[0]: 1`, `arr[1]: 2`, `arr[2]: 3`) + +Par exemple, si nous avons un objet comme celui-ci : + +```js +const obj = { + x: 1, + arr: [1, 2, 3], + arr2: [1, [2], 3], + users: [ + { name: "Peter", surname: "Griffin" }, + { name: "Thomas", surname: "Anderson" }, + ], + "obj2{}": [{ x: 1 }], +}; +``` + +Les étapes suivantes seront exécutées en interne par le sérialiseur Axios : + +```js +const formData = new FormData(); +formData.append("x", "1"); +formData.append("arr[]", "1"); +formData.append("arr[]", "2"); +formData.append("arr[]", "3"); +formData.append("arr2[0]", "1"); +formData.append("arr2[1][0]", "2"); +formData.append("arr2[2]", "3"); +formData.append("users[0][name]", "Peter"); +formData.append("users[0][surname]", "Griffin"); +formData.append("users[1][name]", "Thomas"); +formData.append("users[1][surname]", "Anderson"); +formData.append("obj2{}", '[{"x":1}]'); +``` + +Axios supporte les méthodes raccourcies suivantes : `postForm`, `putForm`, `patchForm` qui sont simplement les méthodes HTTP correspondantes avec l'en-tête `Content-Type` prédéfini à `multipart/form-data`. diff --git a/docs/fr/pages/advanced/progress-capturing.md b/docs/fr/pages/advanced/progress-capturing.md new file mode 100644 index 0000000..2f85481 --- /dev/null +++ b/docs/fr/pages/advanced/progress-capturing.md @@ -0,0 +1,55 @@ +# Capture de progression + +Axios prend en charge la capture de la progression des envois et téléchargements dans les environnements navigateur et Node.js. La fréquence des événements de progression est limitée à 3 fois par seconde. Cela permet d'éviter de surcharger le navigateur avec des événements de progression. Voici un exemple de capture d'événements de progression : + +```js +await axios.post(url, data, { + onUploadProgress: function (axiosProgressEvent) { + /*{ + loaded: number; + total?: number; + progress?: number; // dans la plage [0..1] + bytes: number; // nombre d'octets transférés depuis le dernier déclenchement (delta) + estimated?: number; // temps estimé en secondes + rate?: number; // vitesse d'envoi en octets + upload: true; // indicateur d'envoi + }*/ + }, + + onDownloadProgress: function (axiosProgressEvent) { + /*{ + loaded: number; + total?: number; + progress?: number; + bytes: number; + estimated?: number; + rate?: number; // vitesse de téléchargement en octets + download: true; // indicateur de téléchargement + }*/ + }, +}); +``` + +Vous pouvez également transmettre les événements de progression d'envoi et de téléchargement vers un stream lisible dans Node.js. Cela est utile lorsque vous souhaitez afficher la progression de manière personnalisée. Voici un exemple de transmission des événements de progression : + +```js +const { data } = await axios.post(SERVER_URL, readableStream, { + onUploadProgress: ({ progress }) => { + console.log((progress * 100).toFixed(2)); + }, + + headers: { + "Content-Length": contentLength, + }, + + maxRedirects: 0, // éviter de buffériser l'intégralité du stream +}); +``` + +::: warning +La capture de la progression d'envoi de FormData n'est actuellement pas supportée dans les environnements Node.js +::: + +::: danger +Il est recommandé de désactiver les redirections en définissant maxRedirects: 0 pour envoyer le stream dans l'environnement Node.js, car le package follow-redirects bufférisera l'intégralité du stream en RAM sans suivre l'algorithme de « backpressure » +::: diff --git a/docs/fr/pages/advanced/promises.md b/docs/fr/pages/advanced/promises.md new file mode 100644 index 0000000..286dc95 --- /dev/null +++ b/docs/fr/pages/advanced/promises.md @@ -0,0 +1,81 @@ +# Promises + +axios est construit sur l'API Promise native d'ES6. Chaque requête axios retourne une Promise qui se résout vers un objet de réponse ou se rejette avec une erreur. Si votre environnement ne supporte pas les Promises ES6, vous devrez les polyfiller — par exemple avec [es6-promise](https://github.com/stefanpenner/es6-promise). + +## then / catch / finally + +Comme axios retourne une Promise standard, vous pouvez utiliser `.then()`, `.catch()` et `.finally()` pour gérer le résultat : + +```js +axios.get("/api/users") + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error("Request failed:", error.message); + }) + .finally(() => { + console.log("Request finished"); + }); +``` + +## async / await + +L'approche recommandée pour la plupart des bases de code est `async/await`, qui rend le code asynchrone lisible comme du code synchrone : + +```js +async function fetchUser(id) { + try { + const response = await axios.get(`/api/users/${id}`); + return response.data; + } catch (error) { + console.error("Failed to fetch user:", error.message); + throw error; + } +} +``` + +## Requêtes parallèles + +Comme axios retourne une Promise standard, vous pouvez utiliser `Promise.all` pour effectuer plusieurs requêtes simultanément et attendre qu'elles se terminent toutes : + +```js +const [users, posts] = await Promise.all([ + axios.get("/api/users"), + axios.get("/api/posts"), +]); + +console.log(users.data, posts.data); +``` + +::: tip +`Promise.all` rejettera dès que l'une des requêtes échoue. Si vous souhaitez gérer les échecs partiels, utilisez plutôt `Promise.allSettled`. +::: + +```js +const results = await Promise.allSettled([ + axios.get("/api/users"), + axios.get("/api/posts"), +]); + +results.forEach((result) => { + if (result.status === "fulfilled") { + console.log(result.value.data); + } else { + console.error("Request failed:", result.reason.message); + } +}); +``` + +## Chaînage de requêtes + +Vous pouvez chaîner des appels `.then()` pour exécuter des requêtes séquentiellement, en passant les données d'une requête à la suivante : + +```js +axios.get("/api/user/1") + .then(({ data: user }) => axios.get(`/api/posts?userId=${user.id}`)) + .then(({ data: posts }) => { + console.log("Posts for user:", posts); + }) + .catch(console.error); +``` diff --git a/docs/fr/pages/advanced/rate-limiting.md b/docs/fr/pages/advanced/rate-limiting.md new file mode 100644 index 0000000..074bb70 --- /dev/null +++ b/docs/fr/pages/advanced/rate-limiting.md @@ -0,0 +1,62 @@ +# Limitation de débit + +axios prend en charge la limitation de bande passante dans l'environnement Node.js via l'adaptateur HTTP. Cela vous permet de plafonner la vitesse d'envoi ou de téléchargement des données, ce qui est utile pour les opérations en masse, les tâches en arrière-plan ou le scraping respectueux qui ne doit pas saturer une connexion. + +## `maxRate` + +L'option `maxRate` accepte soit un nombre (octets par seconde) soit un tableau où la première valeur est la limite d'envoi et la deuxième valeur est la limite de téléchargement. Utilisez `[uploadRate]` pour limiter uniquement l'envoi, ou `[uploadRate, downloadRate]` pour limiter les deux sens. Lorsqu'un nombre unique est passé, la même limite s'applique à l'envoi et au téléchargement. + +```js +// Limiter l'envoi et le téléchargement à 100 Ko/s +await axios.get(URL, { maxRate: 100 * 1024 }); + +// Limiter l'envoi à 100 Ko/s, le téléchargement à 500 Ko/s +await axios.get(URL, { maxRate: [100 * 1024, 500 * 1024] }); +``` + +::: warning +`maxRate` n'est supporté que par l'adaptateur HTTP Node.js. Il n'a aucun effet dans les environnements navigateur. +::: + +## Limitation du débit d'envoi + +Plafonnez la vitesse d'envoi tout en journalisant la progression en même temps : + +```js +const { data } = await axios.post(SERVER_URL, myBuffer, { + onUploadProgress: ({ progress, rate }) => { + const percent = (progress * 100).toFixed(1); + const kbps = (rate / 1024).toFixed(1); + console.log(`Upload [${percent}%] at ${kbps} KB/s`); + }, + + maxRate: [100 * 1024], // plafonner l'envoi à 100 Ko/s +}); +``` + +## Limitation du débit de téléchargement + +Plafonnez la vitesse de téléchargement pour les réponses volumineuses : + +```js +const { data } = await axios.get(FILE_URL, { + onDownloadProgress: ({ progress, rate }) => { + const percent = (progress * 100).toFixed(1); + const kbps = (rate / 1024).toFixed(1); + console.log(`Download [${percent}%] at ${kbps} KB/s`); + }, + + maxRate: [Infinity, 200 * 1024], // pas de limite d'envoi, 200 Ko/s en téléchargement + responseType: "arraybuffer", +}); +``` + +## Limitation combinée envoi et téléchargement + +Passez les deux limites sous forme de tableau pour contrôler les deux sens simultanément : + +```js +await axios.post(SERVER_URL, largeBuffer, { + maxRate: [50 * 1024, 500 * 1024], // 50 Ko/s en envoi, 500 Ko/s en téléchargement +}); +``` diff --git a/docs/fr/pages/advanced/request-config.md b/docs/fr/pages/advanced/request-config.md new file mode 100644 index 0000000..f3b1133 --- /dev/null +++ b/docs/fr/pages/advanced/request-config.md @@ -0,0 +1,350 @@ +# Configuration de requête + +La configuration de requête est utilisée pour paramétrer la requête. Un large éventail d'options est disponible, mais la seule option obligatoire est `url`. Si l'objet de configuration ne contient pas de champ `method`, la méthode par défaut est `GET`. + +### `url` + +L'`url` est l'URL vers laquelle la requête est envoyée. Il peut s'agir d'une chaîne de caractères ou d'une instance de `URL`. + +### `method` + +La `method` est la méthode HTTP à utiliser pour la requête. La méthode par défaut est `GET`. + +### `baseURL` + +La `baseURL` est l'URL de base à ajouter en préfixe à l'`url`, sauf si celle-ci est une URL absolue. Utile pour effectuer des requêtes vers le même domaine sans avoir à répéter le nom de domaine et tout préfixe d'API ou de version. + +### `allowAbsoluteUrls` + +`allowAbsoluteUrls` détermine si les URLs absolues peuvent remplacer une `baseUrl` configurée. Lorsqu'elle est définie à `true` (valeur par défaut), les valeurs absolues de `url` remplacent `baseUrl`. Lorsqu'elle est définie à `false`, les valeurs absolues de `url` sont toujours précédées de `baseUrl`. + +### `transformRequest` + +La fonction `transformRequest` vous permet de modifier les données de la requête avant leur envoi au serveur. Cette fonction est appelée avec les données de la requête comme seul argument. Elle ne s'applique que pour les méthodes de requête `PUT`, `POST`, `PATCH` et `DELETE`. La dernière fonction du tableau doit retourner une chaîne ou une instance de Buffer, ArrayBuffer, FormData ou Stream. + +### `transformResponse` + +La fonction `transformResponse` vous permet de modifier les données de la réponse avant qu'elles ne soient transmises aux fonctions `then` ou `catch`. Cette fonction est appelée avec les données de la réponse comme seul argument. + +### `headers` + +Les `headers` sont les en-têtes HTTP à envoyer avec la requête. L'en-tête `Content-Type` est défini à `application/json` par défaut. + +### `params` + +Les `params` sont les paramètres d'URL à envoyer avec la requête. Il doit s'agir d'un objet simple ou d'un objet URLSearchParams. Si l'`url` contient des paramètres de requête, ils seront fusionnés avec l'objet `params`. + +### `paramsSerializer` + +La fonction `paramsSerializer` vous permet de sérialiser l'objet `params` avant son envoi au serveur. Plusieurs options sont disponibles pour cette fonction ; veuillez vous référer à l'exemple de configuration complète en bas de cette page. + +### `data` + +Les `data` sont les données à envoyer comme corps de la requête. Il peut s'agir d'une chaîne, d'un objet simple, d'un Buffer, d'un ArrayBuffer, d'un FormData, d'un Stream ou d'un URLSearchParams. Ne s'applique que pour les méthodes de requête `PUT`, `POST`, `DELETE` et `PATCH`. Sans `transformRequest`, doit être de l'un des types suivants : + +- chaîne, objet simple, ArrayBuffer, ArrayBufferView, URLSearchParams +- Navigateur uniquement : FormData, File, Blob +- Node uniquement : Stream, Buffer, FormData (package form-data) + +### `timeout` + +Le `timeout` est le nombre de millisecondes avant l'expiration de la requête. Si la requête dure plus longtemps que `timeout`, elle sera annulée. + +### `withCredentials` + +La propriété `withCredentials` indique si les requêtes Cross-site Access-Control doivent être effectuées avec des informations d'identification telles que des cookies, des en-têtes d'autorisation ou des certificats client TLS. La définition de `withCredentials` n'a aucun effet sur les requêtes du même site. + +### `adapter` + +`adapter` permet une gestion personnalisée des requêtes, ce qui facilite les tests. Retournez une promise et fournissez une réponse valide ; consultez [les adaptateurs](/pages/advanced/adapters) pour plus d'informations. Nous fournissons également un certain nombre d'adaptateurs intégrés. L'adaptateur par défaut est `http` pour Node et `xhr` pour les navigateurs. La liste complète des adaptateurs intégrés est la suivante : + +- fetch +- http +- xhr + +Vous pouvez également passer un tableau d'adaptateurs ; axios utilisera le premier pris en charge par l'environnement. + +### `auth` + +`auth` indique que l'authentification HTTP Basic doit être utilisée, et fournit les identifiants. Cela définira un en-tête `Authorization`, en écrasant tout en-tête `Authorization` personnalisé que vous auriez défini via `headers`. Notez que seule l'authentification HTTP Basic est configurable via ce paramètre. Pour les tokens Bearer et similaires, utilisez plutôt des en-têtes `Authorization` personnalisés. + +### `responseType` + +Le `responseType` indique le type de données que le serveur retournera. Il peut s'agir de l'un des types suivants : + +- arraybuffer +- document +- json +- text +- stream +- blob (navigateur uniquement) +- formdata (adaptateur fetch uniquement) + +### `responseEncoding` + +Le `responseEncoding` indique l'encodage à utiliser pour décoder les réponses. Les options suivantes sont prises en charge : + +- ascii +- ASCII +- ansi +- ANSI +- binary +- BINARY +- base64 +- BASE64 +- base64url +- BASE64URL +- hex +- HEX +- latin1 +- LATIN1 +- ucs-2 +- UCS-2 +- ucs2 +- UCS2 +- utf-8 +- UTF-8 +- utf8 +- UTF8 +- utf16le +- UTF16LE + +::: tip +Remarque : ignoré pour un `responseType` de `stream` ou pour les requêtes côté client +::: + +### `xsrfCookieName` + +Le `xsrfCookieName` est le nom du cookie à utiliser comme valeur pour le token `XSRF`. + +### `xsrfHeaderName` + +Le `xsrfHeaderName` est le nom de l'en-tête à utiliser comme valeur pour le token `XSRF`. + +### `withXSRFToken` + +La propriété `withXSRFToken` indique si le token `XSRF` doit être envoyé avec la requête. Ne s'applique qu'aux requêtes côté client. La valeur par défaut est `undefined`. + +### `onUploadProgress` + +La fonction `onUploadProgress` vous permet d'écouter la progression d'un envoi. + +### `onDownloadProgress` + +La fonction `onDownloadProgress` vous permet d'écouter la progression d'un téléchargement. + +### `maxContentLength` + +La propriété `maxContentLength` définit le nombre maximum d'octets que le serveur acceptera dans la réponse. + +### `maxBodyLength` + +La propriété `maxBodyLength` définit le nombre maximum d'octets que le serveur acceptera dans la requête. + +### `validateStatus` + +La fonction `validateStatus` vous permet de remplacer la validation du code de statut par défaut. Par défaut, axios rejette la promise si le code de statut n'est pas dans la plage 200-299. Vous pouvez remplacer ce comportement en fournissant une fonction `validateStatus` personnalisée. La fonction doit retourner `true` si le code de statut est dans la plage que vous souhaitez accepter. + +### `maxRedirects` + +La propriété `maxRedirects` définit le nombre maximum de redirections à suivre. Si défini à 0, aucune redirection ne sera suivie. + +### `beforeRedirect` + +La fonction `beforeRedirect` vous permet de modifier la requête avant qu'elle ne soit redirigée. Utilisez-la pour ajuster les options de requête lors d'une redirection, inspecter les derniers en-têtes de réponse, ou annuler la requête en levant une erreur. Si `maxRedirects` est défini à 0, `beforeRedirect` n'est pas utilisé. + +### `socketPath` + +La propriété `socketPath` définit un socket UNIX à utiliser à la place d'une connexion TCP. Par exemple `/var/run/docker.sock` pour envoyer des requêtes au daemon Docker. Seul `socketPath` ou `proxy` peut être spécifié. Si les deux sont spécifiés, `socketPath` est utilisé. + +### `transport` + +La propriété `transport` définit le transport à utiliser pour la requête. Utile pour effectuer des requêtes via un protocole différent, comme `http2`. + +### `httpAgent` et `httpsAgent` + +Les `httpAgent` et `httpsAgent` définissent un agent personnalisé à utiliser pour les requêtes http et https respectivement dans Node.js. Cela permet d'ajouter des options comme `keepAlive` qui ne sont pas activées par défaut. + +### `proxy` + +Le `proxy` définit le nom d'hôte, le port et le protocole d'un serveur proxy que vous souhaitez utiliser. Vous pouvez également définir votre proxy en utilisant les variables d'environnement conventionnelles `http_proxy` et `https_proxy`. + +Si vous utilisez des variables d'environnement pour la configuration de votre proxy, vous pouvez également définir une variable d'environnement `no_proxy` sous la forme d'une liste de domaines séparés par des virgules qui ne doivent pas être mandatés. + +Utilisez `false` pour désactiver les proxies, en ignorant les variables d'environnement. `auth` indique que l'authentification HTTP Basic doit être utilisée pour se connecter au proxy, et fournit les identifiants. Cela définira un en-tête `Proxy-Authorization`, en écrasant tout en-tête `Proxy-Authorization` personnalisé que vous auriez défini via `headers`. Si le serveur proxy utilise HTTPS, vous devez définir le protocole à `https`. + +```js +proxy: { + protocol: "https", + host: "127.0.0.1", + hostname: "localhost", // Prend le dessus sur "host" si les deux sont définis + port: 9000, + auth: { + username: "mikeymike", + password: "rapunz3l" + } +}, +``` + +### `cancelToken` + +La propriété `cancelToken` vous permet de créer un token d'annulation pouvant être utilisé pour annuler la requête. Pour plus d'informations, consultez la documentation sur l'[annulation](/pages/advanced/cancellation). + +### `signal` + +La propriété `signal` vous permet de passer une instance d'`AbortSignal` à la requête. Cela vous permet d'annuler la requête en utilisant l'API `AbortController`. + +### `decompress` + +La propriété `decompress` indique si les données de la réponse doivent être automatiquement décompressées. La valeur par défaut est `true`. + +### `insecureHTTPParser` + +Indique s'il faut utiliser un analyseur HTTP non sécurisé qui accepte des en-têtes HTTP invalides. Cela peut permettre l'interopérabilité avec des implémentations HTTP non conformes. L'utilisation de l'analyseur non sécurisé doit être évitée. + +Notez que l'option `insecureHTTPParser` n'est disponible que dans Node.js 12.10.0 et ultérieur. Consultez la [documentation Node.js](https://nodejs.org/en/blog/vulnerability/february-2020-security-releases/#strict-http-header-parsing-none) pour plus d'informations. Voir l'ensemble complet des options [ici](https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_url_options_callback) + +### `transitional` + +La propriété `transitional` vous permet d'activer ou de désactiver certaines fonctionnalités de transition. Les options suivantes sont disponibles : + +- `silentJSONParsing` : Si défini à `true`, axios n'affichera pas d'avertissement lorsqu'il rencontre des réponses JSON invalides, définissant la valeur de retour à null. Utile lorsque vous travaillez avec des APIs qui retournent du JSON invalide. +- `forcedJSONParsing` : Force axios à analyser les réponses JSON comme du JSON, même si la réponse n'est pas du JSON valide. Utile lorsque vous travaillez avec des APIs qui retournent du JSON invalide. +- `clarifyTimeoutError` : Clarifie le message d'erreur lorsqu'une requête expire. Utile lors du débogage de problèmes de délai d'attente. +- `legacyInterceptorReqResOrdering` : Lorsque défini à true, l'ordre hérité de traitement requête/réponse des intercepteurs sera utilisé. + +### `env` + +La propriété `env` vous permet de définir certaines options de configuration. Par exemple, la classe FormData qui est utilisée pour sérialiser automatiquement le payload en objet FormData. + +- FormData: window?.FormData || global?.FormData + +### `formSerializer` + +La fonction `formSerializer` vous permet de sérialiser l'objet `data` avant son envoi au serveur. Plusieurs options sont disponibles pour cette fonction ; veuillez vous référer à l'exemple de configuration complète en bas de cette page. + +### `maxRate` + +La propriété `maxRate` définit la **bande passante** maximale (en octets par seconde) pour l'envoi et/ou le téléchargement. Elle accepte soit un nombre unique (appliqué dans les deux sens) soit un tableau de deux éléments `[uploadRate, downloadRate]` où chaque élément est une limite en octets par seconde. Par exemple, `100 * 1024` signifie 100 Ko/s. Consultez [Limitation de débit](/pages/advanced/rate-limiting) pour des exemples. + +## Exemple de configuration complète + +```js +{ + url: "/posts", + method: "get", + baseURL: "https://jsonplaceholder.typicode.com", + allowAbsoluteUrls: true, + transformRequest: [function (data, headers) { + return data; + }], + transformResponse: [function (data) { + return data; + }], + headers: {"X-Requested-With": "XMLHttpRequest"}, + params: { + postId: 5 + }, + paramsSerializer: { + // Fonction d'encodage personnalisée qui envoie les paires clé/valeur de façon itérative. + encode?: (param: string): string => { /* Effectuez des opérations personnalisées ici et retournez la chaîne transformée */ }, + + // Fonction de sérialisation personnalisée pour l'ensemble du paramètre. Permet à l'utilisateur de reproduire le comportement antérieur à la v1.x. + serialize?: (params: Record, options?: ParamsSerializerOptions ), + + // Configuration du format des index de tableaux dans les params. + // Trois options disponibles : + // (1) indexes: null (pas de crochets) + // (2) (défaut) indexes: false (crochets vides) + // (3) indexes: true (crochets avec index). + indexes: false + + }, + data: { + firstName: "Fred" + }, + // Syntaxe alternative pour envoyer des données dans le corps de la méthode post : seule la valeur est envoyée, pas la clé + data: "Country=Brasil&City=Belo Horizonte", + timeout: 1000, + withCredentials: false, + adapter: function (config) { + // Faites ce que vous voulez + }, + adapter: "xhr", + auth: { + username: "janedoe", + password: "s00pers3cret" + }, + responseType: "json", + responseEncoding: "utf8", + xsrfCookieName: "XSRF-TOKEN", + xsrfHeaderName: "X-XSRF-TOKEN", + withXSRFToken: boolean | undefined | ((config: InternalAxiosRequestConfig) => boolean | undefined), + onUploadProgress: function ({loaded, total, progress, bytes, estimated, rate, upload = true}) { + // Faites ce que vous voulez avec l'événement de progression Axios + }, + onDownloadProgress: function ({loaded, total, progress, bytes, estimated, rate, download = true}) { + // Faites ce que vous voulez avec l'événement de progression Axios + }, + maxContentLength: 2000, + maxBodyLength: 2000, + validateStatus: function (status) { + return status >= 200 && status < 300; + }, + maxRedirects: 21, + beforeRedirect: (options, { headers }) => { + if (options.hostname === "typicode.com") { + options.auth = "user:password"; + } + }, + socketPath: null, + transport: undefined, + httpAgent: new http.Agent({ keepAlive: true }), + httpsAgent: new https.Agent({ keepAlive: true }), + proxy: { + protocol: "https", + host: "127.0.0.1", + // hostname: "127.0.0.1" // Prend le dessus sur "host" si les deux sont définis + port: 9000, + auth: { + username: "mikeymike", + password: "rapunz3l" + } + }, + cancelToken: new CancelToken(function (cancel) { + cancel("Operation has been canceled."); + }), + signal: new AbortController().signal, + decompress: true, + insecureHTTPParser: undefined, + transitional: { + silentJSONParsing: true, + forcedJSONParsing: true, + clarifyTimeoutError: false, + legacyInterceptorReqResOrdering: true, + }, + env: { + FormData: window?.FormData || global?.FormData + }, + formSerializer: { + // Fonction visiteur personnalisée pour sérialiser les valeurs du formulaire + visitor: (value, key, path, helpers) => {}; + + // Utiliser des points au lieu de crochets + dots: boolean; + + // Conserver les terminaisons spéciales comme {} dans la clé de paramètre + metaTokens: boolean; + + // Utiliser le format des index de tableau : + // null - pas de crochets + // false - crochets vides + // true - crochets avec index + indexes: boolean; + }, + maxRate: [ + 100 * 1024, // Limite d'envoi de 100Ko/s, + 100 * 1024 // Limite de téléchargement de 100Ko/s + ] +} +``` diff --git a/docs/fr/pages/advanced/request-method-aliases.md b/docs/fr/pages/advanced/request-method-aliases.md new file mode 100644 index 0000000..bf7ac76 --- /dev/null +++ b/docs/fr/pages/advanced/request-method-aliases.md @@ -0,0 +1,130 @@ +# Alias de requête + +axios fournit un ensemble d'alias pour effectuer des requêtes HTTP. Ces alias sont des raccourcis pour effectuer des requêtes via la méthode `request`. Ils sont conçus pour être faciles à utiliser et offrir une façon plus pratique d'effectuer des requêtes. + +axios s'efforce de suivre les RFC 7231 et RFC 5789 aussi fidèlement que possible. Les alias sont conçus pour être cohérents avec les méthodes HTTP définies dans ces RFC. + +### `axios` + +axios peut être utilisé pour effectuer une requête HTTP en passant uniquement l'objet de configuration. L'objet de configuration complet est documenté [ici](/pages/advanced/request-config) + +```ts +axios(url: string | AxiosRequestConfig, config?: AxiosRequestConfig); +``` + +## Alias de méthode + +Les alias suivants sont disponibles pour effectuer des requêtes : + +### `request` + +La méthode `request` est la méthode principale pour effectuer des requêtes HTTP. Elle accepte un objet de configuration en argument et retourne une promise qui se résout vers l'objet de réponse. C'est une méthode générique pouvant être utilisée pour tout type de requête HTTP. + +```ts +axios.request(config: AxiosRequestConfig): AxiosResponse; +``` + +### `get` + +La méthode `get` est utilisée pour effectuer une requête GET. Elle accepte une URL et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.get(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `delete` + +La méthode `delete` est utilisée pour effectuer une requête DELETE. Elle accepte une URL et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.delete(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `head` + +La méthode `head` est utilisée pour effectuer une requête HEAD. Elle accepte une URL et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.head(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `options` + +La méthode `options` est utilisée pour effectuer une requête OPTIONS. Elle accepte une URL et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.options(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `post` + +La méthode `post` est utilisée pour effectuer une requête POST. Elle accepte une URL, un objet de données optionnel et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.post(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `put` + +La méthode `put` est utilisée pour effectuer une requête PUT. Elle accepte une URL, un objet de données optionnel et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.put(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `patch` + +La méthode `patch` est utilisée pour effectuer une requête PATCH. Elle accepte une URL, un objet de données optionnel et un objet de configuration optionnel en arguments et retourne une promise qui se résout vers l'objet de réponse. + +```ts +axios.patch(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +## Méthodes raccourcies pour les données de formulaire + +Ces méthodes sont équivalentes à leurs homologues ci-dessus, mais prédéfinissent le `Content-Type` à `multipart/form-data`. Elles constituent la façon recommandée d'envoyer des fichiers ou de soumettre des formulaires HTML. + +### `postForm` + +```ts +axios.postForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// Envoyer un fichier depuis un input file du navigateur +await axios.postForm("/api/upload", { + file: document.querySelector("#fileInput").files[0], + description: "Profile photo", +}); +``` + +### `putForm` + +```ts +axios.putForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// Remplacer une ressource avec des données de formulaire +await axios.putForm("/api/users/1/avatar", { + avatar: document.querySelector("#avatarInput").files[0], +}); +``` + +### `patchForm` + +```ts +axios.patchForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// Mettre à jour des champs spécifiques avec des données de formulaire +await axios.patchForm("/api/users/1", { + displayName: "New Name", + avatar: document.querySelector("#avatarInput").files[0], +}); +``` + +::: tip +`postForm`, `putForm` et `patchForm` acceptent les mêmes types de données que leurs méthodes de base — objets simples, `FormData`, `FileList` et `HTMLFormElement`. Consultez [Envoi de fichiers](/pages/advanced/file-posting) pour plus d'exemples. +::: diff --git a/docs/fr/pages/advanced/response-schema.md b/docs/fr/pages/advanced/response-schema.md new file mode 100644 index 0000000..64bf35a --- /dev/null +++ b/docs/fr/pages/advanced/response-schema.md @@ -0,0 +1,64 @@ +# Schéma de réponse + +Chaque requête axios se résout vers un objet de réponse ayant la structure suivante. Le schéma est cohérent aussi bien dans les environnements navigateur que Node.js. + +```js +{ + // Les données de réponse fournies par le serveur. + // Lors de l'utilisation de `transformResponse`, ce sera le résultat de la dernière transformation. + data: {}, + + // Le code de statut HTTP de la réponse du serveur (ex. 200, 404, 500). + status: 200, + + // Le message de statut HTTP correspondant au code de statut (ex. "OK", "Not Found"). + statusText: "OK", + + // Les en-têtes de réponse envoyés par le serveur. + // Les noms d'en-têtes sont en minuscules. Vous pouvez y accéder par notation crochet ou point. + headers: {}, + + // La configuration axios utilisée pour cette requête, incluant baseURL, + // headers, timeout, params, et toutes autres options que vous avez fournies. + config: {}, + + // L'objet de requête sous-jacent. + // Dans Node.js : la dernière instance de `http.ClientRequest` (après toute redirection). + // Dans le navigateur : l'instance de `XMLHttpRequest`. + request: {}, +} +``` + +## Accéder aux champs de la réponse + +En pratique, vous déstructurerez généralement uniquement les parties dont vous avez besoin : + +```js +const { data, status, headers } = await axios.get("/api/users/1"); + +console.log(status); // 200 +console.log(headers["content-type"]); // "application/json; charset=utf-8" +console.log(data); // { id: 1, name: "Jay", email: "jay@example.com" } +``` + +## Vérifier le code de statut + +axios résout la promise pour toute réponse 2xx et rejette pour tout ce qui est en dehors de cette plage par défaut. Vous pouvez personnaliser ce comportement avec l'option de configuration `validateStatus` : + +```js +const response = await axios.get("/api/resource", { + validateStatus: (status) => status < 500, // résoudre pour tout statut inférieur à 500 +}); +``` + +## Accéder aux en-têtes de réponse + +Tous les noms d'en-têtes de réponse sont en minuscules, quelle que soit la façon dont le serveur les a envoyés : + +```js +const response = await axios.get("/api/resource"); + +// Ces deux lignes sont équivalentes +const contentType = response.headers["content-type"]; +const contentType2 = response.headers.get("content-type"); +``` diff --git a/docs/fr/pages/advanced/retry.md b/docs/fr/pages/advanced/retry.md new file mode 100644 index 0000000..527637a --- /dev/null +++ b/docs/fr/pages/advanced/retry.md @@ -0,0 +1,130 @@ +# Nouvelles tentatives et récupération sur erreur + +Les requêtes réseau peuvent échouer pour des raisons transitoires — une défaillance momentanée du serveur, une brève interruption du réseau, ou une réponse de limitation de débit. Implémenter une stratégie de nouvelle tentative dans un intercepteur vous permet de gérer ces échecs de manière transparente, sans polluer votre code applicatif. + +## Nouvelle tentative de base avec un intercepteur de réponse + +L'approche la plus simple consiste à intercepter des codes de statut d'erreur spécifiques et à renvoyer immédiatement la requête originale un nombre limité de fois : + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +const MAX_RETRIES = 3; + +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + // Ne réessayer que pour les erreurs réseau ou les erreurs serveur 5xx + const shouldRetry = + !error.response || (error.response.status >= 500 && error.response.status < 600); + + if (!shouldRetry) { + return Promise.reject(error); + } + + config._retryCount = config._retryCount ?? 0; + + if (config._retryCount >= MAX_RETRIES) { + return Promise.reject(error); + } + + config._retryCount += 1; + return api(config); + } +); +``` + +## Délai exponentiel + +Réessayer immédiatement après un échec peut surcharger un serveur déjà en difficulté. Le délai exponentiel attend progressivement plus longtemps entre chaque tentative : + +```js +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + const shouldRetry = + !error.response || (error.response.status >= 500 && error.response.status < 600); + + if (!shouldRetry) return Promise.reject(error); + + config._retryCount = config._retryCount ?? 0; + + if (config._retryCount >= 3) return Promise.reject(error); + + config._retryCount += 1; + + // Attendre 200ms, 400ms, 800ms, ... avant chaque nouvelle tentative + const backoff = 100 * 2 ** config._retryCount; + await delay(backoff); + + return api(config); + } +); +``` + +## Nouvelle tentative sur 429 (limite de débit) avec Retry-After + +Lorsque le serveur répond avec `429 Too Many Requests`, il inclut souvent un en-tête `Retry-After` indiquant exactement combien de temps attendre : + +```js +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + if (error.response?.status !== 429) return Promise.reject(error); + + config._retryCount = config._retryCount ?? 0; + if (config._retryCount >= 3) return Promise.reject(error); + + config._retryCount += 1; + + const retryAfterHeader = error.response.headers["retry-after"]; + const waitMs = retryAfterHeader + ? parseFloat(retryAfterHeader) * 1000 // l'en-tête est en secondes + : 1000; // par défaut 1 seconde + + await new Promise((resolve) => setTimeout(resolve, waitMs)); + return api(config); + } +); +``` + +## Désactiver les nouvelles tentatives pour une requête spécifique + +Si certaines requêtes ne doivent jamais être réessayées (ex. des mutations non idempotentes que vous ne voulez pas dupliquer), ajoutez un indicateur à la configuration de la requête : + +```js +// Ajoutez ceci dans votre intercepteur avant la logique de nouvelle tentative : +if (config._noRetry) return Promise.reject(error); + +// Puis désactivez les nouvelles tentatives pour des appels spécifiques : +await api.post("/payments/charge", body, { _noRetry: true }); +``` + +## Combiner nouvelles tentatives et annulation + +Utilisez un `AbortController` pour annuler une requête qui attend un délai de backoff : + +```js +const controller = new AbortController(); + +try { + await api.get("/api/data", { signal: controller.signal }); +} catch (error) { + if (axios.isCancel(error)) { + console.log("Request aborted by user"); + } +} + +// Annuler la requête (et tout délai de nouvelle tentative en attente) depuis un autre endroit : +controller.abort(); +``` diff --git a/docs/fr/pages/advanced/testing.md b/docs/fr/pages/advanced/testing.md new file mode 100644 index 0000000..5b75ab8 --- /dev/null +++ b/docs/fr/pages/advanced/testing.md @@ -0,0 +1,145 @@ +# Tests + +Tester du code qui effectue des requêtes HTTP avec axios est simple. L'approche recommandée consiste à simuler (mocker) axios lui-même afin que vos tests s'exécutent sans toucher un vrai réseau, vous donnant un contrôle total sur les réponses que reçoit votre code. + +## Simulation avec Vitest ou Jest + +Vitest et Jest supportent tous deux la simulation de modules avec `vi.mock` / `jest.mock`. Vous pouvez simuler l'ensemble du module axios et contrôler ce que chaque méthode retourne : + +```js +// user-service.js +import axios from "axios"; + +export async function getUser(id) { + const { data } = await axios.get(`/api/users/${id}`); + return data; +} +``` + +```js +// user-service.test.js +import { describe, it, expect, vi } from "vitest"; +import axios from "axios"; +import { getUser } from "./user-service"; + +vi.mock("axios"); + +describe("getUser", () => { + it("returns user data on success", async () => { + const mockUser = { id: 1, name: "Jay" }; + + // Faire en sorte que axios.get se résolve avec notre fausse réponse + axios.get.mockResolvedValueOnce({ data: mockUser }); + + const result = await getUser(1); + + expect(result).toEqual(mockUser); + expect(axios.get).toHaveBeenCalledWith("/api/users/1"); + }); + + it("throws when the request fails", async () => { + axios.get.mockRejectedValueOnce(new Error("Network error")); + + await expect(getUser(1)).rejects.toThrow("Network error"); + }); +}); +``` + +## Simuler une AxiosError + +Pour tester les chemins de gestion d'erreurs qui inspectent `error.response`, créez directement une instance d'`AxiosError` : + +```js +import axios, { AxiosError } from "axios"; +import { vi } from "vitest"; + +const mockError = new AxiosError( + "Not Found", + "ERR_BAD_REQUEST", + {}, // config + {}, // request + { // response + status: 404, + statusText: "Not Found", + data: { message: "User not found" }, + headers: {}, + config: {}, + } +); + +axios.get.mockRejectedValueOnce(mockError); +``` + +## Utiliser axios-mock-adapter + +[axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter) est une bibliothèque qui installe un adaptateur personnalisé sur votre instance axios, interceptant les requêtes au niveau de l'adaptateur. Cela signifie que vos intercepteurs continuent de s'exécuter, ce qui la rend plus adaptée aux tests d'intégration. + +```bash +npm install --save-dev axios-mock-adapter +``` + +```js +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; + +const mock = new MockAdapter(axios); + +// Simuler une requête GET +mock.onGet("/api/users/1").reply(200, { id: 1, name: "Jay" }); + +// Simuler une requête POST +mock.onPost("/api/users").reply(201, { id: 2, name: "New User" }); + +// Simuler une erreur réseau +mock.onGet("/api/failing").networkError(); + +// Simuler un délai d'attente dépassé +mock.onGet("/api/slow").timeout(); +``` + +Réinitialisez les simulations entre les tests : + +```js +afterEach(() => { + mock.reset(); // effacer tous les gestionnaires enregistrés +}); +``` + +## Tester les intercepteurs + +Pour tester les intercepteurs de manière isolée, créez une nouvelle instance axios dans votre test : + +```js +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; + +describe("auth interceptor", () => { + it("attaches a Bearer token to every request", async () => { + const instance = axios.create(); + const mock = new MockAdapter(instance); + + // Ajoutez votre intercepteur + instance.interceptors.request.use((config) => { + config.headers.set("Authorization", "Bearer test-token"); + return config; + }); + + // Capturez la configuration de la requête en inspectant ce que mock a reçu + let capturedConfig; + mock.onGet("/api/data").reply((config) => { + capturedConfig = config; + return [200, {}]; + }); + + await instance.get("/api/data"); + + expect(capturedConfig.headers["Authorization"]).toBe("Bearer test-token"); + }); +}); +``` + +## Conseils + +- Simulez toujours au niveau du module (ou utilisez `MockAdapter`) — évitez de simuler des méthodes individuelles sur une instance partagée, car l'état peut fuiter entre les tests. +- Préférez `mockResolvedValueOnce` / `mockRejectedValueOnce` à `mockResolvedValue` pour que les tests soient isolés et ne s'affectent pas mutuellement. +- Pour tester la logique de nouvelle tentative, utilisez `MockAdapter` afin que l'intercepteur testé s'exécute réellement à chaque tentative. diff --git a/docs/fr/pages/advanced/type-script.md b/docs/fr/pages/advanced/type-script.md new file mode 100644 index 0000000..936e5a9 --- /dev/null +++ b/docs/fr/pages/advanced/type-script.md @@ -0,0 +1,8 @@ +# TypeScript + +`axios` inclut des définitions de types pour TypeScript. Elles sont incluses dans le package npm `axios` via le fichier `index.d.ts`. Comme axios publie à la fois avec un export par défaut ESM et un `module.exports` CJS, il existe quelques nuances à prendre en compte : + +- Le paramètre recommandé est d'utiliser `"moduleResolution": "node16"` (impliqué par `"module": "node16"`). Notez que cela nécessite TypeScript 4.7 ou supérieur. +- Si vous utilisez ESM, vos paramètres devraient convenir. +- Si vous compilez TypeScript en CJS et ne pouvez pas utiliser `"moduleResolution": "node16"`, vous devez activer `esModuleInterop`. +- Si vous utilisez TypeScript pour vérifier les types de code JavaScript CJS, votre seule option est d'utiliser `"moduleResolution": "node16"`. diff --git a/docs/fr/pages/advanced/x-www-form-urlencoded-format.md b/docs/fr/pages/advanced/x-www-form-urlencoded-format.md new file mode 100644 index 0000000..4dfc8dc --- /dev/null +++ b/docs/fr/pages/advanced/x-www-form-urlencoded-format.md @@ -0,0 +1,78 @@ +# Format x-www-form-urlencoded + +## URLSearchParams + +Par défaut, axios sérialise les objets JavaScript en `JSON`. Pour envoyer des données au format [`application/x-www-form-urlencoded`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) à la place, vous pouvez utiliser l'API [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams), [supportée](http://www.caniuse.com/#feat=urlsearchparams) par la grande majorité des navigateurs, et [Node.js](https://nodejs.org/api/url.html#url_class_urlsearchparams) depuis la version v10 (publiée en 2018). + +```js +const params = new URLSearchParams({ foo: 'bar' }); +params.append('extraparam', 'value'); +axios.post('/foo', params); +``` + +## Chaîne de requête + +Pour les navigateurs plus anciens ou les environnements sans `URLSearchParams`, vous pouvez utiliser la bibliothèque [`qs`](https://github.com/ljharb/qs) pour sérialiser des objets au format `application/x-www-form-urlencoded`. + +```js +const qs = require('qs'); +axios.post('/foo', qs.stringify({ bar: 123 })); +``` + +Dans les très anciennes versions de Node.js, vous pouvez utiliser le module natif `querystring` fourni avec Node.js. Notez que ce module a été déprécié dans Node.js v16 — préférez `URLSearchParams` ou `qs` pour le nouveau code. + +```js +const querystring = require('querystring'); +axios.post('https://something.com/', querystring.stringify({ foo: 'bar' })); +``` + +## Sérialisation automatique vers URLSearchParams + +À partir de la version v0.21.0, axios sérialise automatiquement les objets JavaScript en `URLSearchParams` si l'en-tête `Content-Type` est défini à `application/x-www-form-urlencoded`. Cela signifie que vous pouvez passer directement un objet JavaScript à la propriété `data` de la configuration de requête axios. Par exemple lors de l'envoi de données vers une requête `POST` : + +```js +const data = { + x: 1, + arr: [1, 2, 3], + arr2: [1, [2], 3], + users: [ + { name: 'Peter', surname: 'Griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], +}; + +await axios.postForm('https://postman-echo.com/post', data, { + headers: { 'content-type': 'application/x-www-form-urlencoded' }, +}); +``` + +L'objet `data` sera automatiquement sérialisé en `URLSearchParams` et envoyé au format `application/x-www-form-urlencoded`. Le serveur recevra les données suivantes : + +```json +{ + "x": "1", + "arr[]": ["1", "2", "3"], + "arr2[0]": "1", + "arr2[1][0]": "2", + "arr2[2]": "3", + "users[0][name]": "Peter", + "users[0][surname]": "Griffin", + "users[1][name]": "Thomas", + "users[1][surname]": "Anderson" +} +``` + +Si le body-parser de votre backend (comme `body-parser` d'`express.js`) prend en charge le décodage des objets imbriqués, vous obtiendrez automatiquement le même objet côté serveur. + +```js +var app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); // support des corps encodés + +app.post('/', function (req, res, next) { + // écho du corps en JSON + res.send(JSON.stringify(req.body)); +}); + +server = app.listen(3000); +``` diff --git a/docs/fr/pages/getting-started/examples/commonjs.md b/docs/fr/pages/getting-started/examples/commonjs.md new file mode 100644 index 0000000..7b1e078 --- /dev/null +++ b/docs/fr/pages/getting-started/examples/commonjs.md @@ -0,0 +1,226 @@ +# Exemples JavaScript + +## Importer la bibliothèque + +Pour importer la bibliothèque dans un environnement CommonJS, vous pouvez utiliser la fonction `require`, ou l'instruction `import` si vous utilisez un bundler comme Webpack ou Rollup. + +#### Sans bundler + +```js +const axios = require("axios"); +``` + +#### Avec bundler (webpack, rollup, vite, etc.) + +```js +import axios from "axios"; +``` + +## Utiliser then/catch/finally + +Comme axios retourne une Promise en son coeur, vous pouvez choisir d'utiliser des callbacks avec `then`, `catch` et `finally` pour gérer vos données de réponse, les erreurs et la fin de la requête. + +### Requête GET + +```js +axios + .get("https://jsonplaceholder.typicode.com/posts", { + params: { + postId: 5, + }, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Requête POST + +```js +axios + .post("https://jsonplaceholder.typicode.com/posts", { + title: "foo", + body: "bar", + userId: 1, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Requête PUT + +```js +axios + .put("https://jsonplaceholder.typicode.com/posts/1", { + title: "foo", + body: "bar", + userId: 1, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Requête PATCH + +```js +axios + .patch("https://jsonplaceholder.typicode.com/posts/1", { + title: "foo", + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### Requête DELETE + +```js +axios + .delete("https://jsonplaceholder.typicode.com/posts/1") + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +## Utiliser async/await + +Une autre façon de gérer les promises est d'utiliser `async` et `await`. Cela vous permet d'utiliser des blocs try/catch/finally pour gérer les erreurs et la fin de la requête. Cette approche rend votre code plus lisible et plus facile à comprendre, et permet également d'éviter ce qu'on appelle le « callback hell ». + +::: tip +Remarque : async/await fait partie d'ECMAScript 2017 et n'est pas supporté par Internet Explorer et les navigateurs plus anciens. À utiliser avec précaution. +::: + +### Requête GET + +```js +const getPosts = async () => { + try { + const response = await axios.get( + "https://jsonplaceholder.typicode.com/posts", + { + params: { + postId: 5, + }, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Requête POST + +```js +const createPost = async () => { + try { + const response = await axios.post( + "https://jsonplaceholder.typicode.com/posts", + { + title: "foo", + body: "bar", + userId: 1, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Requête PUT + +```js +const updatePost = async () => { + try { + const response = await axios.put( + "https://jsonplaceholder.typicode.com/posts/1", + { + title: "foo", + body: "bar", + userId: 1, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Requête PATCH + +```js +const updatePost = async () => { + try { + const response = await axios.patch( + "https://jsonplaceholder.typicode.com/posts/1", + { + title: "foo", + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### Requête DELETE + +```js +const deletePost = async () => { + try { + const response = await axios.delete( + "https://jsonplaceholder.typicode.com/posts/1" + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` diff --git a/docs/fr/pages/getting-started/examples/typescript.md b/docs/fr/pages/getting-started/examples/typescript.md new file mode 100644 index 0000000..2ac459a --- /dev/null +++ b/docs/fr/pages/getting-started/examples/typescript.md @@ -0,0 +1,139 @@ +# Exemple TypeScript + +## Importer les types + +axios inclut des définitions TypeScript prêtes à l'emploi. Vous pouvez importer les types dont vous avez besoin directement depuis `"axios"` : + +```ts +import axios from "axios"; +import type { AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"; +``` + +## Typer une requête + +Utilisez un paramètre de type générique sur la réponse pour indiquer à TypeScript la forme que prendront vos données : + +```ts +import axios from "axios"; + +type Post = { + userId: number; + id: number; + title: string; + body: string; +}; + +const response = await axios.get("https://jsonplaceholder.typicode.com/posts/1"); + +console.log(response.data.title); // TypeScript sait que c'est une string +``` + +## Typer une fonction + +Encapsulez les requêtes dans des fonctions avec des types de retour explicites pour une sécurité de type maximale : + +```ts +import axios, { AxiosResponse } from "axios"; + +type Post = { + userId: number; + id: number; + title: string; + body: string; +}; + +const getPost = async (id: number): Promise => { + const response = await axios.get( + `https://jsonplaceholder.typicode.com/posts/${id}` + ); + return response.data; +}; +``` + +## Typer une requête POST + +Vous pouvez typer à la fois le corps de la requête et la réponse attendue : + +```ts +type CreatePostBody = { + title: string; + body: string; + userId: number; +}; + +type CreatePostResponse = CreatePostBody & { id: number }; + +const createPost = async (data: CreatePostBody): Promise => { + const response = await axios.post( + "https://jsonplaceholder.typicode.com/posts", + data + ); + return response.data; +}; +``` + +## Instance axios typée + +Créez une instance typée afin d'y intégrer votre URL de base et vos en-têtes : + +```ts +import axios from "axios"; +import type { AxiosInstance } from "axios"; + +const api: AxiosInstance = axios.create({ + baseURL: "https://api.example.com", + timeout: 5000, +}); +``` + +## Intercepteurs typés + +Utilisez `InternalAxiosRequestConfig` (et non `AxiosRequestConfig`) pour les intercepteurs de requête dans v1.x : + +```ts +import axios from "axios"; +import type { InternalAxiosRequestConfig, AxiosResponse } from "axios"; + +api.interceptors.request.use((config: InternalAxiosRequestConfig) => { + config.headers.set("Authorization", `Bearer ${getToken()}`); + return config; +}); + +api.interceptors.response.use( + (response: AxiosResponse) => response, + (error) => Promise.reject(error) +); +``` + +## Typer les erreurs + +Utilisez `axios.isAxiosError()` pour affiner le type d'une erreur capturée : + +```ts +import axios, { AxiosError } from "axios"; + +type ApiError = { + message: string; + code: number; +}; + +try { + await axios.get("/api/protected-resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + // error.response?.data est typé comme ApiError + console.error(error.response?.data.message); + console.error(error.response?.status); + } else { + throw error; + } +} +``` + +## Notes sur la configuration TypeScript + +Comme axios publie à la fois des versions ESM et CJS, il existe quelques nuances selon votre configuration : + +- Le paramètre recommandé est `"moduleResolution": "node16"` (impliqué par `"module": "node16"`). Cela nécessite TypeScript 4.7 ou supérieur. +- Si vous compilez TypeScript vers CJS et ne pouvez pas utiliser `"moduleResolution": "node16"`, activez `"esModuleInterop": true`. +- Si vous utilisez TypeScript pour vérifier les types de code JavaScript CJS, votre seule option est `"moduleResolution": "node16"`. diff --git a/docs/fr/pages/getting-started/features.md b/docs/fr/pages/getting-started/features.md new file mode 100644 index 0000000..8cf2ae4 --- /dev/null +++ b/docs/fr/pages/getting-started/features.md @@ -0,0 +1,42 @@ +# Fonctionnalités + +axios est un client HTTP puissant qui propose une API simple et facile à utiliser pour effectuer des requêtes HTTP. Il prend en charge tous les navigateurs modernes et est largement utilisé dans la communauté JavaScript. Voici quelques-unes des fonctionnalités qui font d'axios un excellent choix pour votre prochain projet. + +## Isomorphique + +axios est un client HTTP universel qui peut être utilisé aussi bien dans le navigateur que dans Node.js. Cela signifie que vous pouvez utiliser axios pour effectuer des requêtes API depuis votre code frontend aussi bien que depuis votre code backend. Cela fait d'axios un excellent choix pour développer des applications web progressives, des applications monopages et des applications avec rendu côté serveur. + +axios est également un excellent choix pour les équipes qui travaillent à la fois sur le frontend et le backend. En utilisant axios pour les deux, vous disposez d'une API cohérente pour effectuer des requêtes HTTP, ce qui peut contribuer à réduire la complexité de votre code. + +## Support Fetch + +axios offre une prise en charge de premier plan de l'API Fetch, qui est un remplacement moderne de l'API XHR. L'adaptateur est optionnel et peut être activé via la configuration. La même API est maintenue pour les adaptateurs XHR et Fetch, ce qui facilite l'adoption de l'API Fetch dans votre code sans modifier votre code existant. + +## Support des navigateurs + +axios prend en charge tous les navigateurs modernes et certains navigateurs plus anciens, notamment Chrome, Firefox, Safari et Edge. axios est un excellent choix pour développer des applications web devant prendre en charge un large éventail de navigateurs. + +## Support de Node.js + +axios supporte également un large éventail de versions de Node.js, avec une compatibilité testée jusqu'à la version v12.x, ce qui en fait un bon choix dans les environnements où la mise à jour vers la dernière version de Node.js n'est pas possible ou pratique. + +En plus de Node.js, axios dispose de tests de fumée pour Bun et Deno qui valident les comportements clés de l'exécution et renforcent la confiance dans la compatibilité multi-environnements. + +## Fonctionnalités supplémentaires + +- Support de l'API Promise +- Interception des requêtes et des réponses +- Transformation des données de requête et de réponse +- Abort controller +- Délais d'attente (timeouts) +- Sérialisation des paramètres de requête avec support des entrées imbriquées +- Sérialisation automatique du corps de la requête vers : + - JSON (application/json) + - Multipart / FormData (multipart/form-data) + - Formulaire encodé en URL (application/x-www-form-urlencoded) +- Envoi de formulaires HTML en JSON +- Gestion automatique des données JSON dans la réponse +- Capture de la progression pour les navigateurs et Node.js avec des informations supplémentaires (vitesse de transfert, temps restant) +- Limitation de la bande passante pour Node.js +- Compatible avec les implémentations conformes de FormData et Blob (y compris Node.js) +- Protection côté client contre les attaques XSRF diff --git a/docs/fr/pages/getting-started/first-steps.md b/docs/fr/pages/getting-started/first-steps.md new file mode 100644 index 0000000..e27f6a6 --- /dev/null +++ b/docs/fr/pages/getting-started/first-steps.md @@ -0,0 +1,73 @@ +# Premiers pas + +Bienvenue dans la documentation d'axios ! Ce guide vous aidera à démarrer avec axios et à effectuer votre première requête API. Si vous débutez avec axios, nous vous recommandons de commencer ici. + +## Installation + +Vous pouvez utiliser axios dans votre projet de plusieurs façons. La méthode la plus courante consiste à l'installer depuis npm et à l'inclure dans votre projet. Nous supportons également jsDelivr, unpkg, et d'autres options. + +#### Avec npm + +```bash +npm install axios +``` + +#### Avec pnpm + +```bash +pnpm install axios +``` + +#### Avec yarn + +```bash +yarn add axios +``` + +#### Avec bun + +```bash +bun add axios +``` + +#### Avec deno + +```bash +deno install npm:axios +``` + +#### Avec jsDelivr + +Lors de l'utilisation de jsDelivr, nous recommandons d'utiliser la version minifiée ainsi que d'épingler le numéro de version afin d'éviter des changements inattendus. Si vous souhaitez utiliser la dernière version, vous pouvez le faire en omettant le numéro de version. Ceci est fortement déconseillé en production car cela peut entraîner des modifications inattendues dans votre application. + +```html + +``` + +#### Avec unpkg + +Lors de l'utilisation d'unpkg, nous recommandons d'utiliser la version minifiée ainsi que d'épingler le numéro de version afin d'éviter des changements inattendus. Si vous souhaitez utiliser la dernière version, vous pouvez le faire en omettant le numéro de version. Ceci est fortement déconseillé en production car cela peut entraîner des modifications inattendues dans votre application. + +```html + +``` + +## Votre première requête + +Une requête axios peut être effectuée en seulement deux lignes de code. Envoyer votre première requête avec axios est très simple. Vous pouvez interroger n'importe quelle API en fournissant l'URL et la méthode. Par exemple, pour effectuer une requête GET vers l'API JSONPlaceholder, vous pouvez utiliser le code suivant : + +```js +import axios from "axios"; + +const response = await axios.get( + "https://jsonplaceholder.typicode.com/posts/1" +); + +console.log(response.data); +``` + +axios propose une API simple pour effectuer des requêtes. Vous pouvez utiliser la méthode `axios.get` pour une requête GET, la méthode `axios.post` pour une requête POST, et ainsi de suite. Vous pouvez également utiliser la méthode `axios.request` pour effectuer une requête avec n'importe quelle méthode HTTP. + +## Prochaines étapes + +Maintenant que vous avez effectué votre première requête avec axios, vous êtes prêt à explorer le reste de la documentation. Vous pouvez en apprendre davantage sur l'envoi de requêtes, la gestion des réponses et l'utilisation d'axios dans vos projets. Consultez le reste de la documentation pour en savoir plus. diff --git a/docs/fr/pages/getting-started/upgrade-guide.md b/docs/fr/pages/getting-started/upgrade-guide.md new file mode 100644 index 0000000..849f50a --- /dev/null +++ b/docs/fr/pages/getting-started/upgrade-guide.md @@ -0,0 +1,92 @@ +# Guide de migration + +Ce guide a pour but de vous aider à migrer votre projet d'une version du framework à une autre. Il est recommandé de lire les notes de version de chaque version majeure que vous migrez, car elles peuvent contenir des informations importantes sur les changements incompatibles. + +## Migration de v0.x vers v1.x + +### Modification de l'instruction d'importation + +Dans v1.x, l'instruction d'importation a été modifiée pour utiliser l'export `default`. Vous devrez donc mettre à jour vos instructions d'importation en conséquence. + +```diff +- import { axios } from "axios"; ++ import axios from "axios"; +``` + +### Modifications du système d'intercepteurs + +Dans v1.x, vous devez utiliser le type `InternalAxiosRequestConfig` pour typer le paramètre `config` dans l'intercepteur de `request`. En effet, le paramètre `config` est désormais typé comme `InternalAxiosRequestConfig` au lieu du type public `AxiosRequestConfig`. + +```diff +- axios.interceptors.request.use((config: AxiosRequestConfig) => { ++ axios.interceptors.request.use((config: InternalAxiosRequestConfig) => { + return config; + }); +``` + +### Modifications de la structure des en-têtes de requête + +Dans v1.x, la structure des en-têtes de requête a été modifiée pour supprimer la propriété `common`. Vous devrez donc mettre à jour votre code pour utiliser la nouvelle structure des en-têtes de requête comme suit : + +```diff +- if (request.headers?.common?.Authorization) { +- request.headers.common.Authorization = ... ++ if (request.headers?.Authorization) { ++ request.headers.Authorization = ... +``` + +Les en-têtes par défaut qui se trouvaient précédemment sous `common`, `get`, `post`, etc. sont désormais définis directement sur `axios.defaults.headers` : + +```diff +- axios.defaults.headers.common["Accept"] = "application/json"; ++ axios.defaults.headers["Accept"] = "application/json"; +``` + +### Données multipart/form-data + +Si une requête inclut un payload `FormData`, l'en-tête `Content-Type: multipart/form-data` est désormais défini automatiquement. Supprimez tout en-tête manuel pour éviter les doublons : + +```diff +- axios.post("/upload", formData, { +- headers: { "Content-Type": "multipart/form-data" }, +- }); ++ axios.post("/upload", formData); +``` + +Si vous définissez explicitement `Content-Type: application/json`, axios sérialisera désormais automatiquement les données en JSON. + +### Sérialisation des paramètres + +v1.x a introduit plusieurs changements incompatibles dans la façon dont les paramètres d'URL sont sérialisés. Les plus importants : + +**Les `params` sont désormais encodés en pourcentage par défaut.** Si votre backend attendait des crochets bruts issus de l'encodage de style qs, vous devrez peut-être configurer un sérialiseur personnalisé : + +```js +import qs from 'qs'; + +axios.create({ + paramsSerializer: { + serialize: (params) => qs.stringify(params, { arrayFormat: 'brackets' }), + }, +}); +``` + +**Les objets imbriqués dans `params` sont désormais sérialisés avec la notation entre crochets** (`foo[bar]=1`) plutôt que la notation pointée. Si votre backend attendait la notation pointée, utilisez un sérialiseur personnalisé. + +**Les paramètres `null` et `undefined`** sont désormais gérés de manière cohérente : les valeurs `null` sont sérialisées comme des chaînes vides, tandis que les valeurs `undefined` sont entièrement omises. + +Pour les options complètes de configuration de la sérialisation des paramètres, consultez la page [Configuration de requête](/pages/advanced/request-config). + +### Les éléments internes ne sont plus exportés + +Nous avons décidé de ne plus exporter les éléments internes d'axios. Vous devrez donc mettre à jour votre code pour n'utiliser que l'API publique d'axios. Cette modification a été apportée pour simplifier l'API et réduire la surface exposée d'axios, nous permettant ainsi d'effectuer des modifications internes sans les déclarer comme des changements incompatibles. + +Veuillez consulter la [référence API](/pages/advanced/api-reference) sur ce site pour obtenir les dernières informations sur l'API publique d'axios. + +### Configuration de requête + +Nous avons apporté des modifications à l'objet de configuration de requête. Veuillez consulter la [référence de configuration](/pages/advanced/request-config) sur ce site pour obtenir les dernières informations. + +### Changements incompatibles non répertoriés + +Ce guide n'est pas exhaustif et peut ne pas couvrir tous les changements incompatibles. Si vous rencontrez un problème, veuillez ouvrir un ticket sur le [dépôt GitHub de la documentation](https://github.com/axios/docs) avec le label `breaking change`. diff --git a/docs/fr/pages/misc/security.md b/docs/fr/pages/misc/security.md new file mode 100644 index 0000000..5879a54 --- /dev/null +++ b/docs/fr/pages/misc/security.md @@ -0,0 +1,24 @@ +# Politique de sécurité + +## Signaler une vulnérabilité + +Si vous pensez avoir trouvé une vulnérabilité de sécurité dans le projet, veuillez nous la signaler comme décrit ci-dessous. Nous prenons toutes les vulnérabilités de sécurité au sérieux. Si vous avez trouvé une vulnérabilité dans une bibliothèque tierce, veuillez la signaler aux mainteneurs de cette bibliothèque. + +## Processus de signalement + +Veuillez ne pas signaler les vulnérabilités de sécurité via des issues GitHub publiques. Veuillez utiliser le canal de sécurité officiel sur GitHub en créant un [avis de sécurité](https://github.com/axios/axios/security). + +## Politique de divulgation + +Lorsque nous recevons un rapport de vulnérabilité de sécurité, nous lui assignons un responsable principal. Cette personne est responsable du rapport de vulnérabilité. Le responsable confirmera le problème et déterminera les versions affectées. Il évaluera ensuite le problème et déterminera la gravité du problème. Le responsable développera un correctif pour le problème et préparera une version. Le responsable informera le rapporteur lorsque le correctif sera prêt à être annoncé. + +## Mises à jour de sécurité + +Les mises à jour de sécurité seront publiées dès que possible après que le correctif a été développé et testé. Nous informerons les utilisateurs de la version via le dépôt GitHub du projet. Nous publierons également les notes de version et les avis de sécurité sur la page des versions GitHub du projet. Nous déprécierons également toutes les versions contenant la vulnérabilité de sécurité. + +## Partenaires de sécurité et remerciements + +Nous tenons à remercier les chercheurs en sécurité suivants pour leur collaboration afin de contribuer à la sécurité du projet pour tous : + +- [Socket Dev](https://socket.dev/) +- [GitHub Security Lab](https://securitylab.github.com/) diff --git a/docs/fr/pages/misc/semver.md b/docs/fr/pages/misc/semver.md new file mode 100644 index 0000000..2b15479 --- /dev/null +++ b/docs/fr/pages/misc/semver.md @@ -0,0 +1,44 @@ +# Versionnage sémantique + +Le versionnage sémantique est un schéma de versionnage utilisé pour communiquer la nature des changements dans un package logiciel. C'est un ensemble simple de règles et d'exigences qui dictent comment les numéros de version sont attribués et incrémentés. + +## Versionnage d'axios + +axios suit le schéma de versionnage sémantique. Cela signifie que chaque version d'axios se voit attribuer un numéro de version composé de trois parties : majeure, mineure et correctif. Le numéro de version est incrémenté en fonction de la nature des changements apportés dans la version. + +Dans le passé, axios n'a pas toujours strictement suivi le versionnage sémantique, mais à l'avenir, une adhérence beaucoup plus stricte au schéma de versionnage sémantique sera maintenue pour garantir que les utilisateurs peuvent se fier aux numéros de version pour communiquer la nature des changements dans la bibliothèque. + +Un bref aperçu du schéma de versionnage est fourni ci-dessous. + +## Format de version + +Un numéro de version sémantique est composé de trois parties : + +1. Version majeure +2. Version mineure +3. Version de correctif + +Le numéro de version est écrit sous la forme `MAJEURE.MINEURE.CORRECTIF`. Chaque partie du numéro de version a une signification spécifique : + +- **Version majeure** : Incrémentée lorsque vous effectuez des changements d'API incompatibles. +- **Version mineure** : Incrémentée lorsque vous ajoutez des fonctionnalités de manière rétrocompatible. +- **Version de correctif** : Incrémentée lorsque vous effectuez des corrections de bugs rétrocompatibles. + +## Versions de pré-publication + +En plus des trois parties du numéro de version, vous pouvez ajouter une version de pré-publication. Cela se fait en ajoutant un tiret et une série d'identifiants séparés par des points immédiatement après la version de correctif. Par exemple, `1.0.0-alpha.1`. + +Les versions de pré-publication sont utilisées pour indiquer qu'une version est instable et peut ne pas satisfaire les exigences de compatibilité prévues telles qu'indiquées par le numéro de version. Les versions de pré-publication sont ordonnées en fonction de l'ordre des identifiants. Par exemple, `1.0.0-alpha.1` vient avant `1.0.0-alpha.2`. + +## Plages de versions + +Lorsque vous spécifiez une plage de versions pour un package, vous pouvez utiliser une variété d'opérateurs pour spécifier la plage de versions acceptables. Les opérateurs suivants sont disponibles : + +- `>` : Supérieur à +- `<` : Inférieur à +- `>=` : Supérieur ou égal à +- `<=` : Inférieur ou égal à +- `~` : Approximativement égal à +- `^` : Compatible avec + +Par exemple, `^1.0.0` signifie que toute version supérieure ou égale à `1.0.0` et inférieure à `2.0.0` est acceptable. diff --git a/docs/fr/pages/misc/sponsors.md b/docs/fr/pages/misc/sponsors.md new file mode 100644 index 0000000..1b244e6 --- /dev/null +++ b/docs/fr/pages/misc/sponsors.md @@ -0,0 +1,185 @@ +--- +layout: page +--- + + + +
+

Sponsors

+

Axios est soutenu par les organisations suivantes. Si vous souhaitez sponsoriser Axios, consultez notre page Open Collective pour plus d'informations.

+ +
+
+
+
+ +
+
+ {{ capitalizeFirstLetter(sponsor.tier) }} +
+
+ {{ sponsor.name }} +
+
+
+
+
+ + diff --git a/docs/zh/index.md b/docs/zh/index.md new file mode 100644 index 0000000..113a7cd --- /dev/null +++ b/docs/zh/index.md @@ -0,0 +1,329 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: 'axios 文档' + text: 'axios 是一个基于 Promise 的简单 HTTP 客户端,适用于浏览器和 Node.js' + image: + dark: /logo.svg + light: /logo-light.svg + alt: axios + actions: + - theme: brand + text: 快速开始 + link: /zh/pages/getting-started/first-steps + - theme: alt + text: API 参考 + link: /zh/pages/advanced/api-reference + +features: + - title: 简单易用 + details: axios 上手极为简单,一行代码即可完成初始化。最基本的 API 请求仅需 2 行代码。 + - title: 强大的拦截器 + details: 创新的拦截器系统让您可以完全掌控请求和响应的生命周期,支持修改请求、响应及错误。 + - title: TypeScript 支持 + details: axios 提供完整的类型声明,全面支持 TypeScript,让您可以在 TypeScript 项目中放心使用。 +--- + + + + +
+

赞助商

+
+
+
+
+
+
+ +
+
+

{{ sponsor.name }}

+
+
+ {{ capitalizeFirstLetter(sponsor.tier) }} +
+
+
+
+ +
+
+
+
+
+ + diff --git a/docs/zh/pages/advanced/adapters.md b/docs/zh/pages/advanced/adapters.md new file mode 100644 index 0000000..e762b61 --- /dev/null +++ b/docs/zh/pages/advanced/adapters.md @@ -0,0 +1,88 @@ +# 适配器 + +适配器允许你自定义 axios 处理请求数据的方式。默认情况下,axios 使用 `['xhr', 'http', 'fetch']` 的有序优先级列表,并选择当前环境支持的第一个适配器。实际上,这意味着在浏览器中使用 `xhr`,在 Node.js 中使用 `http`,在两者均不可用的环境(如 Cloudflare Workers 或 Deno)中使用 `fetch`。 + +编写自定义适配器可以让你完全掌控 axios 如何发起请求和处理响应,适用于测试、自定义传输或非标准环境等场景。 + +## 内置适配器 + +可以通过 `adapter` 配置选项按名称选择内置适配器: + +```js +// 使用 fetch 适配器 +const instance = axios.create({ adapter: "fetch" }); + +// 使用 XHR 适配器(浏览器默认) +const instance = axios.create({ adapter: "xhr" }); + +// 使用 HTTP 适配器(Node.js 默认) +const instance = axios.create({ adapter: "http" }); +``` + +你也可以传入一个适配器名称数组,axios 将使用当前环境支持的第一个: + +```js +const instance = axios.create({ adapter: ["fetch", "xhr", "http"] }); +``` + +关于 `fetch` 适配器的更多详情,请参阅 [Fetch 适配器](/pages/advanced/fetch-adapter)页面。 + +## 创建自定义适配器 + +要创建自定义适配器,需要编写一个接受 `config` 对象并返回 Promise 的函数,该 Promise 需解析为有效的 axios 响应对象。 + +```js +import axios from "axios"; +import { settle } from "axios/unsafe/core/settle.js"; + +function myAdapter(config) { + /** + * 到此时: + * - config 已与默认配置合并 + * - 请求转换器已执行 + * - 请求拦截器已执行 + * + * 适配器现在负责发起请求 + * 并返回有效的响应对象。 + */ + + return new Promise((resolve, reject) => { + // 在此执行自定义请求逻辑。 + // 本示例以原生 fetch API 为起点。 + fetch(config.url, { + method: config.method?.toUpperCase() ?? "GET", + headers: config.headers?.toJSON() ?? {}, + body: config.data, + signal: config.signal, + }) + .then(async (fetchResponse) => { + const responseData = await fetchResponse.text(); + + const response = { + data: responseData, + status: fetchResponse.status, + statusText: fetchResponse.statusText, + headers: Object.fromEntries(fetchResponse.headers.entries()), + config, + request: null, + }; + + // settle 根据 HTTP 状态码决定是 resolve 还是 reject + settle(resolve, reject, response); + + /** + * 到此后: + * - 响应转换器将执行 + * - 响应拦截器将执行 + */ + }) + .catch(reject); + }); +} + +const instance = axios.create({ adapter: myAdapter }); +``` + +::: tip +`settle` 辅助函数对 2xx 状态码 resolve Promise,对其他状态码 reject Promise,与 axios 的默认行为一致。如果需要自定义状态码验证,请改用 `validateStatus` 配置选项。 +::: diff --git a/docs/zh/pages/advanced/api-reference.md b/docs/zh/pages/advanced/api-reference.md new file mode 100644 index 0000000..4181bc9 --- /dev/null +++ b/docs/zh/pages/advanced/api-reference.md @@ -0,0 +1,331 @@ +# API 参考 + +以下是 axios 包中所有可用函数和类的列表。这些函数可在你的项目中使用和导入。所有函数和类均受我们遵循语义化版本的承诺保护,即在未发布主版本变更的情况下,这些 API 将保持稳定不变。 + +## 实例 + +`axios` 实例是你用于发起 HTTP 请求的主要对象,它是一个创建 `Axios` 类新实例的工厂函数。`axios` 实例提供了多个请求方法,详见文档的[请求别名](/pages/advanced/request-method-aliases)章节。 + +## 类 + +### `Axios` + +`Axios` 类是发起 HTTP 请求的核心类,是一个创建 `Axios` 类新实例的工厂函数。该类提供多个 HTTP 请求方法,详见文档的[请求别名](/pages/advanced/request-method-aliases)章节。 + +#### `constructor` + +创建一个新的 `Axios` 实例,构造函数接受一个可选的配置对象作为参数。 + +```ts +constructor(instanceConfig?: AxiosRequestConfig); +``` + +#### `request` + +处理请求调用和响应解析,是发起 HTTP 请求的核心方法。接受一个配置对象作为参数,返回一个解析为响应对象的 Promise。 + +```ts +request(configOrUrl: string | AxiosRequestConfig, config: AxiosRequestConfig): Promise>; +``` + +### `CancelToken` + +`CancelToken` 类基于 `tc39/proposal-cancelable-promises` 提案,用于创建可取消 HTTP 请求的令牌。该类现已废弃,推荐使用 `AbortController` API。 + +从 0.22.0 版本起,`CancelToken` 类已废弃,将在未来版本中移除。建议改用 `AbortController` API。 + +该类主要为了向后兼容而保留导出,未来将被移除。我们强烈不建议在新项目中使用,因此不再对其 API 进行文档说明。 + +## 函数 + +### `AxiosError` + +`AxiosError` 类是 HTTP 请求失败时抛出的错误类,继承自 `Error` 类并添加了额外属性。 + +#### `constructor` + +创建一个新的 `AxiosError` 实例,构造函数接受可选的 message、code、config、request 和 response 作为参数。 + +```ts +constructor(message?: string, code?: string, config?: InternalAxiosRequestConfig, request?: any, response?: AxiosResponse); +``` + +#### `properties` + +`AxiosError` 类提供以下属性: + +```ts +// 配置实例。 +config?: InternalAxiosRequestConfig; + +// 错误代码。 +code?: string; + +// 请求实例。 +request?: any; + +// 响应实例。 +response?: AxiosResponse; + +// 表示该错误是否为 AxiosError 的布尔值。 +isAxiosError: boolean; + +// 错误状态码。 +status?: number; + +// 将错误转换为 JSON 对象的辅助方法。 +toJSON: () => object; + +// 错误原因。 +cause?: Error; +``` + +### `AxiosHeaders` + +`AxiosHeaders` 类是用于管理 HTTP 请求头的工具类,提供添加、删除和获取请求头等操作方法。 + +此处仅列出主要方法,完整方法列表请参阅类型声明文件。 + +#### `constructor` + +创建一个新的 `AxiosHeaders` 实例,构造函数接受一个可选的请求头对象作为参数。 + +```ts +constructor(headers?: RawAxiosHeaders | AxiosHeaders | string); +``` + +#### `set` + +向请求头对象添加一个请求头。 + +```ts +set(headerName?: string, value?: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders; +set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders; +``` + +#### `get` + +从请求头对象获取一个请求头。 + +```ts +get(headerName: string, parser: RegExp): RegExpExecArray | null; +get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue; +``` + +#### `has` + +检查请求头对象中是否存在某个请求头。 + +```ts +has(header: string, matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `delete` + +从请求头对象移除一个请求头。 + +```ts +delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `clear` + +从请求头对象移除所有请求头。 + +```ts +clear(matcher?: AxiosHeaderMatcher): boolean; +``` + +#### `normalize` + +规范化请求头对象。 + +```ts +normalize(format: boolean): AxiosHeaders; +``` + +#### `concat` + +合并多个请求头对象。 + +```ts +concat(...targets: Array): AxiosHeaders; +``` + +#### `toJSON` + +将请求头对象转换为 JSON 对象。 + +```ts +toJSON(asStrings?: boolean): RawAxiosHeaders; +``` + +### `CanceledError` + +`CanceledError` 类是 HTTP 请求被取消时抛出的错误类,继承自 `AxiosError` 类。 + +### `Cancel` + +`Cancel` 类是 `CanceledError` 类的别名,为向后兼容而保留导出,将在未来版本中移除。 + +### `isCancel` + +检查某个错误是否为 `CanceledError` 的函数,可用于区分主动取消和意外错误。 + +```ts +isCancel(value: any): boolean; +``` + +```js +import axios from "axios"; + +const controller = new AbortController(); + +axios.get("/api/data", { signal: controller.signal }).catch((error) => { + if (axios.isCancel(error)) { + console.log("Request was cancelled:", error.message); + } else { + console.error("Unexpected error:", error); + } +}); + +controller.abort("User navigated away"); +``` + +### `isAxiosError` + +检查某个错误是否为 `AxiosError` 的函数。在 `catch` 块中使用此函数,可安全访问 axios 特有的错误属性,如 `error.response` 和 `error.config`。 + +```ts +isAxiosError(value: any): value is AxiosError; +``` + +```js +import axios from "axios"; + +try { + await axios.get("/api/resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + // error.response、error.config、error.code 均可使用 + console.error("HTTP error", error.response?.status, error.message); + } else { + // 非 axios 错误(例如编程错误) + throw error; + } +} +``` + +### `all` + +`all` 函数接受一组 Promise 并返回一个在所有 Promise 都完成后才完成的单一 Promise,现已废弃,推荐使用 `Promise.all` 方法。 + +从 0.22.0 版本起,`all` 函数已废弃,将在未来版本中移除。建议改用 `Promise.all` 方法。 + +### `spread` + +`spread` 函数可将一个参数数组展开为函数调用的多个参数,在你需要将数组参数传递给接收多个参数的函数时非常实用。 + +```ts +spread(callback: (...args: T[]) => R): (array: T[]) => R; +``` + +### `toFormData` + +将普通 JavaScript 对象(包括嵌套对象)转换为 `FormData` 实例,在需要从对象中以编程方式构建 multipart 表单数据时非常实用。 + +```ts +toFormData(sourceObj: object, formData?: FormData, options?: FormSerializerOptions): FormData; +``` + +```js +import { toFormData } from "axios"; + +const data = { name: "Jay", avatar: fileBlob }; +const form = toFormData(data); +// form 现在是一个可直接发送的 FormData 实例 +await axios.post("/api/users", form); +``` + +### `formToJSON` + +将 `FormData` 实例转换回普通 JavaScript 对象,在需要以结构化格式读取表单数据时非常实用。 + +```ts +formToJSON(form: FormData): object; +``` + +```js +import { formToJSON } from "axios"; + +const form = new FormData(); +form.append("name", "Jay"); +form.append("role", "admin"); + +const obj = formToJSON(form); +console.log(obj); // { name: "Jay", role: "admin" } +``` + +### `getAdapter` + +通过名称或名称数组解析并返回一个适配器函数。axios 在内部使用此函数为当前环境选择最合适的适配器。 + +```ts +getAdapter(adapters: string | string[]): AxiosAdapter; +``` + +```js +import { getAdapter } from "axios"; + +// 显式获取 fetch 适配器 +const fetchAdapter = getAdapter("fetch"); + +// 按优先级列表获取最合适的适配器 +const adapter = getAdapter(["fetch", "xhr", "http"]); +``` + +### `mergeConfig` + +合并两个 axios 配置对象,使用与 axios 内部合并默认配置和请求级选项相同的深度合并策略。后者的值优先级更高。 + +```ts +mergeConfig(config1: AxiosRequestConfig, config2: AxiosRequestConfig): AxiosRequestConfig; +``` + +```js +import { mergeConfig } from "axios"; + +const base = { baseURL: "https://api.example.com", timeout: 5000 }; +const override = { timeout: 10000, headers: { "X-Custom": "value" } }; + +const merged = mergeConfig(base, override); +// { baseURL: "https://api.example.com", timeout: 10000, headers: { "X-Custom": "value" } } +``` + +## 常量 + +### `HttpStatusCode` + +包含 HTTP 状态码命名常量的对象,可用于编写更具可读性的条件判断,避免直接使用数字字面量。 + +```js +import axios, { HttpStatusCode } from "axios"; + +try { + const response = await axios.get("/api/resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + if (error.response?.status === HttpStatusCode.NotFound) { + console.error("Resource not found"); + } else if (error.response?.status === HttpStatusCode.Unauthorized) { + console.error("Authentication required"); + } + } +} +``` + +## 其他 + +### `VERSION` + +`axios` 包的当前版本号字符串,随每次发布更新。 diff --git a/docs/zh/pages/advanced/authentication.md b/docs/zh/pages/advanced/authentication.md new file mode 100644 index 0000000..e9bf906 --- /dev/null +++ b/docs/zh/pages/advanced/authentication.md @@ -0,0 +1,142 @@ +# 认证 + +大多数 API 都需要某种形式的认证。本页介绍在 axios 请求中附加凭据的最常见模式。 + +## Bearer 令牌(JWT) + +最常见的方式是在 `Authorization` 请求头中附加 JWT。最简洁的做法是通过 axios 实例上的请求拦截器实现,这样令牌会在每次请求时实时读取: + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +api.interceptors.request.use((config) => { + const token = localStorage.getItem("access_token"); + if (token) { + config.headers.set("Authorization", `Bearer ${token}`); + } + return config; +}); +``` + +## HTTP Basic 认证 + +对于使用 HTTP Basic 认证的 API,传入 `auth` 选项即可。axios 会自动对凭据进行编码并设置 `Authorization` 请求头: + +```js +const response = await axios.get("https://api.example.com/data", { + auth: { + username: "myUser", + password: "myPassword", + }, +}); +``` + +::: tip +对于 Bearer 令牌和 API 密钥,请使用自定义 `Authorization` 请求头,而非 `auth` 选项——`auth` 仅适用于 HTTP Basic 认证。 +::: + +## API 密钥 + +API 密钥通常作为请求头或查询参数传递,具体取决于 API 的要求: + +```js +// 作为请求头 +const api = axios.create({ + baseURL: "https://api.example.com", + headers: { "X-API-Key": "your-api-key-here" }, +}); + +// 作为查询参数 +const response = await axios.get("https://api.example.com/data", { + params: { apiKey: "your-api-key-here" }, +}); +``` + +## 令牌刷新 + +当访问令牌过期时,你需要静默刷新它并重新发送失败的请求。响应拦截器是实现此逻辑的合适位置: + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +// 跟踪是否已有刷新正在进行,以避免并行发起多个刷新请求 +let isRefreshing = false; +let failedQueue = []; + +const processQueue = (error, token = null) => { + failedQueue.forEach((prom) => { + if (error) { + prom.reject(error); + } else { + prom.resolve(token); + } + }); + failedQueue = []; +}; + +api.interceptors.response.use( + (response) => response, + async (error) => { + const originalRequest = error.config; + + if (error.response?.status === 401 && !originalRequest._retry) { + if (isRefreshing) { + // 将请求加入队列,等待刷新完成 + return new Promise((resolve, reject) => { + failedQueue.push({ resolve, reject }); + }) + .then((token) => { + originalRequest.headers["Authorization"] = `Bearer ${token}`; + return api(originalRequest); + }) + .catch((err) => Promise.reject(err)); + } + + originalRequest._retry = true; + isRefreshing = true; + + try { + const { data } = await axios.post("/auth/refresh", { + refreshToken: localStorage.getItem("refresh_token"), + }); + + const newToken = data.access_token; + localStorage.setItem("access_token", newToken); + api.defaults.headers.common["Authorization"] = `Bearer ${newToken}`; + + processQueue(null, newToken); + return api(originalRequest); + } catch (refreshError) { + processQueue(refreshError, null); + // 跳转到登录页或触发事件 + localStorage.removeItem("access_token"); + window.location.href = "/login"; + return Promise.reject(refreshError); + } finally { + isRefreshing = false; + } + } + + return Promise.reject(error); + } +); +``` + +## 基于 Cookie 的认证 + +对于依赖 Cookie 的会话 API,设置 `withCredentials: true` 以在跨域请求中携带 Cookie: + +```js +const api = axios.create({ + baseURL: "https://api.example.com", + withCredentials: true, // 每次请求均携带 Cookie +}); +``` + +::: warning +`withCredentials: true` 要求服务器响应时携带 `Access-Control-Allow-Credentials: true`,且 `Access-Control-Allow-Origin` 必须为具体域名(不能是通配符)。 +::: diff --git a/docs/zh/pages/advanced/cancellation.md b/docs/zh/pages/advanced/cancellation.md new file mode 100644 index 0000000..4649c34 --- /dev/null +++ b/docs/zh/pages/advanced/cancellation.md @@ -0,0 +1,70 @@ +# 取消请求 + +从 v0.22.0 起,axios 支持使用 AbortController 以简洁的方式取消请求。该功能在浏览器和 Node.js(使用支持 AbortController 的 axios 版本)中均可使用。要取消请求,需要创建一个 `AbortController` 实例,并将其 `signal` 传入请求的 `signal` 选项。 + +```js +const controller = new AbortController(); + +axios + .get("/foo/bar", { + signal: controller.signal, + }) + .then(function (response) { + //... + }); +// 取消请求 +controller.abort(); +``` + +## CancelToken + +你也可以使用 `CancelToken` API 来取消请求。该 API 已废弃,将在下一个主版本中移除,建议改用 `AbortController`。可以使用 `CancelToken.source` 工厂方法创建取消令牌,如下所示: + +```js +const CancelToken = axios.CancelToken; +const source = CancelToken.source(); + +axios + .get("/user/12345", { + cancelToken: source.token, + }) + .catch(function (thrown) { + if (axios.isCancel(thrown)) { + console.log("Request canceled", thrown.message); + } else { + // 处理错误 + } + }); + +axios.post( + "/user/12345", + { + name: "new name", + }, + { + cancelToken: source.token, + } +); + +// 取消请求(message 参数可选) +source.cancel("Operation canceled by the user."); +``` + +也可以通过向 `CancelToken` 构造函数传入执行函数来创建取消令牌: + +```js +const CancelToken = axios.CancelToken; +let cancel; + +axios.get("/user/12345", { + cancelToken: new CancelToken(function executor(c) { + // 执行函数接收一个 cancel 函数作为参数 + cancel = c; + }), +}); + +// 取消请求 +cancel(); +``` + +你可以使用同一个取消令牌或 AbortController 取消多个请求。如果在 axios 请求开始时取消令牌已处于已取消状态,则请求会立即被取消,不会尝试发起实际的网络请求。 diff --git a/docs/zh/pages/advanced/config-defaults.md b/docs/zh/pages/advanced/config-defaults.md new file mode 100644 index 0000000..19e6a19 --- /dev/null +++ b/docs/zh/pages/advanced/config-defaults.md @@ -0,0 +1,48 @@ +# 配置默认值 + +axios 允许你指定应用于每个请求的配置默认值,包括 `baseURL`、`headers`、`timeout` 等属性。下面是使用配置默认值的示例: + +```js +axios.defaults.baseURL = "https://jsonplaceholder.typicode.com/posts"; +axios.defaults.headers.common["Authorization"] = AUTH_TOKEN; +axios.defaults.headers.post["Content-Type"] = + "application/x-www-form-urlencoded"; +``` + +## 自定义实例默认值 + +axios 实例在创建时会有自己的默认配置,这些默认配置可以通过修改实例的 `defaults` 属性来覆盖。下面是使用自定义实例默认值的示例: + +```js +var instance = axios.create({ + baseURL: "https://jsonplaceholder.typicode.com/posts", + timeout: 1000, + headers: { Authorization: "foobar" }, +}); + +instance.defaults.headers.common["Authorization"] = AUTH_TOKEN; +``` + +## 配置优先级 + +配置将按照优先级顺序合并,依次为:库的默认值、实例的默认属性,最后是请求时传入的配置参数。下面通过示例说明优先级顺序。 + +首先,创建一个使用库提供的默认值的实例。此时 timeout 配置值为 `0`,这是库的默认值。 + +```js +const instance = axios.create(); +``` + +接下来,将实例的 timeout 默认值覆盖为 `2500` 毫秒。此后,使用该实例的所有请求都将在 2.5 秒后超时。 + +```js +instance.defaults.timeout = 2500; +``` + +最后,发起一个 timeout 为 `5000` 毫秒的请求,该请求将在 5 秒后超时。 + +```js +instance.get("/longRequest", { + timeout: 5000, +}); +``` diff --git a/docs/zh/pages/advanced/create-an-instance.md b/docs/zh/pages/advanced/create-an-instance.md new file mode 100644 index 0000000..a0fcb6a --- /dev/null +++ b/docs/zh/pages/advanced/create-an-instance.md @@ -0,0 +1,87 @@ +# 创建实例 + +`axios.create()` 允许你创建一个预配置的 axios 实例。该实例与默认 `axios` 对象拥有相同的请求和响应 API,但会将你提供的配置作为每次请求的基础配置。对于任何超过单文件规模的应用,这是使用 axios 的推荐方式。 + +```ts +import axios from "axios"; + +const instance = axios.create({ + baseURL: "https://api.example.com", + timeout: 5000, + headers: { "X-Custom-Header": "foobar" }, +}); +``` + +`create` 方法接受完整的[请求配置](/pages/advanced/request-config)对象。之后可以像使用默认 axios 对象一样使用该实例: + +```js +const response = await instance.get("/users/1"); +``` + +## 为什么要使用实例? + +### 按服务设置 baseURL + +在大多数应用中,你需要与多个 API 通信。为每个服务创建独立的实例,可以避免在每次调用时重复指定 baseURL: + +```js +const githubApi = axios.create({ baseURL: "https://api.github.com" }); +const internalApi = axios.create({ baseURL: "https://api.internal.example.com" }); + +const { data: repos } = await githubApi.get("/users/axios/repos"); +const { data: users } = await internalApi.get("/users"); +``` + +### 共享认证请求头 + +在一个实例上附加认证令牌,让该实例的所有请求自动携带,而不影响其他实例: + +```js +const authApi = axios.create({ + baseURL: "https://api.example.com", + headers: { + Authorization: `Bearer ${getToken()}`, + }, +}); +``` + +### 按服务设置超时与重试 + +不同服务有不同的可靠性特征。可以为实时服务设置较短的超时,为批处理任务设置较长的超时: + +```js +const realtimeApi = axios.create({ baseURL: "https://realtime.example.com", timeout: 2000 }); +const batchApi = axios.create({ baseURL: "https://batch.example.com", timeout: 60000 }); +``` + +### 隔离的拦截器 + +添加到实例上的拦截器只对该实例生效,有助于保持关注点分离: + +```js +const loggingApi = axios.create({ baseURL: "https://api.example.com" }); + +loggingApi.interceptors.request.use((config) => { + console.log(`→ ${config.method?.toUpperCase()} ${config.url}`); + return config; +}); +``` + +## 按请求覆盖默认配置 + +在请求时传入的配置始终会覆盖实例默认配置: + +```js +const api = axios.create({ timeout: 5000 }); + +// 这个特定请求使用 30 秒超时 +await api.get("/slow-endpoint", { timeout: 30000 }); +``` + +::: tip +实例默认配置也可以在创建后通过修改 `instance.defaults` 来更改: + +```js +instance.defaults.headers.common["Authorization"] = `Bearer ${newToken}`; +``` +::: diff --git a/docs/zh/pages/advanced/error-handling.md b/docs/zh/pages/advanced/error-handling.md new file mode 100644 index 0000000..842f606 --- /dev/null +++ b/docs/zh/pages/advanced/error-handling.md @@ -0,0 +1,70 @@ +# 错误处理 + +axios 可能会抛出多种不同类型的错误,有些来自 axios 本身,有些来自服务器或客户端。下表列出了所抛出错误的基本结构: + +| 属性 | 说明 | +| ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| message | 错误信息的简要摘要,以及失败时的状态码。 | +| name | 定义错误的来源,对于 axios 来说始终是 `AxiosError`。 | +| stack | 提供错误的堆栈跟踪。 | +| config | 包含用户在发起请求时定义的特定实例配置的 axios 配置对象。 | +| code | 表示 axios 内部识别的错误,下表列出了 axios 内部错误的具体说明。 | +| status | HTTP 响应状态码。常见 HTTP 响应状态码的含义请参阅[此处](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)。 | + +以下是 axios 内部可能出现的错误列表: + +| 错误代码 | 说明 | +| ------------------------- | --------------------------------------------------------------------------------------- | +| ERR_BAD_OPTION_VALUE | axios 配置中提供了无效或不支持的值。 | +| ERR_BAD_OPTION | axios 配置中提供了无效选项。 | +| ECONNABORTED | 通常表示请求已超时(除非设置了 `transitional.clarifyTimeoutError`)或被浏览器或其插件中止。 | +| ETIMEDOUT | 请求因超过 axios 默认时限而超时。必须将 `transitional.clarifyTimeoutError` 设置为 `true`,否则会抛出通用的 `ECONNABORTED` 错误。 | +| ERR_NETWORK | 网络相关问题。在浏览器中,此错误也可能由 [CORS](https://developer.mozilla.org/ru/docs/Web/HTTP/Guides/CORS) 或[混合内容](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content)策略违规引起。出于安全考虑,浏览器不允许 JS 代码获知错误的真实原因,请检查控制台。 | +| ERR_FR_TOO_MANY_REDIRECTS | 请求重定向次数过多,超过了 axios 配置中指定的最大重定向次数。 | +| ERR_DEPRECATED | 使用了 axios 中已废弃的功能或方法。 | +| ERR_BAD_RESPONSE | 响应无法正确解析或格式异常,通常与 `5xx` 状态码的响应有关。 | +| ERR_BAD_REQUEST | 请求格式异常或缺少必要参数,通常与 `4xx` 状态码的响应有关。 | +| ERR_CANCELED | 功能或方法被用户通过 AbortSignal(或 CancelToken)显式取消。 | +| ERR_NOT_SUPPORT | 当前 axios 环境不支持该功能或方法。 | +| ERR_INVALID_URL | axios 请求提供了无效的 URL。 | + +## 处理错误 + +axios 的默认行为是在请求失败时 reject Promise。不过,你也可以捕获错误并按需处理。以下是捕获错误的示例: + +```js +axios.get("/user/12345").catch(function (error) { + if (error.response) { + // 请求已发出,服务器返回了不在 2xx 范围内的状态码 + console.log(error.response.data); + console.log(error.response.status); + console.log(error.response.headers); + } else if (error.request) { + // 请求已发出,但未收到响应 + // `error.request` 在浏览器中是 XMLHttpRequest 实例,在 node.js 中是 http.ClientRequest 实例 + console.log(error.request); + } else { + // 在设置请求时触发了错误 + console.log("Error", error.message); + } + console.log(error.config); +}); +``` + +使用 `validateStatus` 配置选项,可以覆盖默认条件(`status >= 200 && status < 300`),自定义应当抛出错误的 HTTP 状态码。 + +```js +axios.get("/user/12345", { + validateStatus: function (status) { + return status < 500; // 仅在状态码小于 500 时 resolve + }, +}); +``` + +使用 `toJSON` 方法,可以获取包含更多错误信息的对象。 + +```js +axios.get("/user/12345").catch(function (error) { + console.log(error.toJSON()); +}); +``` diff --git a/docs/zh/pages/advanced/fetch-adapter.md b/docs/zh/pages/advanced/fetch-adapter.md new file mode 100644 index 0000000..a28ea8e --- /dev/null +++ b/docs/zh/pages/advanced/fetch-adapter.md @@ -0,0 +1,81 @@ +# Fetch 适配器 + +`fetch` 适配器是我们在 1.7.0 版本中引入的新适配器,使 axios 能够使用 `fetch` API,兼顾两者的优势。默认情况下,当构建中 `xhr` 和 `http` 适配器不可用,或当前环境不支持时,会使用 `fetch`。若要将其作为默认适配器,必须在创建 axios 实例时通过 `adapter` 选项显式指定。 + +```js +import axios from 'axios'; + +const instance = axios.create({ + adapter: 'fetch', +}); +``` + +该适配器支持与 `xhr` 适配器相同的功能,包括上传和下载进度捕获,还支持额外的响应类型,如 `stream` 和 `formdata`(如果环境支持)。 + +## 自定义 fetch + +从 `v1.12.0` 起,你可以自定义 fetch 适配器,使用自定义的 `fetch` 函数代替环境全局的 `fetch`。可以通过 `env` 配置选项传入自定义的 `fetch` 函数、`Request` 和 `Response` 构造函数。这在使用提供了自己 `fetch` 实现的自定义环境或应用框架时非常实用。 + +::: info +使用自定义 `fetch` 函数时,可能还需要提供匹配的 `Request` 和 `Response` 构造函数。如果省略,将使用全局构造函数。如果你的自定义 `fetch` 与全局构造函数不兼容,可以传入 `null` 来禁用它们。 + +**注意:** 将 `Request` 和 `Response` 设置为 `null` 后,fetch 适配器将无法捕获上传和下载进度。 +::: + +### 基本示例 + +```js +import customFetchFunction from 'customFetchModule'; + +const instance = axios.create({ + adapter: 'fetch', + onDownloadProgress(e) { + console.log('downloadProgress', e); + }, + env: { + fetch: customFetchFunction, + Request: null, // null -> 禁用该构造函数 + Response: null, + }, +}); +``` + +### 与 Tauri 一起使用 + +[Tauri](https://tauri.app/plugin/http-client/) 提供了一个平台 `fetch` 函数,可绕过浏览器对原生层请求的 CORS 限制。以下示例展示了在 Tauri 应用中使用该自定义 fetch 配置 axios 的最简设置。 + +```js +import { fetch } from '@tauri-apps/plugin-http'; +import axios from 'axios'; + +const instance = axios.create({ + adapter: 'fetch', + onDownloadProgress(e) { + console.log('downloadProgress', e); + }, + env: { + fetch, + }, +}); + +const { data } = await instance.get('https://google.com'); +``` + +### 与 SvelteKit 一起使用 + +[SvelteKit](https://svelte.dev/docs/kit/web-standards#Fetch-APIs) 为服务端 `load` 函数提供了自定义的 `fetch` 实现,用于处理 Cookie 转发和相对 URL。由于其 `fetch` 与标准 `URL` API 不兼容,必须明确配置 axios 使用它,并禁用全局 `Request` 和 `Response` 构造函数。 + +```js +export async function load({ fetch }) { + const { data: post } = await axios.get('https://jsonplaceholder.typicode.com/posts/1', { + adapter: 'fetch', + env: { + fetch, + Request: null, + Response: null, + }, + }); + + return { post }; +} +``` diff --git a/docs/zh/pages/advanced/file-posting.md b/docs/zh/pages/advanced/file-posting.md new file mode 100644 index 0000000..d75d163 --- /dev/null +++ b/docs/zh/pages/advanced/file-posting.md @@ -0,0 +1,99 @@ +# 文件上传 + +axios 让文件上传变得简单。需要 `multipart/form-data` 上传时,使用 `postForm` 或 `FormData` 即可。 + +## 单文件上传(浏览器) + +直接将 `File` 对象作为字段值传入——axios 会自动检测并使用正确的内容类型: + +```js +await axios.postForm("https://httpbin.org/post", { + description: "My profile photo", + file: document.querySelector("#fileInput").files[0], +}); +``` + +## 多文件上传(浏览器) + +传入 `FileList` 可一次性上传所有选中的文件,所有文件将使用相同的字段名(`files[]`)发送: + +```js +await axios.postForm( + "https://httpbin.org/post", + document.querySelector("#fileInput").files +); +``` + +如需为每个文件使用不同的字段名,请手动构建 `FormData` 对象: + +```js +const formData = new FormData(); +formData.append("avatar", avatarFile); +formData.append("cover", coverFile); + +await axios.post("https://httpbin.org/post", formData); +``` + +## 跟踪上传进度(浏览器) + +使用 `onUploadProgress` 回调向用户显示进度条或百分比: + +```js +await axios.postForm("https://httpbin.org/post", { + file: document.querySelector("#fileInput").files[0], +}, { + onUploadProgress: (progressEvent) => { + const percent = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log(`Upload progress: ${percent}%`); + }, +}); +``` + +进度事件对象上可用的完整字段列表,请参阅[进度捕获](/pages/advanced/progress-capturing)。 + +## Node.js 中的文件上传 + +在 Node.js 中,使用 `fs.createReadStream` 上传文件系统中的文件,无需将整个文件加载到内存: + +```js +import fs from "fs"; +import FormData from "form-data"; +import axios from "axios"; + +const form = new FormData(); +form.append("file", fs.createReadStream("/path/to/file.jpg")); +form.append("description", "My uploaded file"); + +await axios.post("https://httpbin.org/post", form); +``` + +::: tip +在 Node.js 环境中创建 `FormData` 对象需要 `form-data` npm 包。在现代 Node.js(v18+)中,全局 `FormData` 已原生可用。 +::: + +## 上传 Buffer(Node.js) + +也可以直接上传内存中的 `Buffer`: + +```js +const buffer = Buffer.from("Hello, world!"); + +const form = new FormData(); +form.append("file", buffer, { + filename: "hello.txt", + contentType: "text/plain", + knownLength: buffer.length, +}); + +await axios.post("https://httpbin.org/post", form); +``` + +::: warning +Node.js 环境目前不支持捕获 `FormData` 上传进度。 +::: + +::: danger +在 Node.js 中上传可读流时,请设置 `maxRedirects: 0`,以防止 `follow-redirects` 包将整个流缓冲到内存中。 +::: diff --git a/docs/zh/pages/advanced/header-methods.md b/docs/zh/pages/advanced/header-methods.md new file mode 100644 index 0000000..668cf60 --- /dev/null +++ b/docs/zh/pages/advanced/header-methods.md @@ -0,0 +1,188 @@ +# 请求头方法 + +随着新 `AxiosHeaders` 类的引入,axios 提供了一组操作请求头的方法,比直接操作请求头对象更加方便。 + +## 构造函数 `new AxiosHeaders(headers?)` + +`AxiosHeaders` 类的构造函数接受一个可选的请求头对象来初始化实例,对象可以包含任意数量的请求头,且键名不区分大小写。 + +```js +constructor(headers?: RawAxiosHeaders | AxiosHeaders | string); +``` + +为方便起见,你可以传入一个以换行符分隔的请求头字符串,它们会被解析并添加到实例中。 + +```js +const headers = new AxiosHeaders(` +Host: www.bing.com +User-Agent: curl/7.54.0 +Accept: */*`); + +console.log(headers); + +// Object [AxiosHeaders] { +// host: 'www.bing.com', +// 'user-agent': 'curl/7.54.0', +// accept: '*/*' +// } +``` + +## Set + +`set` 方法用于在 `AxiosHeaders` 实例上设置请求头,可以传入单个请求头名称和值、包含多个请求头的对象,或以换行符分隔的请求头字符串。该方法还接受一个可选的 `rewrite` 参数,用于控制设置请求头时的覆盖行为。 + +```js +set(headerName, value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher); +set(headerName, value, rewrite?: (this: AxiosHeaders, value: string, name: string) => boolean); +set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean); +``` + +`rewrite` 参数控制覆盖行为: + +- `false` - 如果请求头的值已设置(不为 undefined),则不覆盖 +- `undefined`(默认)- 覆盖请求头,除非其值被设置为 false +- `true` - 始终覆盖 + +该参数也可以接受一个用户自定义函数,用于决定是否应覆盖该值,函数接收当前值、请求头名称和请求头对象作为参数。 + +`AxiosHeaders` 会保留第一个匹配键的大小写形式。你可以利用这一特性,先以 `undefined` 值预设一个键名,之后再设置值,从而保留特定的请求头大小写。详见[保留特定请求头大小写](/pages/advanced/headers#preserving-a-specific-header-case)。 + +## Get + +`get` 方法用于获取请求头的值,可以传入单个请求头名称、可选的匹配器或解析器。匹配器默认为 `true`,解析器可以是用于从请求头中提取值的正则表达式。 + +```js +get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue; +get(headerName: string, parser: RegExp): RegExpExecArray | null; +``` + +以下是 `get` 方法的一些使用示例: + +```js +const headers = new AxiosHeaders({ + 'Content-Type': 'multipart/form-data; boundary=Asrf456BGe4h', +}); + +console.log(headers.get('Content-Type')); +// multipart/form-data; boundary=Asrf456BGe4h + +console.log(headers.get('Content-Type', true)); // 解析以 \s,;= 为分隔符的键值对字符串: +// [Object: null prototype] { +// 'multipart/form-data': undefined, +// boundary: 'Asrf456BGe4h' +// } + +console.log( + headers.get('Content-Type', (value, name, headers) => { + return String(value).replace(/a/g, 'ZZZ'); + }) +); +// multipZZZrt/form-dZZZtZZZ; boundZZZry=Asrf456BGe4h + +console.log(headers.get('Content-Type', /boundary=(\w+)/)?.[0]); +// boundary=Asrf456BGe4h +``` + +## Has + +`has` 方法用于检查 `AxiosHeaders` 实例中是否存在某个请求头,可以传入单个请求头名称和可选的匹配器。 + +```js +has(header: string, matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +如果请求头已设置(值不为 undefined),则返回 true。 +::: + +## Delete + +`delete` 方法用于从 `AxiosHeaders` 实例中删除某个请求头,可以传入单个请求头名称和可选的匹配器。 + +```js +delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +如果至少有一个请求头被移除,则返回 true。 +::: + +## Clear + +`clear` 方法用于在不传入任何参数时删除 `AxiosHeaders` 实例中的所有请求头。如果传入匹配器,则只移除与匹配器匹配的请求头,此时匹配器用于匹配请求头名称而非值。 + +```js +clear(matcher?: AxiosHeaderMatcher): boolean; +``` + +::: info +如果至少有一个请求头被清除,则返回 true。 +::: + +## Normalize + +如果直接修改了请求头对象,可能导致相同名称但大小写不同的重复项。此方法通过将重复键合并为一个来规范化请求头对象。axios 在每个拦截器调用后内部使用此方法。将 format 设置为 true 可将请求头名称转换为首字母大写的格式(cOntEnt-type => Content-Type),设置为 false 则保留原始格式。 + +```js +const headers = new AxiosHeaders({ + foo: '1', +}); + +headers.Foo = '2'; +headers.FOO = '3'; + +console.log(headers.toJSON()); // [Object: null prototype] { foo: '1', Foo: '2', FOO: '3' } +console.log(headers.normalize().toJSON()); // [Object: null prototype] { foo: '3' } +console.log(headers.normalize(true).toJSON()); // [Object: null prototype] { Foo: '3' } +``` + +::: info +返回 `this` 以支持链式调用。 +::: + +## Concat + +将实例与目标对象合并到一个新的 AxiosHeaders 实例中。如果目标是字符串,它将被解析为原始 HTTP 请求头;如果目标是 AxiosHeaders 实例,它将与当前实例合并。 + +这对于组合请求头时的大小写预设非常有用,例如: + +```js +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); +``` + +```js +concat(...targets: Array): AxiosHeaders; +``` + +::: info +返回一个新的 AxiosHeaders 实例。 +::: + +## toJSON + +将所有内部请求头值解析到一个新的 null 原型对象中。将 `asStrings` 设置为 true 可将数组解析为以逗号分隔的字符串。 + +```js +toJSON(asStrings?: boolean): RawAxiosHeaders; +``` + +## From + +从传入的原始请求头创建并返回一个新的 `AxiosHeaders` 实例;如果传入的已经是 `AxiosHeaders` 实例,则直接返回该实例。 + +```js +from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders; +``` + +## 快捷方法 + +以下快捷方法可供使用: + +- `setContentType`、`getContentType`、`hasContentType` +- `setContentLength`、`getContentLength`、`hasContentLength` +- `setAccept`、`getAccept`、`hasAccept` +- `setUserAgent`、`getUserAgent`、`hasUserAgent` +- `setContentEncoding`、`getContentEncoding`、`hasContentEncoding` diff --git a/docs/zh/pages/advanced/headers.md b/docs/zh/pages/advanced/headers.md new file mode 100644 index 0000000..8fbdd81 --- /dev/null +++ b/docs/zh/pages/advanced/headers.md @@ -0,0 +1,153 @@ +# 请求头 + +axios 暴露了自己的 AxiosHeaders 类,通过类 Map 的 API 来操作请求头,保证键名不区分大小写。axios 内部使用该类管理请求头,同时也将其暴露给用户以提供便利。尽管 HTTP 请求头本身不区分大小写,axios 仍会保留原始请求头的大小写形式,以满足风格需求,并在服务器错误地将请求头大小写视为有效区分时提供兼容。直接操作请求头对象的旧方式仍然可用,但已废弃,不建议在新代码中使用。 + +## 使用请求头 + +AxiosHeaders 对象实例可以包含不同类型的内部值,用于控制设置和合并逻辑。axios 在将最终请求头对象发送前会调用 `toJSON` 方法。AxiosHeaders 对象也是可迭代的,可以在循环中使用,或转换为数组或对象。 + +请求头值可以是以下类型之一: + +- `string` - 正常的字符串值,将被发送到服务器 +- `null` - 转换为 JSON 时跳过该请求头 +- `false` - 转换为 JSON 时跳过该请求头,并额外表示调用 `set` 方法时必须将 `rewrite` 选项设置为 true 才能覆盖此值(axios 内部使用此机制允许用户选择不安装某些请求头,如 User-Agent 或 Content-Type) +- `undefined` - 值未设置 + +::: warning +如果请求头值不是 undefined,则视为已设置。 +::: + +请求头对象始终在拦截器和转换器中初始化,如以下示例所示: + +```js +axios.interceptors.request.use((request: InternalAxiosRequestConfig) => { + request.headers.set("My-header", "value"); + + request.headers.set({ + "My-set-header1": "my-set-value1", + "My-set-header2": "my-set-value2", + }); + + // 禁止 axios 后续设置此请求头 + request.headers.set("User-Agent", false); + + request.headers.setContentType("text/plain"); + + // 直接访问的方式已废弃 + request.headers["My-set-header2"] = "newValue"; + + return request; +}); +``` + +你可以使用任何可迭代方法遍历 AxiosHeaders,如 for-of 循环、forEach 或展开运算符: + +```js +const headers = new AxiosHeaders({ + foo: '1', + bar: '2', + baz: '3', +}); + +for (const [header, value] of headers) { + console.log(header, value); +} + +// foo 1 +// bar 2 +// baz 3 +``` + +## 在请求中设置请求头 + +最常见的设置请求头的方式是在请求配置或实例配置的 `headers` 选项中设置: + +```js +// 针对单个请求 +await axios.get('/api/data', { + headers: { + 'Accept-Language': 'en-US', + 'X-Request-ID': 'abc123', + }, +}); + +// 针对实例(应用于每个请求) +const api = axios.create({ + headers: { + 'X-App-Version': '2.0.0', + }, +}); +``` + +## 保留特定请求头大小写 + +axios 请求头名称不区分大小写,但 `AxiosHeaders` 会保留第一个匹配键的大小写形式。如果你需要为大小写敏感的非标准服务器保留特定大小写,可以在 `defaults` 中预设键名,之后再按常规方式设置值。 + +```js +const api = axios.create(); + +api.defaults.headers.common = { + 'content-type': undefined, + accept: undefined, +}; + +await api.put(url, data, { + headers: { + 'Content-Type': 'application/octet-stream', + Accept: 'application/json', + }, +}); +``` + +也可以在组合请求头时直接使用 `AxiosHeaders` 实现: + +```js +import axios, { AxiosHeaders } from 'axios'; + +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); + +await axios.put(url, data, { headers }); +``` + +## 在拦截器中设置请求头 + +拦截器是附加动态请求头(如认证令牌)的合适位置,因为令牌可能在实例首次创建时还不可用: + +```js +api.interceptors.request.use((config) => { + const token = getAuthToken(); // 在请求时读取 + config.headers.set('Authorization', `Bearer ${token}`); + return config; +}); +``` + +## 读取响应头 + +响应头以 `AxiosHeaders` 实例的形式在 `response.headers` 上可用,所有头名称均为小写: + +```js +const response = await axios.get('/api/data'); + +console.log(response.headers['content-type']); +// application/json; charset=utf-8 + +console.log(response.headers.get('x-request-id')); +// abc123 +``` + +## 移除默认请求头 + +如需取消 axios 默认设置的请求头(如 `Content-Type` 或 `User-Agent`),将其值设置为 `false`: + +```js +await axios.post('/api/data', payload, { + headers: { + 'Content-Type': false, // 让浏览器自动设置(例如针对 FormData) + }, +}); +``` + +关于完整 `AxiosHeaders` 方法 API 的详细说明,请参阅[请求头方法](/pages/advanced/header-methods)页面。 diff --git a/docs/zh/pages/advanced/html-form-processing.md b/docs/zh/pages/advanced/html-form-processing.md new file mode 100644 index 0000000..b0e67ff --- /dev/null +++ b/docs/zh/pages/advanced/html-form-processing.md @@ -0,0 +1,57 @@ +# HTML 表单提交(浏览器) + +你也可以直接从 HTML 表单元素提交数据,无需任何额外的 JavaScript 代码即可提交页面中的表单。 + +```js +await axios.postForm('https://httpbin.org/post', document.querySelector('#htmlForm')); +``` + +`FormData` 和 `HTMLForm` 对象也可以通过显式将 `Content-Type` 请求头设置为 `application/json` 来以 `JSON` 格式发送: + +```js +await axios.post('https://httpbin.org/post', document.querySelector('#htmlForm'), { + headers: { + 'Content-Type': 'application/json', + }, +}); +``` + +以下是一个有效的、可被上述代码提交的表单示例: + +```html +
+ + + + + + + + + +
+``` + +上述表单将以如下格式提交: + +```json +{ + "foo": "1", + "deep": { + "prop": "2", + "prop spaced": "3" + }, + "baz": ["4", "5"], + "user": { + "age": "value2" + } +} +``` + +::: warning +目前不支持将 Blob/File 以 JSON(base64)格式发送。 +::: diff --git a/docs/zh/pages/advanced/http2.md b/docs/zh/pages/advanced/http2.md new file mode 100644 index 0000000..ea928f5 --- /dev/null +++ b/docs/zh/pages/advanced/http2.md @@ -0,0 +1,72 @@ +# HTTP2 + +在 `1.13.0` 版本中,`http` 适配器新增了实验性的 HTTP/2 支持,仅在 Node.js 环境中可用。 + +## 基本用法 + +使用 `httpVersion` 选项来选择请求使用的协议版本,将其设置为 `2` 可启用 HTTP/2。 + +```js +const { data, headers, status } = await axios.post( + "https://httpbin.org/post", + form, + { + httpVersion: 2, + }, +); +``` + +## `http2Options` + +可以通过 `http2Options` 配置对象传入内部 `session.request()` 调用的原生额外选项,其中还包括自定义的 `sessionTimeout` 参数,用于控制空闲 HTTP/2 会话在关闭前保持存活的时间(毫秒),默认值为 `1000ms`。 + +```js +{ + httpVersion: 2, + http2Options: { + rejectUnauthorized: false, // 接受自签名证书(仅用于开发环境) + sessionTimeout: 5000, // 空闲会话保持 5 秒 + }, +} +``` + +::: warning +HTTP/2 支持目前仍为实验性功能,API 可能在未来的次要版本或补丁版本中发生变化。 +::: + +## 完整示例 + +以下示例通过 HTTP/2 发送 `multipart/form-data` POST 请求,并同时跟踪上传和下载进度。 + +```js +const form = new FormData(); +form.append("foo", "123"); + +const { data, headers, status } = await axios.post( + "https://httpbin.org/post", + form, + { + httpVersion: 2, + http2Options: { + // rejectUnauthorized: false, + // sessionTimeout: 1000 + }, + onUploadProgress(e) { + console.log("upload progress", e); + }, + onDownloadProgress(e) { + console.log("download progress", e); + }, + responseType: "arraybuffer", + }, +); +``` + +## 配置参考 + +| 选项 | 类型 | 默认值 | 说明 | +|---|---|---|---| +| `httpVersion` | `number` | `1` | 使用的 HTTP 协议版本,设置为 `2` 可启用 HTTP/2。 | +| `http2Options.sessionTimeout` | `number` | `1000` | 空闲 HTTP/2 会话关闭前等待的时间(毫秒)。 | + +Node.js 内置 `http2` 模块支持的其他原生 `session.request()` 选项也可以通过 `http2Options` 传入。 diff --git a/docs/zh/pages/advanced/interceptors.md b/docs/zh/pages/advanced/interceptors.md new file mode 100644 index 0000000..7003ebe --- /dev/null +++ b/docs/zh/pages/advanced/interceptors.md @@ -0,0 +1,116 @@ +# 拦截器 + +拦截器是一种强大的机制,可用于拦截和修改 HTTP 请求与响应,与 Express.js 中的中间件非常相似。拦截器是在请求发送前和响应接收前执行的函数,适用于日志记录、修改请求头、修改响应等多种场景。 + +拦截器的基本用法如下: + +```js +// 添加请求拦截器 +axios.interceptors.request.use( + function (config) { + // 在请求发送之前执行某些操作 + return config; + }, + function (error) { + // 处理请求错误 + return Promise.reject(error); + } +); + +// 添加响应拦截器 +axios.interceptors.response.use( + function (response) { + // 状态码在 2xx 范围内的响应会触发此函数 + // 处理响应数据 + return response; + }, + function (error) { + // 状态码不在 2xx 范围内的响应会触发此函数 + // 处理响应错误 + return Promise.reject(error); + } +); +``` + +## 移除拦截器 + +可以通过对要移除的拦截器调用 `eject` 方法来移除特定拦截器。也可以通过在 `axios.interceptors` 对象上调用 `clear` 方法来移除所有拦截器。以下是移除拦截器的示例: + +```js +// 移除请求拦截器 +const myInterceptor = axios.interceptors.request.use(function () { + /*...*/ +}); +axios.interceptors.request.eject(myInterceptor); + +// 移除响应拦截器 +const myInterceptor = axios.interceptors.response.use(function () { + /*...*/ +}); +axios.interceptors.response.eject(myInterceptor); +``` + +以下是移除所有拦截器的示例: + +```js +const instance = axios.create(); +instance.interceptors.request.use(function () { + /*...*/ +}); +instance.interceptors.request.clear(); // 移除所有请求拦截器 +instance.interceptors.response.use(function () { + /*...*/ +}); +instance.interceptors.response.clear(); // 移除所有响应拦截器 +``` + +## 拦截器的默认行为 + +添加请求拦截器时,默认被视为异步执行。当主线程被阻塞时(拦截器底层会创建一个 Promise,你的请求会被放到调用栈底部),这可能导致 axios 请求的执行出现延迟。如果你的请求拦截器是同步的,可以在选项对象中添加一个标志,告知 axios 同步运行该代码,从而避免请求执行的延迟。 + +```js +axios.interceptors.request.use( + function (config) { + config.headers.test = "I am only a header!"; + return config; + }, + null, + { synchronous: true } +); +``` + +## 使用 `runWhen` 的拦截器 + +如果你希望根据运行时条件决定是否执行某个拦截器,可以在选项对象中添加 `runWhen` 函数。仅当 `runWhen` 返回 `false` 时,拦截器不会执行。该函数会以 config 对象作为参数调用(你也可以为其绑定自定义参数)。这对于只需在特定时机运行的异步请求拦截器非常实用。 + +```js +function onGetCall(config) { + return config.method === "get"; +} +axios.interceptors.request.use( + function (config) { + config.headers.test = "special get headers"; + return config; + }, + null, + { runWhen: onGetCall } +); +``` + +## 多个拦截器 + +你可以在同一个请求或响应上添加多个拦截器,同一拦截器链中的多个拦截器遵循以下规则: + +- 每个拦截器都会执行 +- 请求拦截器按照后进先出(LIFO)的顺序执行 +- 响应拦截器按照添加顺序(FIFO)执行 +- 只返回最后一个拦截器的结果 +- 每个拦截器接收其前驱拦截器的结果 +- 当成功回调中的拦截器抛出错误时 + - 后续的成功回调拦截器不会被调用 + - 后续的错误回调拦截器会被调用 + - 一旦被捕获,后续的成功回调拦截器将再次被调用(与 Promise 链的行为一致) + +::: tip +要深入了解拦截器的工作原理,可以查阅[这里](https://github.com/axios/axios/blob/v1.x/test/specs/interceptors.spec.js)的测试用例。 +::: diff --git a/docs/zh/pages/advanced/multipart-form-data-format.md b/docs/zh/pages/advanced/multipart-form-data-format.md new file mode 100644 index 0000000..76f92e7 --- /dev/null +++ b/docs/zh/pages/advanced/multipart-form-data-format.md @@ -0,0 +1,120 @@ +# multipart/form-data 格式 + +axios 支持以 `multipart/form-data` 格式发送请求,这种格式常用于文件上传。要以该格式发送请求,需要创建一个 `FormData` 对象并向其追加数据,然后将 `FormData` 对象传入 axios 请求配置的 `data` 属性。 + +```js +const formData = new FormData(); +formData.append("foo", "bar"); + +axios.post("https://httpbin.org/post", formData); +``` + +在 Node.js 中,可以使用 `form-data` 库,如下所示: + +```js +const FormData = require("form-data"); + +const form = new FormData(); +form.append("my_field", "my value"); +form.append("my_buffer", Buffer.alloc(10)); +form.append("my_file", fs.createReadStream("/foo/bar.jpg")); + +axios.post("https://example.com", form); +``` + +## 自动序列化为 FormData + +从 v0.27.0 起,如果请求的 Content-Type 请求头设置为 `multipart/form-data`,axios 支持自动将对象序列化为 FormData 对象。这意味着你可以直接将 JavaScript 对象传入 axios 请求配置的 `data` 属性。例如,向 POST 请求传递数据时: + +```js +import axios from "axios"; + +axios + .post( + "https://httpbin.org/post", + { x: 1 }, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ) + .then(({ data }) => console.log(data)); +``` + +在 Node.js 构建中,默认使用 ([`form-data`](https://github.com/form-data/form-data)) 作为 polyfill。你可以通过设置 `env.FormData` 配置变量来覆盖 FormData 类,但大多数情况下不需要这样做: + +```js +const axios = require("axios"); +var FormData = require("form-data"); + +axios + .post( + "https://httpbin.org/post", + { x: 1, buf: Buffer.alloc(10) }, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ) + .then(({ data }) => console.log(data)); +``` + +## 支持的特殊结尾 + +axios FormData 序列化器支持以下特殊结尾,用于执行对应操作: + +- `{}` - 使用 JSON.stringify 序列化该值 +- `[]` - 将类数组对象展开为具有相同键的独立字段 + +::: warning +注意:展开/扩展操作默认应用于数组和 FileList 对象 +::: + +## 配置 FormData 序列化器 + +FormData 序列化器通过 `config.formSerializer` 对象属性支持以下额外选项,用于处理特殊情况: + +- `visitor: Function` - 用户自定义的访问者函数,将递归调用以按照自定义规则将数据对象序列化为 FormData 对象。 +- `dots: boolean = false` - 使用点号表示法代替方括号来序列化数组和对象; +- `metaTokens: boolean = true` - 在 FormData 键中添加特殊结尾(如 `user{}: '{"name": "John"}'`)。后端 body 解析器可以利用此元信息自动将值解析为 JSON。 +- `indexes: null|false|true = false` - 控制如何为扁平类数组对象的展开键添加索引 + - `null` - 不添加方括号(`arr: 1`,`arr: 2`,`arr: 3`) + - `false`(默认)- 添加空方括号(`arr[]: 1`,`arr[]: 2`,`arr[]: 3`) + - `true` - 添加带索引的方括号(`arr[0]: 1`,`arr[1]: 2`,`arr[2]: 3`) + +例如,对于以下对象: + +```js +const obj = { + x: 1, + arr: [1, 2, 3], + arr2: [1, [2], 3], + users: [ + { name: "Peter", surname: "Griffin" }, + { name: "Thomas", surname: "Anderson" }, + ], + "obj2{}": [{ x: 1 }], +}; +``` + +axios 序列化器内部将执行以下步骤: + +```js +const formData = new FormData(); +formData.append("x", "1"); +formData.append("arr[]", "1"); +formData.append("arr[]", "2"); +formData.append("arr[]", "3"); +formData.append("arr2[0]", "1"); +formData.append("arr2[1][0]", "2"); +formData.append("arr2[2]", "3"); +formData.append("users[0][name]", "Peter"); +formData.append("users[0][surname]", "Griffin"); +formData.append("users[1][name]", "Thomas"); +formData.append("users[1][surname]", "Anderson"); +formData.append("obj2{}", '[{"x":1}]'); +``` + +axios 支持以下快捷方法:`postForm`、`putForm`、`patchForm`,它们分别对应相应的 HTTP 方法,并预设 `Content-Type` 请求头为 `multipart/form-data`。 diff --git a/docs/zh/pages/advanced/progress-capturing.md b/docs/zh/pages/advanced/progress-capturing.md new file mode 100644 index 0000000..81af9b0 --- /dev/null +++ b/docs/zh/pages/advanced/progress-capturing.md @@ -0,0 +1,55 @@ +# 进度捕获 + +axios 同时支持在浏览器和 Node.js 环境中捕获请求的上传/下载进度。进度事件的触发频率被限制为每秒最多 3 次,以避免浏览器被过多的进度事件压垮。以下是捕获进度事件的示例: + +```js +await axios.post(url, data, { + onUploadProgress: function (axiosProgressEvent) { + /*{ + loaded: number; + total?: number; + progress?: number; // 范围 [0..1] + bytes: number; // 自上次触发以来传输的字节数(增量) + estimated?: number; // 预计剩余时间(秒) + rate?: number; // 上传速度(字节/秒) + upload: true; // 上传标识 + }*/ + }, + + onDownloadProgress: function (axiosProgressEvent) { + /*{ + loaded: number; + total?: number; + progress?: number; + bytes: number; + estimated?: number; + rate?: number; // 下载速度(字节/秒) + download: true; // 下载标识 + }*/ + }, +}); +``` + +你也可以在 Node.js 中将上传和下载进度事件流式传输到可读流,以便以自定义方式显示进度。以下是流式传输进度事件的示例: + +```js +const { data } = await axios.post(SERVER_URL, readableStream, { + onUploadProgress: ({ progress }) => { + console.log((progress * 100).toFixed(2)); + }, + + headers: { + "Content-Length": contentLength, + }, + + maxRedirects: 0, // 避免缓冲整个流 +}); +``` + +::: warning +Node.js 环境目前不支持捕获 FormData 上传进度 +::: + +::: danger +建议通过设置 `maxRedirects: 0` 来禁用重定向,以便在 Node.js 环境中上传流,因为 `follow-redirects` 包会不遵循"背压"算法而将整个流缓冲到内存中 +::: diff --git a/docs/zh/pages/advanced/promises.md b/docs/zh/pages/advanced/promises.md new file mode 100644 index 0000000..928a18b --- /dev/null +++ b/docs/zh/pages/advanced/promises.md @@ -0,0 +1,81 @@ +# Promise + +axios 基于原生 ES6 Promise API 构建。每个 axios 请求都返回一个 Promise,该 Promise 解析为响应对象或以错误拒绝。如果你的环境不支持 ES6 Promise,需要使用 polyfill,例如 [es6-promise](https://github.com/stefanpenner/es6-promise)。 + +## then / catch / finally + +由于 axios 返回的是标准 Promise,你可以使用 `.then()`、`.catch()` 和 `.finally()` 来处理结果: + +```js +axios.get("/api/users") + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error("Request failed:", error.message); + }) + .finally(() => { + console.log("Request finished"); + }); +``` + +## async / await + +大多数代码库推荐使用 `async/await`,它使异步代码读起来像同步代码: + +```js +async function fetchUser(id) { + try { + const response = await axios.get(`/api/users/${id}`); + return response.data; + } catch (error) { + console.error("Failed to fetch user:", error.message); + throw error; + } +} +``` + +## 并行请求 + +由于 axios 返回标准 Promise,你可以使用 `Promise.all` 同时发起多个请求,并等待所有请求完成: + +```js +const [users, posts] = await Promise.all([ + axios.get("/api/users"), + axios.get("/api/posts"), +]); + +console.log(users.data, posts.data); +``` + +::: tip +`Promise.all` 会在任何一个请求失败时立即 reject。如果你希望处理部分失败的情况,请改用 `Promise.allSettled`。 +::: + +```js +const results = await Promise.allSettled([ + axios.get("/api/users"), + axios.get("/api/posts"), +]); + +results.forEach((result) => { + if (result.status === "fulfilled") { + console.log(result.value.data); + } else { + console.error("Request failed:", result.reason.message); + } +}); +``` + +## 链式请求 + +可以链式调用 `.then()` 来顺序执行请求,将上一个请求的数据传递给下一个: + +```js +axios.get("/api/user/1") + .then(({ data: user }) => axios.get(`/api/posts?userId=${user.id}`)) + .then(({ data: posts }) => { + console.log("Posts for user:", posts); + }) + .catch(console.error); +``` diff --git a/docs/zh/pages/advanced/rate-limiting.md b/docs/zh/pages/advanced/rate-limiting.md new file mode 100644 index 0000000..d2c16a9 --- /dev/null +++ b/docs/zh/pages/advanced/rate-limiting.md @@ -0,0 +1,62 @@ +# 速率限制 + +axios 通过 HTTP 适配器在 Node.js 环境中支持带宽限制。你可以限制数据的上传或下载速度,适用于批量操作、后台任务或不希望占满带宽的礼貌抓取等场景。 + +## `maxRate` + +`maxRate` 选项接受一个数字(字节/秒)或一个数组,数组第一个值为上传限制,第二个值为下载限制。使用 `[uploadRate]` 仅限制上传,使用 `[uploadRate, downloadRate]` 同时限制两个方向。传入单个数字时,该限制同时应用于上传和下载。 + +```js +// 将上传和下载速度均限制为 100 KB/s +await axios.get(URL, { maxRate: 100 * 1024 }); + +// 上传限制 100 KB/s,下载限制 500 KB/s +await axios.get(URL, { maxRate: [100 * 1024, 500 * 1024] }); +``` + +::: warning +`maxRate` 仅支持 Node.js HTTP 适配器,在浏览器环境中无效。 +::: + +## 上传速率限制 + +限制上传速度的同时记录进度: + +```js +const { data } = await axios.post(SERVER_URL, myBuffer, { + onUploadProgress: ({ progress, rate }) => { + const percent = (progress * 100).toFixed(1); + const kbps = (rate / 1024).toFixed(1); + console.log(`Upload [${percent}%] at ${kbps} KB/s`); + }, + + maxRate: [100 * 1024], // 上传限制 100 KB/s +}); +``` + +## 下载速率限制 + +限制大响应体的下载速度: + +```js +const { data } = await axios.get(FILE_URL, { + onDownloadProgress: ({ progress, rate }) => { + const percent = (progress * 100).toFixed(1); + const kbps = (rate / 1024).toFixed(1); + console.log(`Download [${percent}%] at ${kbps} KB/s`); + }, + + maxRate: [Infinity, 200 * 1024], // 不限制上传,下载限制 200 KB/s + responseType: "arraybuffer", +}); +``` + +## 同时限制上传和下载 + +将两个限制作为数组传入,可同时控制两个方向: + +```js +await axios.post(SERVER_URL, largeBuffer, { + maxRate: [50 * 1024, 500 * 1024], // 上传 50 KB/s,下载 500 KB/s +}); +``` diff --git a/docs/zh/pages/advanced/request-config.md b/docs/zh/pages/advanced/request-config.md new file mode 100644 index 0000000..04cfcfe --- /dev/null +++ b/docs/zh/pages/advanced/request-config.md @@ -0,0 +1,350 @@ +# 请求配置 + +请求配置用于配置 HTTP 请求的各项参数。虽然有大量可用选项,但唯一必填的选项是 `url`。如果配置对象中没有 `method` 字段,默认使用 `GET` 方法。 + +### `url` + +`url` 是请求的目标 URL,可以是字符串或 `URL` 实例。 + +### `method` + +`method` 是请求使用的 HTTP 方法,默认为 `GET`。 + +### `baseURL` + +`baseURL` 是拼接在 `url` 前面的基础 URL,除非 `url` 是绝对 URL。这对于向同一域名发起请求非常实用,无需在每次请求时重复写域名和 API 版本前缀。 + +### `allowAbsoluteUrls` + +`allowAbsoluteUrls` 决定绝对 URL 是否可以覆盖已配置的 `baseUrl`。设置为 `true`(默认值)时,绝对 `url` 会覆盖 `baseUrl`;设置为 `false` 时,绝对 `url` 始终会拼接在 `baseUrl` 之后。 + +### `transformRequest` + +`transformRequest` 函数允许你在数据发送到服务器之前对其进行修改,仅适用于 `PUT`、`POST`、`PATCH` 和 `DELETE` 请求方法。数组中的最后一个函数必须返回字符串、Buffer、ArrayBuffer、FormData 或 Stream 实例。 + +### `transformResponse` + +`transformResponse` 函数允许你在数据传递给 `then` 或 `catch` 函数之前对响应数据进行修改,函数以响应数据为唯一参数。 + +### `headers` + +`headers` 是随请求发送的 HTTP 请求头,默认将 `Content-Type` 设置为 `application/json`。 + +### `params` + +`params` 是随请求发送的 URL 查询参数,必须是普通对象或 URLSearchParams 对象。如果 `url` 中已包含查询参数,它们将与 `params` 对象合并。 + +### `paramsSerializer` + +`paramsSerializer` 函数允许你在参数发送到服务器之前自定义 `params` 对象的序列化方式,有多个可用选项,详见本页末尾的完整请求配置示例。 + +### `data` + +`data` 是作为请求体发送的数据,可以是字符串、普通对象、Buffer、ArrayBuffer、FormData、Stream 或 URLSearchParams,仅适用于 `PUT`、`POST`、`DELETE` 和 `PATCH` 请求方法。在未设置 `transformRequest` 的情况下,必须是以下类型之一: + +- string、普通对象、ArrayBuffer、ArrayBufferView、URLSearchParams +- 仅浏览器:FormData、File、Blob +- 仅 Node.js:Stream、Buffer、FormData(form-data 包) + +### `timeout` + +`timeout` 是请求超时前等待的毫秒数。如果请求耗时超过 `timeout`,请求将被中止。 + +### `withCredentials` + +`withCredentials` 属性指示跨域 Access-Control 请求是否应携带 cookie、授权请求头或 TLS 客户端证书等凭据。该设置对同源请求无效。 + +### `adapter` + +`adapter` 允许自定义请求处理方式,便于测试。返回一个 Promise 并提供有效的响应,详见[适配器](/pages/advanced/adapters)文档。我们还提供了多个内置适配器,Node.js 默认使用 `http`,浏览器默认使用 `xhr`。内置适配器列表如下: + +- fetch +- http +- xhr + +你也可以传入一个适配器数组,axios 将使用当前环境支持的第一个适配器。 + +### `auth` + +`auth` 表示使用 HTTP Basic 认证,并提供凭据。这将设置 `Authorization` 请求头,覆盖任何通过 `headers` 自定义的 `Authorization` 请求头。请注意,仅 HTTP Basic 认证可通过此参数配置,Bearer 令牌等请改用自定义 `Authorization` 请求头。 + +### `responseType` + +`responseType` 指示服务器响应的数据类型,可以是以下之一: + +- arraybuffer +- document +- json +- text +- stream +- blob(仅浏览器) +- formdata(仅 fetch 适配器) + +### `responseEncoding` + +`responseEncoding` 指示解码响应时使用的编码,支持以下选项: + +- ascii +- ASCII +- ansi +- ANSI +- binary +- BINARY +- base64 +- BASE64 +- base64url +- BASE64URL +- hex +- HEX +- latin1 +- LATIN1 +- ucs-2 +- UCS-2 +- ucs2 +- UCS2 +- utf-8 +- UTF-8 +- utf8 +- UTF8 +- utf16le +- UTF16LE + +::: tip +注意:当 `responseType` 为 `stream` 或客户端请求时,此选项将被忽略 +::: + +### `xsrfCookieName` + +`xsrfCookieName` 是用作 `XSRF` 令牌值的 cookie 名称。 + +### `xsrfHeaderName` + +`xsrfHeaderName` 是用作 `XSRF` 令牌值的请求头名称。 + +### `withXSRFToken` + +`withXSRFToken` 属性指示是否随请求发送 `XSRF` 令牌,仅适用于客户端请求,默认值为 undefined。 + +### `onUploadProgress` + +`onUploadProgress` 函数允许你监听上传进度。 + +### `onDownloadProgress` + +`onDownloadProgress` 函数允许你监听下载进度。 + +### `maxContentLength` + +`maxContentLength` 属性定义服务器在响应中允许接收的最大字节数。 + +### `maxBodyLength` + +`maxBodyLength` 属性定义服务器在请求中允许接收的最大字节数。 + +### `validateStatus` + +`validateStatus` 函数允许你覆盖默认的状态码验证逻辑。默认情况下,axios 会在状态码不在 200-299 范围内时拒绝 Promise。你可以提供自定义的 `validateStatus` 函数来覆盖此行为,该函数应在状态码在你希望接受的范围内时返回 `true`。 + +### `maxRedirects` + +`maxRedirects` 属性定义最大重定向次数,设置为 0 时不跟随任何重定向。 + +### `beforeRedirect` + +`beforeRedirect` 函数允许你在请求重定向前对其进行修改,可用于调整重定向时的请求选项、检查最新的响应头或通过抛出错误来取消请求。当 `maxRedirects` 设置为 0 时,不会使用 `beforeRedirect`。 + +### `socketPath` + +`socketPath` 属性定义用于替代 TCP 连接的 UNIX 套接字路径,例如 `/var/run/docker.sock`,用于向 Docker 守护进程发送请求。`socketPath` 和 `proxy` 只能指定其中一个,如果两者都指定,则使用 `socketPath`。 + +### `transport` + +`transport` 属性定义请求使用的传输方式,适用于通过不同协议(如 `http2`)发起请求的场景。 + +### `httpAgent` 和 `httpsAgent` + +`httpAgent` 和 `httpsAgent` 分别定义在 Node.js 中执行 HTTP 和 HTTPS 请求时使用的自定义代理,可用于添加 `keepAlive` 等默认未启用的选项。 + +### `proxy` + +`proxy` 定义代理服务器的主机名、端口和协议,也可以通过常规的 `http_proxy` 和 `https_proxy` 环境变量来定义代理。 + +如果你使用环境变量配置代理,还可以定义 `no_proxy` 环境变量,以逗号分隔的方式列出不需要代理的域名。 + +设置为 `false` 可禁用代理,忽略环境变量。`auth` 表示使用 HTTP Basic 认证连接代理并提供凭据,这将设置 `Proxy-Authorization` 请求头,覆盖任何通过 `headers` 自定义的 `Proxy-Authorization` 请求头。如果代理服务器使用 HTTPS,则必须将协议设置为 `https`。 + +```js +proxy: { + protocol: "https", + host: "127.0.0.1", + hostname: "localhost", // 如果同时定义了 "host" 和 "hostname",则优先使用 "hostname" + port: 9000, + auth: { + username: "mikeymike", + password: "rapunz3l" + } +}, +``` + +### `cancelToken` + +`cancelToken` 属性允许你创建一个取消令牌,用于取消请求。详见[取消请求](/pages/advanced/cancellation)文档。 + +### `signal` + +`signal` 属性允许你向请求传入一个 `AbortSignal` 实例,从而通过 `AbortController` API 取消请求。 + +### `decompress` + +`decompress` 属性指示是否自动解压响应数据,默认值为 `true`。 + +### `insecureHTTPParser` + +指示是否使用接受无效 HTTP 请求头的不安全 HTTP 解析器,可用于与不符合规范的 HTTP 实现互通。不建议使用不安全解析器。 + +请注意,`insecureHTTPParser` 选项仅在 Node.js 12.10.0 及更高版本中可用。请阅读 [Node.js 文档](https://nodejs.org/en/blog/vulnerability/february-2020-security-releases/#strict-http-header-parsing-none)以获取更多信息。完整选项列表见[此处](https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_url_options_callback)。 + +### `transitional` + +`transitional` 属性允许你启用或禁用某些过渡性功能,可用选项如下: + +- `silentJSONParsing`:设置为 `true` 时,遇到无效 JSON 响应时 axios 不会输出警告,返回值设为 null。适用于返回无效 JSON 的 API。 +- `forcedJSONParsing`:强制 axios 将响应解析为 JSON,即使响应不是有效的 JSON。适用于返回无效 JSON 的 API。 +- `clarifyTimeoutError`:在请求超时时提供更清晰的错误信息,适用于调试超时问题。 +- `legacyInterceptorReqResOrdering`:设置为 true 时使用旧版拦截器请求/响应排序。 + +### `env` + +`env` 属性允许你设置一些配置选项,例如用于自动将数据序列化为 FormData 对象的 FormData 类。 + +- FormData: window?.FormData || global?.FormData + +### `formSerializer` + +`formSerializer` 函数允许你在数据发送到服务器之前自定义 `data` 对象的序列化方式,有多个可用选项,详见本页末尾的完整请求配置示例。 + +### `maxRate` + +`maxRate` 属性定义上传和/或下载的最大**带宽**(字节/秒)。接受单个数字(同时适用于两个方向)或两元素数组 `[uploadRate, downloadRate]`,每个元素为字节/秒限制。例如,`100 * 1024` 表示 100 KB/s。详见[速率限制](/pages/advanced/rate-limiting)中的示例。 + +## 完整请求配置示例 + +```js +{ + url: "/posts", + method: "get", + baseURL: "https://jsonplaceholder.typicode.com", + allowAbsoluteUrls: true, + transformRequest: [function (data, headers) { + return data; + }], + transformResponse: [function (data) { + return data; + }], + headers: {"X-Requested-With": "XMLHttpRequest"}, + params: { + postId: 5 + }, + paramsSerializer: { + // 自定义编码函数,以迭代方式逐个序列化键值对。 + encode?: (param: string): string => { /* 在此执行自定义操作并返回转换后的字符串 */ }, + + // 对整个参数进行自定义序列化的函数,允许用户模拟 1.x 之前的行为。 + serialize?: (params: Record, options?: ParamsSerializerOptions ), + + // 配置数组索引在参数中的格式。 + // 三种可用选项: + // (1) indexes: null(不添加方括号) + // (2)(默认)indexes: false(添加空方括号) + // (3) indexes: true(添加带索引的方括号) + indexes: false + + }, + data: { + firstName: "Fred" + }, + // 另一种将数据发送到请求体的语法,仅适用于 POST 方法,只发送值,不发送键 + data: "Country=Brasil&City=Belo Horizonte", + timeout: 1000, + withCredentials: false, + adapter: function (config) { + // 在此执行自定义逻辑 + }, + adapter: "xhr", + auth: { + username: "janedoe", + password: "s00pers3cret" + }, + responseType: "json", + responseEncoding: "utf8", + xsrfCookieName: "XSRF-TOKEN", + xsrfHeaderName: "X-XSRF-TOKEN", + withXSRFToken: boolean | undefined | ((config: InternalAxiosRequestConfig) => boolean | undefined), + onUploadProgress: function ({loaded, total, progress, bytes, estimated, rate, upload = true}) { + // 在此处理 axios 进度事件 + }, + onDownloadProgress: function ({loaded, total, progress, bytes, estimated, rate, download = true}) { + // 在此处理 axios 进度事件 + }, + maxContentLength: 2000, + maxBodyLength: 2000, + validateStatus: function (status) { + return status >= 200 && status < 300; + }, + maxRedirects: 21, + beforeRedirect: (options, { headers }) => { + if (options.hostname === "typicode.com") { + options.auth = "user:password"; + } + }, + socketPath: null, + transport: undefined, + httpAgent: new http.Agent({ keepAlive: true }), + httpsAgent: new https.Agent({ keepAlive: true }), + proxy: { + protocol: "https", + host: "127.0.0.1", + // hostname: "127.0.0.1" // 如果同时定义了 "host" 和 "hostname",则优先使用 "hostname" + port: 9000, + auth: { + username: "mikeymike", + password: "rapunz3l" + } + }, + cancelToken: new CancelToken(function (cancel) { + cancel("Operation has been canceled."); + }), + signal: new AbortController().signal, + decompress: true, + insecureHTTPParser: undefined, + transitional: { + silentJSONParsing: true, + forcedJSONParsing: true, + clarifyTimeoutError: false, + legacyInterceptorReqResOrdering: true, + }, + env: { + FormData: window?.FormData || global?.FormData + }, + formSerializer: { + // 自定义访问者函数,用于序列化表单值 + visitor: (value, key, path, helpers) => {}; + + // 使用点号表示法代替方括号格式 + dots: boolean; + + // 在参数键中保留特殊结尾(如 {}) + metaTokens: boolean; + + // 使用数组索引格式: + // null - 不添加方括号 + // false - 添加空方括号 + // true - 添加带索引的方括号 + indexes: boolean; + }, + maxRate: [ + 100 * 1024, // 上传限制 100KB/s + 100 * 1024 // 下载限制 100KB/s + ] +} +``` diff --git a/docs/zh/pages/advanced/request-method-aliases.md b/docs/zh/pages/advanced/request-method-aliases.md new file mode 100644 index 0000000..427a6a7 --- /dev/null +++ b/docs/zh/pages/advanced/request-method-aliases.md @@ -0,0 +1,130 @@ +# 请求别名 + +axios 提供了一组发起 HTTP 请求的别名方法,这些别名是 `request` 方法的快捷方式,设计简洁、使用方便。 + +axios 尽量遵循 RFC 7231 和 RFC 5789 规范,别名方法与这些规范中定义的 HTTP 方法保持一致。 + +### `axios` + +axios 可以通过仅传入配置对象来发起 HTTP 请求,完整的配置对象文档见[此处](/pages/advanced/request-config)。 + +```ts +axios(url: string | AxiosRequestConfig, config?: AxiosRequestConfig); +``` + +## 方法别名 + +以下是可用的请求别名方法: + +### `request` + +`request` 方法是发起 HTTP 请求的主方法,接受一个配置对象并返回解析为响应对象的 Promise,可用于发起任意类型的 HTTP 请求。 + +```ts +axios.request(config: AxiosRequestConfig): AxiosResponse; +``` + +### `get` + +`get` 方法用于发起 GET 请求,接受 URL 和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.get(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `delete` + +`delete` 方法用于发起 DELETE 请求,接受 URL 和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.delete(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `head` + +`head` 方法用于发起 HEAD 请求,接受 URL 和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.head(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `options` + +`options` 方法用于发起 OPTIONS 请求,接受 URL 和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.options(url: string, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `post` + +`post` 方法用于发起 POST 请求,接受 URL、可选数据对象和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.post(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `put` + +`put` 方法用于发起 PUT 请求,接受 URL、可选数据对象和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.put(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +### `patch` + +`patch` 方法用于发起 PATCH 请求,接受 URL、可选数据对象和可选配置对象,返回解析为响应对象的 Promise。 + +```ts +axios.patch(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +## 表单数据快捷方法 + +这些方法与上述对应方法等价,但会预设 `Content-Type` 为 `multipart/form-data`,是上传文件或提交 HTML 表单的推荐方式。 + +### `postForm` + +```ts +axios.postForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// 从浏览器文件输入框上传文件 +await axios.postForm("/api/upload", { + file: document.querySelector("#fileInput").files[0], + description: "Profile photo", +}); +``` + +### `putForm` + +```ts +axios.putForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// 用表单数据替换资源 +await axios.putForm("/api/users/1/avatar", { + avatar: document.querySelector("#avatarInput").files[0], +}); +``` + +### `patchForm` + +```ts +axios.patchForm(url: string, data?: D, config?: AxiosRequestConfig): AxiosResponse; +``` + +```js +// 使用表单数据更新特定字段 +await axios.patchForm("/api/users/1", { + displayName: "New Name", + avatar: document.querySelector("#avatarInput").files[0], +}); +``` + +::: tip +`postForm`、`putForm` 和 `patchForm` 接受与基础方法相同的所有数据类型——普通对象、`FormData`、`FileList` 以及 `HTMLFormElement`。更多示例请参阅[文件上传](/pages/advanced/file-posting)。 +::: diff --git a/docs/zh/pages/advanced/response-schema.md b/docs/zh/pages/advanced/response-schema.md new file mode 100644 index 0000000..a5356c5 --- /dev/null +++ b/docs/zh/pages/advanced/response-schema.md @@ -0,0 +1,63 @@ +# 响应结构 + +每个 axios 请求都会解析为具有以下结构的响应对象,在浏览器和 Node.js 环境中保持一致。 + +```js +{ + // 服务器提供的响应数据。 + // 使用 `transformResponse` 时,这将是最后一次转换的结果。 + data: {}, + + // 服务器响应的 HTTP 状态码(如 200、404、500)。 + status: 200, + + // 与状态码对应的 HTTP 状态消息(如 "OK"、"Not Found")。 + statusText: "OK", + + // 服务器发送的响应头。 + // 响应头名称均为小写,可通过方括号或点号表示法访问。 + headers: {}, + + // 本次请求使用的 axios 配置,包括 baseURL、headers、timeout、params 及其他选项。 + config: {}, + + // 底层请求对象。 + // 在 Node.js 中:最后一个 `http.ClientRequest` 实例(经过任何重定向后)。 + // 在浏览器中:`XMLHttpRequest` 实例。 + request: {}, +} +``` + +## 访问响应字段 + +实际使用中,你通常只需要解构出所需的部分: + +```js +const { data, status, headers } = await axios.get("/api/users/1"); + +console.log(status); // 200 +console.log(headers["content-type"]); // "application/json; charset=utf-8" +console.log(data); // { id: 1, name: "Jay", email: "jay@example.com" } +``` + +## 检查状态码 + +axios 默认对任何 2xx 响应 resolve Promise,对超出该范围的响应 reject Promise。可以通过 `validateStatus` 配置选项自定义此行为: + +```js +const response = await axios.get("/api/resource", { + validateStatus: (status) => status < 500, // 500 以下的所有状态码均 resolve +}); +``` + +## 访问响应头 + +无论服务器如何发送,所有响应头名称均为小写: + +```js +const response = await axios.get("/api/resource"); + +// 以下两种写法等价 +const contentType = response.headers["content-type"]; +const contentType2 = response.headers.get("content-type"); +``` diff --git a/docs/zh/pages/advanced/retry.md b/docs/zh/pages/advanced/retry.md new file mode 100644 index 0000000..e47533e --- /dev/null +++ b/docs/zh/pages/advanced/retry.md @@ -0,0 +1,130 @@ +# 重试与错误恢复 + +网络请求可能因瞬时原因而失败——服务器抖动、短暂的网络中断或限流响应。在拦截器中实现重试策略,可以让你透明地处理这些失败,无需在业务代码中添加繁琐的重试逻辑。 + +## 基本重试(使用响应拦截器) + +最简单的方式是捕获特定错误状态码,并在有限次数内立即重新发送原始请求: + +```js +import axios from "axios"; + +const api = axios.create({ baseURL: "https://api.example.com" }); + +const MAX_RETRIES = 3; + +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + // 仅在网络错误或 5xx 服务器错误时重试 + const shouldRetry = + !error.response || (error.response.status >= 500 && error.response.status < 600); + + if (!shouldRetry) { + return Promise.reject(error); + } + + config._retryCount = config._retryCount ?? 0; + + if (config._retryCount >= MAX_RETRIES) { + return Promise.reject(error); + } + + config._retryCount += 1; + return api(config); + } +); +``` + +## 指数退避 + +失败后立即重试可能会使本已压力过大的服务器雪上加霜。指数退避策略会在每次重试之间等待逐渐增长的时间: + +```js +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + const shouldRetry = + !error.response || (error.response.status >= 500 && error.response.status < 600); + + if (!shouldRetry) return Promise.reject(error); + + config._retryCount = config._retryCount ?? 0; + + if (config._retryCount >= 3) return Promise.reject(error); + + config._retryCount += 1; + + // 每次重试前分别等待 200ms、400ms、800ms…… + const backoff = 100 * 2 ** config._retryCount; + await delay(backoff); + + return api(config); + } +); +``` + +## 响应 429(限流)时使用 Retry-After + +当服务器返回 `429 Too Many Requests` 时,通常会在响应头中包含 `Retry-After` 字段,明确告知你需要等待多长时间: + +```js +api.interceptors.response.use( + (response) => response, + async (error) => { + const config = error.config; + + if (error.response?.status !== 429) return Promise.reject(error); + + config._retryCount = config._retryCount ?? 0; + if (config._retryCount >= 3) return Promise.reject(error); + + config._retryCount += 1; + + const retryAfterHeader = error.response.headers["retry-after"]; + const waitMs = retryAfterHeader + ? parseFloat(retryAfterHeader) * 1000 // 请求头单位为秒 + : 1000; // 默认等待 1 秒 + + await new Promise((resolve) => setTimeout(resolve, waitMs)); + return api(config); + } +); +``` + +## 针对特定请求禁用重试 + +如果某些请求不应被重试(例如不幂等的变更操作,不希望重复执行),可以在请求配置中添加一个标志: + +```js +// 在重试逻辑之前,在拦截器中添加以下判断: +if (config._noRetry) return Promise.reject(error); + +// 然后在特定调用中禁用重试: +await api.post("/payments/charge", body, { _noRetry: true }); +``` + +## 结合重试与取消 + +使用 `AbortController` 可以取消正在等待退避延迟的请求: + +```js +const controller = new AbortController(); + +try { + await api.get("/api/data", { signal: controller.signal }); +} catch (error) { + if (axios.isCancel(error)) { + console.log("Request aborted by user"); + } +} + +// 从其他地方取消请求(以及任何待处理的重试延迟): +controller.abort(); +``` diff --git a/docs/zh/pages/advanced/testing.md b/docs/zh/pages/advanced/testing.md new file mode 100644 index 0000000..6802509 --- /dev/null +++ b/docs/zh/pages/advanced/testing.md @@ -0,0 +1,145 @@ +# 测试 + +测试使用 axios 发起 HTTP 请求的代码非常简单。推荐的方式是对 axios 本身进行 mock,让测试在不触及真实网络的情况下运行,从而完全控制代码收到的响应内容。 + +## 使用 Vitest 或 Jest 进行 Mock + +Vitest 和 Jest 都支持通过 `vi.mock` / `jest.mock` 进行模块级 mock。你可以 mock 整个 axios 模块,并控制每个方法的返回值: + +```js +// user-service.js +import axios from "axios"; + +export async function getUser(id) { + const { data } = await axios.get(`/api/users/${id}`); + return data; +} +``` + +```js +// user-service.test.js +import { describe, it, expect, vi } from "vitest"; +import axios from "axios"; +import { getUser } from "./user-service"; + +vi.mock("axios"); + +describe("getUser", () => { + it("returns user data on success", async () => { + const mockUser = { id: 1, name: "Jay" }; + + // 让 axios.get 返回我们的假响应 + axios.get.mockResolvedValueOnce({ data: mockUser }); + + const result = await getUser(1); + + expect(result).toEqual(mockUser); + expect(axios.get).toHaveBeenCalledWith("/api/users/1"); + }); + + it("throws when the request fails", async () => { + axios.get.mockRejectedValueOnce(new Error("Network error")); + + await expect(getUser(1)).rejects.toThrow("Network error"); + }); +}); +``` + +## Mock AxiosError + +要测试检查 `error.response` 的错误处理路径,可以直接创建一个 `AxiosError` 实例: + +```js +import axios, { AxiosError } from "axios"; +import { vi } from "vitest"; + +const mockError = new AxiosError( + "Not Found", + "ERR_BAD_REQUEST", + {}, // config + {}, // request + { // response + status: 404, + statusText: "Not Found", + data: { message: "User not found" }, + headers: {}, + config: {}, + } +); + +axios.get.mockRejectedValueOnce(mockError); +``` + +## 使用 axios-mock-adapter + +[axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter) 是一个在 axios 实例上安装自定义适配器的库,在适配器层面拦截请求。这意味着你的拦截器仍然会执行,因此更适合集成测试。 + +```bash +npm install --save-dev axios-mock-adapter +``` + +```js +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; + +const mock = new MockAdapter(axios); + +// Mock GET 请求 +mock.onGet("/api/users/1").reply(200, { id: 1, name: "Jay" }); + +// Mock POST 请求 +mock.onPost("/api/users").reply(201, { id: 2, name: "New User" }); + +// Mock 网络错误 +mock.onGet("/api/failing").networkError(); + +// Mock 超时 +mock.onGet("/api/slow").timeout(); +``` + +在每个测试之间重置 mock: + +```js +afterEach(() => { + mock.reset(); // 清除所有已注册的处理器 +}); +``` + +## 测试拦截器 + +要单独测试拦截器,在测试中创建一个全新的 axios 实例: + +```js +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; + +describe("auth interceptor", () => { + it("attaches a Bearer token to every request", async () => { + const instance = axios.create(); + const mock = new MockAdapter(instance); + + // 添加你的拦截器 + instance.interceptors.request.use((config) => { + config.headers.set("Authorization", "Bearer test-token"); + return config; + }); + + // 通过检查 mock 收到的内容来捕获请求配置 + let capturedConfig; + mock.onGet("/api/data").reply((config) => { + capturedConfig = config; + return [200, {}]; + }); + + await instance.get("/api/data"); + + expect(capturedConfig.headers["Authorization"]).toBe("Bearer test-token"); + }); +}); +``` + +## 最佳实践 + +- 始终在模块级别进行 mock(或使用 `MockAdapter`)——避免在共享实例的单个方法上进行 mock,因为状态可能在测试之间泄漏。 +- 优先使用 `mockResolvedValueOnce` / `mockRejectedValueOnce`,而不是 `mockResolvedValue`,以确保测试相互隔离,互不影响。 +- 测试重试逻辑时,使用 `MockAdapter`,以便被测拦截器在每次重试时都能真正执行。 diff --git a/docs/zh/pages/advanced/type-script.md b/docs/zh/pages/advanced/type-script.md new file mode 100644 index 0000000..7154d57 --- /dev/null +++ b/docs/zh/pages/advanced/type-script.md @@ -0,0 +1,8 @@ +# TypeScript + +`axios` 支持 TypeScript 类型定义,这些定义通过 npm 包中的 `index.d.ts` 文件提供。由于 axios 同时以 ESM 默认导出和 CJS `module.exports` 两种方式发布,存在以下注意事项: + +- 推荐使用 `"moduleResolution": "node16"`(由 `"module": "node16"` 隐式指定),需要 TypeScript 4.7 或更高版本。 +- 如果你使用 ESM,现有配置应该没有问题。 +- 如果你将 TypeScript 编译为 CJS 且无法使用 `"moduleResolution": "node16"`,则必须启用 `esModuleInterop`。 +- 如果你使用 TypeScript 对 CJS JavaScript 代码进行类型检查,则只能使用 `"moduleResolution": "node16"`。 diff --git a/docs/zh/pages/advanced/x-www-form-urlencoded-format.md b/docs/zh/pages/advanced/x-www-form-urlencoded-format.md new file mode 100644 index 0000000..1810cc2 --- /dev/null +++ b/docs/zh/pages/advanced/x-www-form-urlencoded-format.md @@ -0,0 +1,78 @@ +# x-www-form-urlencoded 格式 + +## URLSearchParams + +默认情况下,axios 会将 JavaScript 对象序列化为 `JSON`。如果需要以 [`application/x-www-form-urlencoded` 格式](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)发送数据,可以使用 [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) API,绝大多数浏览器[已支持](http://www.caniuse.com/#feat=urlsearchparams)该 API,Node.js 从 v10(2018 年发布)开始也[支持](https://nodejs.org/api/url.html#url_class_urlsearchparams)。 + +```js +const params = new URLSearchParams({ foo: 'bar' }); +params.append('extraparam', 'value'); +axios.post('/foo', params); +``` + +## 查询字符串 + +对于不支持 `URLSearchParams` 的旧版浏览器或环境,可以使用 [`qs`](https://github.com/ljharb/qs) 库将对象序列化为 `application/x-www-form-urlencoded` 格式。 + +```js +const qs = require('qs'); +axios.post('/foo', qs.stringify({ bar: 123 })); +``` + +在非常旧的 Node.js 版本中,可以使用 Node.js 内置的 `querystring` 模块。注意该模块在 Node.js v16 中已废弃——新代码请优先使用 `URLSearchParams` 或 `qs`。 + +```js +const querystring = require('querystring'); +axios.post('https://something.com/', querystring.stringify({ foo: 'bar' })); +``` + +## 自动序列化为 URLSearchParams + +从 v0.21.0 起,如果将 `Content-Type` 请求头设置为 `application/x-www-form-urlencoded`,axios 会自动将 JavaScript 对象序列化为 `URLSearchParams`。这意味着你可以直接将 JavaScript 对象传入 axios 请求配置的 `data` 属性。例如,向 `POST` 请求传递数据时: + +```js +const data = { + x: 1, + arr: [1, 2, 3], + arr2: [1, [2], 3], + users: [ + { name: 'Peter', surname: 'Griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], +}; + +await axios.postForm('https://postman-echo.com/post', data, { + headers: { 'content-type': 'application/x-www-form-urlencoded' }, +}); +``` + +`data` 对象将被自动序列化为 `URLSearchParams` 并以 `application/x-www-form-urlencoded` 格式发送。服务器将收到以下数据: + +```json +{ + "x": "1", + "arr[]": ["1", "2", "3"], + "arr2[0]": "1", + "arr2[1][0]": "2", + "arr2[2]": "3", + "users[0][name]": "Peter", + "users[0][surname]": "Griffin", + "users[1][name]": "Thomas", + "users[1][surname]": "Anderson" +} +``` + +如果你的后端 body 解析器(如 `express.js` 的 `body-parser`)支持嵌套对象解码,服务器端将自动还原为相同的对象结构: + +```js +var app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); // 支持编码后的请求体 + +app.post('/', function (req, res, next) { + // 将请求体以 JSON 格式回传 + res.send(JSON.stringify(req.body)); +}); + +server = app.listen(3000); +``` diff --git a/docs/zh/pages/getting-started/examples/commonjs.md b/docs/zh/pages/getting-started/examples/commonjs.md new file mode 100644 index 0000000..79a7941 --- /dev/null +++ b/docs/zh/pages/getting-started/examples/commonjs.md @@ -0,0 +1,226 @@ +# JavaScript 示例 + +## 导入库 + +在 CommonJS 环境中,可以使用 `require` 函数导入库;如果使用 Webpack 或 Rollup 等打包工具,则可以使用 `import` 语句。 + +#### 不使用打包工具 + +```js +const axios = require("axios"); +``` + +#### 使用打包工具(webpack、rollup、vite 等) + +```js +import axios from "axios"; +``` + +## 使用 then/catch/finally + +axios 的核心返回的是一个 Promise,你可以使用 `then`、`catch` 和 `finally` 回调来处理响应数据、错误以及请求完成的逻辑。 + +### GET 请求 + +```js +axios + .get("https://jsonplaceholder.typicode.com/posts", { + params: { + postId: 5, + }, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### POST 请求 + +```js +axios + .post("https://jsonplaceholder.typicode.com/posts", { + title: "foo", + body: "bar", + userId: 1, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### PUT 请求 + +```js +axios + .put("https://jsonplaceholder.typicode.com/posts/1", { + title: "foo", + body: "bar", + userId: 1, + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### PATCH 请求 + +```js +axios + .patch("https://jsonplaceholder.typicode.com/posts/1", { + title: "foo", + }) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +### DELETE 请求 + +```js +axios + .delete("https://jsonplaceholder.typicode.com/posts/1") + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + console.log("Request completed"); + }); +``` + +## 使用 async/await + +处理 Promise 的另一种方式是使用 `async` 和 `await`,配合 try/catch/finally 块来处理错误和完成逻辑。这种写法可以让代码更加清晰易读,同时有效避免所谓的"回调地狱"。 + +::: tip +注意:async/await 属于 ECMAScript 2017 规范,Internet Explorer 及部分旧版浏览器不支持,使用时请注意兼容性。 +::: + +### GET 请求 + +```js +const getPosts = async () => { + try { + const response = await axios.get( + "https://jsonplaceholder.typicode.com/posts", + { + params: { + postId: 5, + }, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### POST 请求 + +```js +const createPost = async () => { + try { + const response = await axios.post( + "https://jsonplaceholder.typicode.com/posts", + { + title: "foo", + body: "bar", + userId: 1, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### PUT 请求 + +```js +const updatePost = async () => { + try { + const response = await axios.put( + "https://jsonplaceholder.typicode.com/posts/1", + { + title: "foo", + body: "bar", + userId: 1, + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### PATCH 请求 + +```js +const updatePost = async () => { + try { + const response = await axios.patch( + "https://jsonplaceholder.typicode.com/posts/1", + { + title: "foo", + } + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` + +### DELETE 请求 + +```js +const deletePost = async () => { + try { + const response = await axios.delete( + "https://jsonplaceholder.typicode.com/posts/1" + ); + console.log(response.data); + } catch (error) { + console.error(error); + } finally { + console.log("Request completed"); + } +}; +``` diff --git a/docs/zh/pages/getting-started/examples/typescript.md b/docs/zh/pages/getting-started/examples/typescript.md new file mode 100644 index 0000000..d77a056 --- /dev/null +++ b/docs/zh/pages/getting-started/examples/typescript.md @@ -0,0 +1,139 @@ +# TypeScript 示例 + +## 导入类型 + +axios 内置了 TypeScript 类型定义,你可以直接从 `"axios"` 导入所需的类型: + +```ts +import axios from "axios"; +import type { AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"; +``` + +## 为请求标注类型 + +在响应上使用泛型参数,告知 TypeScript 数据的具体结构: + +```ts +import axios from "axios"; + +type Post = { + userId: number; + id: number; + title: string; + body: string; +}; + +const response = await axios.get("https://jsonplaceholder.typicode.com/posts/1"); + +console.log(response.data.title); // TypeScript 知道这是一个字符串 +``` + +## 为函数标注类型 + +将请求封装在函数中,并明确声明返回类型,以获得最佳的类型安全性: + +```ts +import axios, { AxiosResponse } from "axios"; + +type Post = { + userId: number; + id: number; + title: string; + body: string; +}; + +const getPost = async (id: number): Promise => { + const response = await axios.get( + `https://jsonplaceholder.typicode.com/posts/${id}` + ); + return response.data; +}; +``` + +## 为 POST 请求标注类型 + +你可以同时为请求体和预期响应标注类型: + +```ts +type CreatePostBody = { + title: string; + body: string; + userId: number; +}; + +type CreatePostResponse = CreatePostBody & { id: number }; + +const createPost = async (data: CreatePostBody): Promise => { + const response = await axios.post( + "https://jsonplaceholder.typicode.com/posts", + data + ); + return response.data; +}; +``` + +## 带类型的 axios 实例 + +创建一个带类型的实例,将 baseURL 和请求头内置其中: + +```ts +import axios from "axios"; +import type { AxiosInstance } from "axios"; + +const api: AxiosInstance = axios.create({ + baseURL: "https://api.example.com", + timeout: 5000, +}); +``` + +## 带类型的拦截器 + +在 v1.x 中,请求拦截器应使用 `InternalAxiosRequestConfig`(而非 `AxiosRequestConfig`): + +```ts +import axios from "axios"; +import type { InternalAxiosRequestConfig, AxiosResponse } from "axios"; + +api.interceptors.request.use((config: InternalAxiosRequestConfig) => { + config.headers.set("Authorization", `Bearer ${getToken()}`); + return config; +}); + +api.interceptors.response.use( + (response: AxiosResponse) => response, + (error) => Promise.reject(error) +); +``` + +## 为错误标注类型 + +使用 `axios.isAxiosError()` 对捕获的错误进行类型收窄: + +```ts +import axios, { AxiosError } from "axios"; + +type ApiError = { + message: string; + code: number; +}; + +try { + await axios.get("/api/protected-resource"); +} catch (error) { + if (axios.isAxiosError(error)) { + // error.response?.data 的类型为 ApiError + console.error(error.response?.data.message); + console.error(error.response?.status); + } else { + throw error; + } +} +``` + +## TypeScript 配置说明 + +由于 axios 同时发布了 ESM 和 CJS 版本,根据你的配置不同,可能存在以下注意事项: + +- 推荐设置为 `"moduleResolution": "node16"`(由 `"module": "node16"` 隐式指定),需要 TypeScript 4.7 或更高版本。 +- 如果你将 TypeScript 编译为 CJS 且无法使用 `"moduleResolution": "node16"`,请启用 `"esModuleInterop": true`。 +- 如果你使用 TypeScript 对 CJS JavaScript 代码进行类型检查,则只能使用 `"moduleResolution": "node16"`。 diff --git a/docs/zh/pages/getting-started/features.md b/docs/zh/pages/getting-started/features.md new file mode 100644 index 0000000..6390133 --- /dev/null +++ b/docs/zh/pages/getting-started/features.md @@ -0,0 +1,42 @@ +# 功能特性 + +axios 是一个功能强大的 HTTP 客户端,提供简单易用的 API 来发起 HTTP 请求。它支持所有主流浏览器,在 JavaScript 社区中被广泛使用。以下是 axios 的核心特性,这些特性使其成为你下一个项目的优选方案。 + +## 同构(Isomorphic) + +axios 是一个通用 HTTP 客户端,可在浏览器和 Node.js 中同时使用。这意味着你既可以在前端代码中发起 API 请求,也可以在后端代码中使用 axios,非常适合构建渐进式 Web 应用、单页应用以及服务端渲染应用。 + +对于同时负责前后端开发的团队,axios 也是绝佳选择。统一使用 axios 发起 HTTP 请求,可以降低代码库的复杂度,保持前后端 API 的一致性。 + +## Fetch 支持 + +axios 对 Fetch API 提供了一流的支持。Fetch API 是 XHR API 的现代替代方案,可通过配置选项启用该适配器。XHR 适配器和 Fetch 适配器使用完全相同的 API,因此无需修改现有代码即可平滑迁移到 Fetch API。 + +## 浏览器支持 + +axios 支持所有主流浏览器及部分较旧的浏览器,包括 Chrome、Firefox、Safari 和 Edge,是构建需要兼容多种浏览器的 Web 应用的理想选择。 + +## Node.js 支持 + +axios 同样支持多个 Node.js 版本,兼容性经过测试,最早可追溯至 v12.x,在无法或不便升级到最新 Node.js 版本的环境中同样可以放心使用。 + +此外,axios 还有针对 Bun 和 Deno 的冒烟测试,用于验证关键的运行时行为,增强跨运行时兼容性的可信度。 + +## 其他特性 + +- 支持 Promise API +- 拦截请求和响应 +- 转换请求和响应数据 +- AbortController 支持 +- 超时设置 +- 支持嵌套参数的查询字符串序列化 +- 自动将请求体序列化为: + - JSON(application/json) + - Multipart / FormData(multipart/form-data) + - URL 编码表单(application/x-www-form-urlencoded) +- 将 HTML 表单数据以 JSON 格式发送 +- 自动处理响应中的 JSON 数据 +- 支持浏览器和 Node.js 的进度捕获,并提供额外信息(传输速率、剩余时间) +- 支持在 Node.js 中设置带宽限制 +- 兼容规范的 FormData 和 Blob(包括 Node.js 环境) +- 客户端 XSRF 防护支持 diff --git a/docs/zh/pages/getting-started/first-steps.md b/docs/zh/pages/getting-started/first-steps.md new file mode 100644 index 0000000..af53a55 --- /dev/null +++ b/docs/zh/pages/getting-started/first-steps.md @@ -0,0 +1,73 @@ +# 入门指南 + +欢迎阅读 axios 文档!本指南将帮助你快速上手 axios,并发起第一个 API 请求。如果你是 axios 新手,建议从这里开始。 + +## 安装 + +你可以通过多种方式在项目中使用 axios。最常见的方式是通过 npm 安装,也支持 jsDelivr、unpkg 等 CDN。 + +#### 使用 npm + +```bash +npm install axios +``` + +#### 使用 pnpm + +```bash +pnpm install axios +``` + +#### 使用 yarn + +```bash +yarn add axios +``` + +#### 使用 bun + +```bash +bun add axios +``` + +#### 使用 deno + +```bash +deno install npm:axios +``` + +#### 使用 jsDelivr + +使用 jsDelivr 时,建议使用压缩版本并固定版本号,以避免意外更新。如需使用最新版本,可以去掉版本号,但强烈不建议在生产环境这样做,因为可能导致应用出现意外变化。 + +```html + +``` + +#### 使用 unpkg + +使用 unpkg 时,建议使用压缩版本并固定版本号,以避免意外更新。如需使用最新版本,可以去掉版本号,但强烈不建议在生产环境这样做,因为可能导致应用出现意外变化。 + +```html + +``` + +## 发起第一个请求 + +使用 axios 发起请求最少只需要两行代码。你可以通过提供 URL 和请求方法向任意 API 发送请求。例如,向 JSONPlaceholder API 发起一个 GET 请求: + +```js +import axios from "axios"; + +const response = await axios.get( + "https://jsonplaceholder.typicode.com/posts/1" +); + +console.log(response.data); +``` + +axios 提供了简洁的请求 API。你可以使用 `axios.get` 发起 GET 请求,使用 `axios.post` 发起 POST 请求,依此类推。也可以使用 `axios.request` 方法发起任意类型的请求。 + +## 下一步 + +现在你已经用 axios 完成了第一个请求,可以继续探索 axios 文档的其余内容。了解更多关于发起请求、处理响应以及在项目中使用 axios 的知识,请查阅文档其他章节。 diff --git a/docs/zh/pages/getting-started/upgrade-guide.md b/docs/zh/pages/getting-started/upgrade-guide.md new file mode 100644 index 0000000..cae6d01 --- /dev/null +++ b/docs/zh/pages/getting-started/upgrade-guide.md @@ -0,0 +1,92 @@ +# 升级指南 + +本指南旨在帮助你将项目从旧版本升级到新版本。建议阅读每个主要版本的发布说明,其中可能包含关于破坏性变更的重要信息。 + +## 从 v0.x 升级到 v1.x + +### import 语句变更 + +在 v1.x 中,import 语句改为使用 `default` 导出,你需要将 import 语句更新为如下形式: + +```diff +- import { axios } from "axios"; ++ import axios from "axios"; +``` + +### 拦截器系统变更 + +在 v1.x 中,你需要使用 `InternalAxiosRequestConfig` 类型来为 `request` 拦截器的 `config` 参数标注类型。这是因为该参数现在的类型是 `InternalAxiosRequestConfig`,而不再是公开的 `AxiosRequestConfig`。 + +```diff +- axios.interceptors.request.use((config: AxiosRequestConfig) => { ++ axios.interceptors.request.use((config: InternalAxiosRequestConfig) => { + return config; + }); +``` + +### 请求头结构变更 + +在 v1.x 中,请求头的结构已去除 `common` 属性,你需要按如下方式更新相关代码: + +```diff +- if (request.headers?.common?.Authorization) { +- request.headers.common.Authorization = ... ++ if (request.headers?.Authorization) { ++ request.headers.Authorization = ... +``` + +原本位于 `common`、`get`、`post` 等属性下的默认请求头,现在直接设置在 `axios.defaults.headers` 上: + +```diff +- axios.defaults.headers.common["Accept"] = "application/json"; ++ axios.defaults.headers["Accept"] = "application/json"; +``` + +### Multipart 表单数据 + +如果请求包含 `FormData` 数据,`Content-Type: multipart/form-data` 请求头现在会被自动设置,请移除手动设置以避免重复: + +```diff +- axios.post("/upload", formData, { +- headers: { "Content-Type": "multipart/form-data" }, +- }); ++ axios.post("/upload", formData); +``` + +如果你明确设置了 `Content-Type: application/json`,axios 现在会自动将数据序列化为 JSON。 + +### 参数序列化 + +v1.x 对 URL 参数的序列化方式进行了若干破坏性变更,主要包括: + +**`params` 默认会进行百分号编码。** 如果你的后端期望接收 qs 风格的原始方括号编码,可能需要配置自定义序列化器: + +```js +import qs from 'qs'; + +axios.create({ + paramsSerializer: { + serialize: (params) => qs.stringify(params, { arrayFormat: 'brackets' }), + }, +}); +``` + +**`params` 中的嵌套对象现在使用方括号表示法**(`foo[bar]=1`)序列化,而不再使用点号表示法。如果你的后端期望点号表示法,请使用自定义序列化器。 + +**`null` 和 `undefined` 参数**的处理方式现在已统一:`null` 值序列化为空字符串,而 `undefined` 值则被完全忽略。 + +关于参数序列化配置的完整选项,请参阅[请求配置](/pages/advanced/request-config)页面。 + +### 内部模块不再导出 + +我们决定不再导出 axios 的内部模块,你需要将代码更新为仅使用 axios 的公开 API。此变更旨在简化 API,缩小 axios 的接口范围,使我们能够在不声明破坏性变更的情况下修改内部实现。 + +请查阅本站的 [API 参考](/pages/advanced/api-reference),获取最新的公开 API 信息。 + +### 请求配置 + +我们对请求配置对象进行了调整,请查阅本站的[配置参考](/pages/advanced/request-config)获取最新信息。 + +### 遗漏的破坏性变更 + +本指南并不详尽,可能未涵盖所有破坏性变更。如果你遇到任何问题,欢迎在 [docs GitHub 仓库](https://github.com/axios/docs)提交 issue,并添加 `breaking change` 标签。 diff --git a/docs/zh/pages/misc/security.md b/docs/zh/pages/misc/security.md new file mode 100644 index 0000000..ed662ea --- /dev/null +++ b/docs/zh/pages/misc/security.md @@ -0,0 +1,24 @@ +# 安全政策 + +## 报告漏洞 + +如果你认为在本项目中发现了安全漏洞,请按照以下说明向我们报告。我们对所有安全漏洞报告都认真对待。如果你发现的是第三方库中的漏洞,请向该库的维护者报告。 + +## 报告流程 + +请勿通过公开的 GitHub issue 报告安全漏洞。请使用 GitHub 官方安全渠道,提交 [security advisory(安全公告)](https://github.com/axios/axios/security)。 + +## 披露政策 + +收到安全漏洞报告后,我们将指定一名主要负责人,该负责人负责跟进漏洞报告,确认问题并确定受影响的版本,评估问题严重程度,开发修复方案并准备发布,在修复方案就绪后通知报告人。 + +## 安全更新 + +安全更新将在补丁开发和测试完成后尽快发布。我们将通过项目的 GitHub 仓库通知用户,并在项目的 GitHub Releases 页面发布发版说明和安全公告。我们还将弃用所有包含该安全漏洞的版本。 + +## 安全合作伙伴与致谢 + +感谢以下安全研究人员与我们合作,共同保障项目的安全: + +- [Socket Dev](https://socket.dev/) +- [GitHub Security Lab](https://securitylab.github.com/) diff --git a/docs/zh/pages/misc/semver.md b/docs/zh/pages/misc/semver.md new file mode 100644 index 0000000..1b5eead --- /dev/null +++ b/docs/zh/pages/misc/semver.md @@ -0,0 +1,44 @@ +# 语义化版本 + +语义化版本是一种版本控制方案,用于传达软件包中变更的性质。它是一套简单的规则和要求,规定了版本号的分配和递增方式。 + +## axios 的版本控制 + +axios 遵循语义化版本方案。这意味着每个 axios 版本都由三个部分组成:主版本号、次版本号和补丁版本号,版本号根据发版中变更的性质递增。 + +过去,axios 有时可能未严格遵循语义化版本,但未来将更严格地遵循语义化版本方案,以确保用户可以依赖版本号来了解库中变更的性质。 + +以下是版本方案的简要概述。 + +## 版本格式 + +语义化版本号由三个部分组成: + +1. 主版本号(Major) +2. 次版本号(Minor) +3. 补丁版本号(Patch) + +版本号写作 `MAJOR.MINOR.PATCH`,每个部分有其特定含义: + +- **主版本号**:进行不兼容的 API 变更时递增。 +- **次版本号**:以向后兼容的方式添加新功能时递增。 +- **补丁版本号**:进行向后兼容的缺陷修复时递增。 + +## 预发布版本 + +除版本号的三个部分外,还可以附加预发布版本标识。方式是在补丁版本号后紧跟一个连字符和一系列点号分隔的标识符,例如 `1.0.0-alpha.1`。 + +预发布版本表示该版本不稳定,可能不满足版本号所指示的预期兼容性要求。预发布版本按标识符的顺序排列,例如 `1.0.0-alpha.1` 早于 `1.0.0-alpha.2`。 + +## 版本范围 + +指定包的版本范围时,可以使用多种运算符来表示可接受的版本范围,可用运算符如下: + +- `>`:大于 +- `<`:小于 +- `>=`:大于或等于 +- `<=`:小于或等于 +- `~`:近似等于 +- `^`:兼容 + +例如,`^1.0.0` 表示接受任何大于或等于 `1.0.0` 且小于 `2.0.0` 的版本。 diff --git a/docs/zh/pages/misc/sponsors.md b/docs/zh/pages/misc/sponsors.md new file mode 100644 index 0000000..84b47e2 --- /dev/null +++ b/docs/zh/pages/misc/sponsors.md @@ -0,0 +1,185 @@ +--- +layout: page +--- + + + +
+

赞助商

+

axios 由以下组织提供支持。如果你希望赞助 axios,请访问我们的 open collective 页面了解详情。

+ +
+
+
+
+ +
+
+ {{ capitalizeFirstLetter(sponsor.tier) }} +
+
+ {{ sponsor.name }} +
+
+
+
+
+ +