On this page

🌐 Axios to WHATWG Fetch

将代码从 Axios HTTP 客户端迁移到 Node.js 中原生可用的 WHATWG Fetch API(全局 fetch),以减少依赖并提升性能。它会重写每一个 Axios 请求助手 — axios.request()axios.get()axios.delete()axios.head()axios.options()axios.post()axios.put()axios.patch()axios.postForm()axios.putForm()axios.patchForm() — 并且支持识别默认 ESM 导入、别名导入、CommonJS require() 调用和动态 import()。一旦所有调用点都转换完成,它还会从 package.json 中移除 axios@types/axios 条目。

🌐 Migrates code from the Axios HTTP client to the WHATWG Fetch API that is natively available in Node.js as the global fetch, reducing dependencies and improving performance. It rewrites every Axios request helper — axios.request(), axios.get(), axios.delete(), axios.head(), axios.options(), axios.post(), axios.put(), axios.patch(), axios.postForm(), axios.putForm(), and axios.patchForm() — and recognizes default ESM imports, aliased imports, CommonJS require() calls, and dynamic import(). Once all call sites are converted, it also removes the axios and @types/axios entries from package.json.

🌐 Usage

使用这个 codemod 运行:

🌐 Run this codemod with:

🌐 Examples

🌐 GET request

一个普通的 axios.get() 会变成带有 shim 的 fetch() 调用,这个 shim 可以保持 response.data 属性的正常运行。

🌐 A plain axios.get() becomes a fetch() call with a shim that keeps the response.data property working.

-import axios from "axios";
 const base = "https://dummyjson.com/todos";

-const all = await axios.get(base);
+const all = await fetch(base)
+  .then(async (res) => Object.assign(res, { data: await res.json() }))
+  .catch(() => null);
 console.log("\nGET /todos ->", all.status);
 console.log(`Preview: ${all.data.todos.length} todos`);

🌐 POST request with a JSON body

axios.post()data 参数使用 JSON.stringify() 序列化,并作为 body 选项传递。

🌐 The data argument of axios.post() is serialized with JSON.stringify() and passed as the body option.

-import axios from 'axios';
 const base = 'https://dummyjson.com/todos/add';

-const todoCreated = await axios.post(base, {
-  todo: 'Use DummyJSON in the project',
-  completed: false,
-  userId: 5,
-});
+const todoCreated = await fetch(base, {
+  method: "POST",
+  body: JSON.stringify({
+    todo: 'Use DummyJSON in the project',
+    completed: false,
+    userId: 5,
+  })
+})
+  .then(async (resp) => Object.assign(resp, { data: await resp.json() }))
+  .catch(() => null);
 console.log('\nPOST /todos ->', todoCreated);

🌐 Form submission

axios.postForm()(以及 putForm/patchForm 变体)将负载作为 URLSearchParams 发送。

-import axios from 'axios';
 const base = 'https://dummyjson.com/forms';

-const created = await axios.postForm(`${base}/submit`, {
-    title: 'Form Demo',
-    completed: false,
-});
+const created = await fetch(`${base}/submit`, {
+  method: "POST",
+  body: new URLSearchParams({
+      title: 'Form Demo',
+      completed: false,
+  })
+})
+  .then(async (resp) => Object.assign(resp, { data: await resp.json() }))
+  .catch(() => null);
 console.log(created);

🌐 axios.request() with a config object

配置对象的 urlmethoddata 属性被映射到 fetch() 调用上。

🌐 The url, method, and data properties of the config object are mapped onto the fetch() call.

-import axios from 'axios';
-
 const base = 'https://dummyjson.com/todos/1';

-const customRequest = await axios.request({
-  url: base,
-  method: 'PATCH',
-  data: {
-    todo: 'Updated todo',
-    completed: true,
-  },
-});
+const customRequest = await fetch(base, {
+  method: "PATCH",
+  body: JSON.stringify({
+      todo: 'Updated todo',
+      completed: true,
+    })
+})
+  .then(async (resp) => Object.assign(resp, { data: await resp.json() }))
+  .catch(() => null);
 console.log('\nREQUEST /todos/1 ->', customRequest);

CommonJS 模块的处理方式相同,现在不再使用的 require('axios') 绑定已经被移除了。

🌐 CommonJS modules are handled the same way, and the now-unused require('axios') binding is removed.

-const axios = require('axios');

 function fetchAllTodos() {
-    return axios.get('https://dummyjson.com/todos');
+    return fetch('https://dummyjson.com/todos')
+  .then(async (res) => Object.assign(res, { data: await res.json() }))
+  .catch(() => null);
 }

 module.exports = { fetchAllTodos };

🌐 Notes

  • 一个 fetch 响应是通过 res.json() 暴露它的有效负载,而不是通过 data 属性,所以每次转换的调用后都会跟着 .then(async (res) => Object.assign(res, { data: await res.json() })) 来保持现有的 response.data 访问正常工作。
  • 转换后的调用以 .catch(() => null) 结尾,所以失败的请求会解析为 null,而不是被拒绝。还要注意,不像 Axios,fetch 在遇到 HTTP 错误状态(4xx/5xx)时不会拒绝,所以基于 Axios 拒绝的错误处理代码需要手动检查一下。
  • 安全第一:如果文件中的任何 Axios 调用使用了不支持的配置选项,整个文件将保持不变,并会打印带有源位置的警告,从而保留原有的行为。
  • 转换完成后,codemod 会检测你的包管理器,并从 package.json 中移除 axios@types/axios 依赖。

🌐 Limitations

codemod 会跳过那些 Axios 调用使用了以下任意配置选项的文件,因为它们没有直接的 fetch 等效项:

🌐 The codemod skips files whose Axios calls use any of the following configuration options, because they have no direct fetch equivalent:

  • beforeRedirect
  • cancelToken
  • decompress
  • httpAgent
  • httpsAgent
  • maxBodyLength
  • maxContentLength
  • maxRedirects
  • paramsSerializer
  • signal
  • socketPath
  • timeout
  • transformRequest
  • transformResponse
  • validateStatus
  • withCredentials

它也不涵盖 Axios 中除了直接请求辅助之外的功能,比如拦截器、取消令牌,或者用 axios.create() 创建的实例配置。

🌐 It also does not cover Axios features outside of the direct request helpers, such as interceptors, cancel tokens, or instance configuration created with axios.create().