Skip to content

axios 封装 ​

本页对应 1-9axios封装案例,共 3 段视频,约 37 分钟。

学习目标 ​

  • 能够基于 Promise 和 XMLHttpRequest 封装简易 axios 函数,使其接收配置对象并返回 Promise,支持 .then() 与 .catch() 链式调用。
  • 能够实现请求方法与 URL 的配置,当未传 method 时默认使用 GET,并通过 loadend 事件判断状态码 200–299,成功时 resolve 并解析 JSON 数据,失败时 reject 返回错误对象。
  • 能够为封装函数增加 params 支持,使用 URLSearchParams 将对象转换为查询参数,并以正确格式拼接到 URL 后,调用该函数获取地区列表并渲染到页面。
  • 能够为封装函数增加 data 支持,在请求体中通过 JSON.stringify 提交 JSON 数据,并设置 Content-Type: application/json 请求头。
  • 能够调用封装后的函数完成省份列表获取与渲染、地区列表获取与渲染、用户注册请求,并验证成功与失败场景下的页面或控制台输出。

知识点 ​

需求与整体思路 ​

这一节的目标是:基于 Promise 和 XHR 封装一个简易的 myAxios 函数,再用它获取省份列表并展示到页面上,借此理解 axios 内部大致如何运作。

省份列表展示效果图

为什么需要:直接写 XHR 也能发请求,但调用方式零散;axios 之所以好用,是因为它把请求封装成函数,并返回 Promise,外部可以链式调用 .then 和 .catch。
怎么想:调用 myAxios({ url, method }) 时,外部希望拿到 Promise,所以函数内部要 return new Promise(...);真正的请求逻辑放在 Promise 的回调里。
怎么做:先定义函数和配置参数,再返回 Promise,在 Promise 内创建 XHR、设置请求方法和地址、监听响应、调用 resolve/reject,最后 send()。
易错点:只定义函数不返回 Promise,外部就不能 .then/.catch;Promise 里忘记调用 resolve 或 reject,外部会一直等待。

第一步:定义 myAxios 并接收配置对象 ​

为什么需要:调用时要能传入 URL 和方法,所以函数必须接收一个配置对象。
怎么想:笔记中调用形式类似 myAxios({ url: '...', method: 'GET' }),因此形参可命名为 config,内部通过 config.url、config.method 取值。
怎么做:

js
function myAxios(config) {
  return new Promise((resolve, reject) => {
    // 后续发请求逻辑写在这里
  });
}

易错点:不要漏写形参;不要把 config 当成字符串,它是一个对象。转写稿中先用 console.log(config) 验证,确认传入后能拿到 url 和 method 属性。

第二步:创建 XHR 并设置默认 GET ​

为什么需要:封装后的函数要像 axios 一样,方法可省略,省略时默认使用 GET。
怎么想:config.method 没传时是 undefined,可以用逻辑或 || 设置默认值:有值用传入值,无值用 'GET'。
怎么做:

js
const xhr = new XMLHttpRequest();
xhr.open(config.method || 'GET', config.url);

易错点:不要写死 xhr.open('GET', '固定地址'),否则封装失去意义;默认方法判断要放在 open 的第一个参数位置。小结中的答案就是:config.method 判断有值就用,无值用 'GET'。

第三步:监听响应并处理成功/失败 ​

为什么需要:服务器返回后,要根据状态码决定调用 resolve 还是 reject,这样外部才能走 .then 或 .catch。
怎么想:HTTP 状态码 200–299 视为成功;成功时把响应数据交给 resolve,失败时把异常交给 reject。多数接口返回 JSON 字符串,因此成功时用 JSON.parse 转成对象。
怎么做:

js
xhr.addEventListener('loadend', () => {
  if (xhr.status >= 200 && xhr.status < 300) {
    resolve(JSON.parse(xhr.response));
  } else {
    reject(new Error(xhr.response));
  }
});
xhr.send();

易错点:不要漏掉 xhr.send();状态码上限是 < 300,不是“大于 200 就一直成功”;JSON.parse 只适用于 JSON 格式响应。转写稿中测试错误 URL 时,.catch 能触发,并用 console.dir(err) 查看错误对象,因为 console.log 有时不方便展开。

第四步:调用 myAxios 获取并渲染省份列表 ​

为什么需要:封装完必须调用验证,否则不知道函数是否真的可用。
怎么想:调用后返回 Promise,所以在 .then 中拿结果,在 .catch 中处理失败;页面中准备一个盒子,把 res.list 渲染进去。
怎么做:

js
myAxios({
  url: '省份列表接口地址' // 替换为接口文档中的地址
}).then((res) => {
  document.querySelector('.box').innerText = res.list;
}).catch((err) => {
  console.dir(err);
});

易错点:接口地址要按接口文档复制,不能随意编造;渲染前先确认 res 是对象、res.list 是数组。转写稿中先在网络面板确认请求已发出、方法为 GET,再在控制台查看 res,最后渲染到 .box,页面出现省份信息即验证通过。

小结 ​

本节核心是“返回 Promise + XHR 发请求 + 状态码分流 + 调用渲染”。默认请求方法的写法是:config.method 有值就用传入值,无值用 'GET'。调试时建议依次确认:config 是否拿到、请求是否发出、状态码是否成功、res.list 是否存在、页面盒子选择器是否正确。

需求与整体思路 ​

上一节的 myAxios 只能接收 url 和 method,调用时虽然能发请求,但地区列表接口还需要额外携带查询参数。为什么需要这一步:如果每次把参数手写进 URL,既麻烦又容易拼错,也不符合封装函数的目标。怎么想:在调用 myAxios 时额外传入一个 params 对象,例如 { pname: '辽宁省', cname: '大连市' };函数内部判断 config.params 是否存在,存在就转成查询参数字符串,拼到 URL 后面,再交给 XMLHttpRequest 发送。怎么做:顺序必须是“先判断并拼接 URL,再调用 xhr.open”,因为 open 使用的是最终 URL。易错点:params 不是必传项,不能无脑转换;拼接时不要漏掉 ?。

在 myAxios 中加入 params 支持 ​

为什么需要:地区列表接口的参数是查询参数,需要出现在 URL 的 ? 后面。怎么想:转写稿里强调先判断 params 是否存在,再用浏览器内置对象 URLSearchParams 把对象转成查询串。步骤是:实例化 new URLSearchParams(config.params),再调用 toString()。怎么做:把下面逻辑放在 xhr.open 之前。

js
function myAxios(config) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    // 有 params 才转换并拼接查询参数
    if (config.params) {
      const params = new URLSearchParams(config.params);
      const query = params.toString();
      config.url += '?' + query;
    }

    xhr.open(config.method || 'GET', config.url);

    xhr.addEventListener('loadend', () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        // 绝大多数接口返回 JSON 格式数据
        resolve(JSON.parse(xhr.response));
      } else {
        reject(new Error(xhr.response));
      }
    });

    xhr.send();
  });
}

易错点:config.params 不存在时不要执行转换;toString() 不能漏;拼接时 ? 不能漏。控制台里看到中文变成 %E8... 是 URL 编码,属于正常现象,网络面板里能正常看到中文参数。

调用函数获取地区列表 ​

为什么需要:封装完函数后必须用真实接口验证 params 是否生效。怎么想:地区列表接口使用 GET,方法可省略,因为函数里用 config.method || 'GET' 设置了默认值;参数按接口文档写成查询参数对象。怎么做:调用 myAxios,在 then 中拿到 res.list 并渲染到页面盒子。

js
myAxios({
  url: '地区列表接口地址', // 替换为接口文档中的地址
  params: {
    pname: '辽宁省',
    cname: '大连市'
  }
}).then((res) => {
  console.log(res);
  document.querySelector('.box').innerText = res.list;
}).catch((err) => {
  console.dir(err);
});

易错点:参数名要按接口文档写,不要自己造;then 里先打印 res 确认结构,再取 res.list;失败时用 catch 和 console.dir 查看错误对象。

调试过程与关键细节 ​

调试时可以先在函数里打印 config.params,确认外面传进来的对象存在;再打印 query,确认已经变成 pname=...&cname=... 的形式;最后打印 config.url,确认问号和参数都拼上了。转写稿中还提到,如果暂时注释掉 send,可以避免请求报错干扰观察拼接结果。真正请求后,到网络面板查看请求参数是否显示“辽宁省、大连市”,再到控制台查看返回对象中的 list,最后渲染到 .box。易错点:拼接代码位置不能放到 open 后面;如果原 URL 本身已带 ?,继续用 ? 会出错,应改用 &,本节练习默认 URL 没有查询串,所以用 ?。

目标:让 myAxios 支持请求体 ​

本节要基于上节课的简易 myAxios 继续调优:调用函数时可以额外传入 data 属性,data 是一个 JS 对象;函数内部把它转成 JSON 字符串,并通过请求体发送给服务器。随后用自己封装的 myAxios 完成注册用户。

为什么需要:GET 请求常把参数拼在 URL 上,而注册、登录这类提交数据更适合放在请求体里。怎么想:先判断有没有 data,有才处理请求体;没有就按原来的方式发送。怎么做:在 send 之前判断 config.data,设置请求头,转换数据,再发送。易错点:不要一上来就 JSON.stringify,也不要在没有 data 时仍然携带请求体。

先判断 data 是否存在 ​

为什么需要:并不是每个接口都需要请求体。转写稿中明确说,只有 data 属性存在时,才通过请求体写数据;不存在就不需要携带。

怎么想:调用 myAxios 时传入的对象最终会到 config 形参里,所以判断 config.data。代码应写在 xhr.send() 之前,因为发送动作一旦执行,再设置请求头或改数据就晚了。

怎么做:保留原来的成功/失败监听,在 send 位置分支处理:

js
if (config.data) {
  // 有请求体数据:设置请求头并发送 JSON
} else {
  // 请求体不需要携带数据时调用
  xhr.send();
}

易错点:不要漏掉 else 中的 xhr.send(),否则没有 data 的请求根本发不出去;判断位置也不要放到 send 后面。

设置 Content-Type 请求头 ​

为什么需要:请求体里放的是 JSON,但服务器怎么知道?需要通过请求头告诉服务器数据格式。转写稿中反复强调:在请求体携带数据前,要设置请求头。

怎么想:使用 xhr.setRequestHeader('Content-Type', 'application/json')。值不是凭感觉写的,要去接口文档看。注册账号接口的 body 参数后面写着 application/json,就照文档设置。

怎么做:

js
xhr.setRequestHeader('Content-Type', 'application/json');

易错点:Content-Type 不要拼错;setRequestHeader 必须在 xhr.open() 之后、xhr.send() 之前调用。转写稿里的“康ten type”应纠正为 Content-Type,“杰森/节森/精神”应纠正为 JSON。

用 JSON.stringify 转换后发送 ​

为什么需要:config.data 此时还是 JS 对象,直接发送会变成不符合要求的内容。上面已经声明发送 JSON,下面就要让数据格式匹配。

怎么想:转写稿说得很清楚:config.data 是一个对象,需要额外做一步数据转化,用 JSON.stringify 把对象转成 JSON 字符串。

怎么做:在 if (config.data) 中:

js
if (config.data) {
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.send(JSON.stringify(config.data));
} else {
  xhr.send();
}

易错点:不要写成 xhr.send(config.data);也不要设置 application/json 却发送对象。设置的数据格式和提交的数据格式要匹配。

调用 myAxios 完成注册用户 ​

为什么需要:封装完必须用真实接口验证,否则不知道请求头、请求体是否正确。怎么想:先绑定按钮点击事件,在事件里调用 myAxios,按接口文档填 url、method、data。转写稿中注册接口方法是 POST,不能省略。

怎么做:调用结构如下,URL 用接口文档中的注册账号地址:

js
myAxios({
  url: '接口文档中的注册账号地址',
  method: 'POST',
  data: {
    username: 'IT黑马666',
    password: '123456'
  }
}).then(res => {
  console.log(res);
}).catch(err => {
  console.dir(err);
});

易错点:data 里属性名要照接口文档写,例如 username、password;不要漏 .then 和 .catch。转写稿中第一次注册成功,第二次再点同一账号会报“账号被占用”,这是服务器返回的业务错误,会进入失败分支。

调试过程与易错点 ​

转写稿的调试顺序是:先绑定点击事件,写一个 myAxios 调用占位;再回到函数里补 data 判断、请求头、JSON.stringify 和 send;最后结合接口文档填 URL、方法和参数。

测试时打开网络面板:在“标头”里确认 Content-Type: application/json 已设置;在“载荷/请求”里查看提交数据,必要时点“源代码”确认是 JSON 字符串;在“预览”里看到注册成功。若重复注册,控制台会输出错误,用 console.dir 更方便展开 Error 对象查看 message。

易错点再强调:data 判断要早于 send;请求头要在 open 后、send 前;发送前必须 JSON.stringify;无 data 时也要 send();不要把 GET 的查询参数思路和请求体混在一起。

小结 ​

外面传入 data 选项后,myAxios 内部先判断是否传入了这个属性;有则自己转成 JSON 字符串,设置 Content-Type: application/json 请求头,并在 send 方法中携带;没有则正常 send()。这样就用自己封装的简易 axios 完成了注册用户,也理解了请求体传递数据的关键流程。

课件图示 ​

课件第24页:需求及核心逻辑 1. 基于Promise 和XHR 实现hmAxios函数 2.

课件第26页:需求及核心逻辑 1. 调优hmAxios 函数,支持查询参数功能 2. 调用hm

课件第28页:需求及核心逻辑 1. 调优hmAxios 函数,支持请求体传递数据(JSON)

课件第3页:XMLHttpRequest基本使用 定义:XMLHttpRequest(XHR

课件第4页:试一试 需求:通过XMLHttpRequest 获取省份数据,渲染到页面上 //

课件第15页:定义: Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。

课件第20页:核心功能 Promise + XHR 获取省份数据并渲染 请求数据 传递数据 接

课件第33页:城市查询 注册input事件 函数防抖 查询城市 渲染城市

代码示例 ​

1. 简易 myAxios —— 获取省份列表(默认 GET) ​

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>封装 myAxios - 省份列表</title>
</head>
<body>
  <div class="box"></div>

  <script>
    // 第一步:定义 myAxios,接收配置对象,返回 Promise 对象
    function myAxios(config) {
      return new Promise((resolve, reject) => {
        // 第三步:通过 XHR 发请求
        const xhr = new XMLHttpRequest()

        // 方法不传时默认为 GET(逻辑短路)
        xhr.open(config.method || 'GET', config.url)

        xhr.addEventListener('loadend', () => {
          // 2xx 视为成功
          if (xhr.status >= 200 && xhr.status < 300) {
            // 绝大多数接口返回 JSON 格式,一步到位解析
            resolve(JSON.parse(xhr.response))
          } else {
            reject(new Error(xhr.response))
          }
        })

        xhr.send() // 别漏了发送
      })
    }

    // 第四步:调用函数实现功能(地址以接口文档为准)
    myAxios({
      url: 'http://hmajax.itheima.net/api/province'
    })
      .then((res) => {
        console.log(res)
        document.querySelector('.box').innerHTML = res.list.join('<br>')
      })
      .catch((err) => {
        console.dir(err) // 用 dir 才方便点开查看
      })
  </script>
</body>
</html>

关键行与易错点

  • return new Promise((resolve, reject) => {...}):正因为返回的是 Promise 对象,外部才能 .then().catch();忘了 return 就会报“没有 then 方法”。
  • config.method || 'GET':没传 method 时 config.method 是 undefined(falsy),短路后取 'GET';传了小写 get 也照样能用。
  • 判断条件 status >= 200 && status < 300:上下限都要写,只写 >= 200 会把 404、500 也当成功。
  • resolve(JSON.parse(xhr.response)):解析失败会抛异常,说明接口返回的不是 JSON,需先确认响应内容。
  • reject(new Error(xhr.response)):必须包一层 new Error,直接 reject(字符串) 会让 .catch 里拿到的不是错误对象。
  • xhr.send() 是最容易漏的一行,不调用接口永远不会发出去。

2. 支持 params 查询参数 —— 获取地区列表 ​

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>封装 myAxios - 地区列表</title>
</head>
<body>
  <div class="box"></div>

  <script>
    function myAxios(config) {
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()

        // 第一步:判断 params 选项;有值才拼查询参数
        if (config.params) {
          // 第二步:用 URLSearchParams 把对象转成查询参数字符串
          const paramsObj = new URLSearchParams(config.params)
          const queryString = paramsObj.toString()
          // 第三步:拼到 URL 后面,问号不能漏
          config.url += `?${queryString}`
        }

        // 拼接必须在 open 之前,open 之后改 url 不生效
        xhr.open(config.method || 'GET', config.url)

        xhr.addEventListener('loadend', () => {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve(JSON.parse(xhr.response))
          } else {
            reject(new Error(xhr.response))
          }
        })

        xhr.send()
      })
    }

    // 第四步:获取辽宁省大连市的地区列表
    myAxios({
      url: 'http://hmajax.itheima.net/api/area',
      params: {
        pname: '辽宁省',
        cname: '大连市'
      }
    })
      .then((res) => {
        console.log(res)
        document.querySelector('.box').innerHTML = res.list.join('<br>')
      })
      .catch((err) => console.dir(err))
  </script>
</body>
</html>

关键行与易错点

  • if (config.params):查询参数不是每个接口都需要,必须先判断;不判断就会拼出 undefined。
  • new URLSearchParams(config.params) → .toString():两步就能生成 pname=辽宁省&cname=大连市,它会自动做 URL 编码,控制台看到中文变成 %E8%BE%BD... 是正常现象,服务器能正确解析。
  • config.url += \?${queryString}`:问号是易错点,漏了就变成 api/areapname=...`,接口直接报错。
  • 拼接代码必须写在 xhr.open() 之前:open 之后修改 config.url 不会影响这次请求。
  • 查询参数走的是 URL,所以 xhr.send() 里不需要传任何东西,与上一节写法完全一致。

3. 支持 data 请求体 —— 注册用户 ​

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>封装 myAxios - 注册用户</title>
</head>
<body>
  <button class="btn">注册用户</button>

  <script>
    function myAxios(config) {
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()

        if (config.params) {
          const paramsObj = new URLSearchParams(config.params)
          config.url += `?${paramsObj.toString()}`
        }

        xhr.open(config.method || 'GET', config.url)

        xhr.addEventListener('loadend', () => {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve(JSON.parse(xhr.response))
          } else {
            reject(new Error(xhr.response))
          }
        })

        // 第一步:判断 data 选项是否存在
        if (config.data) {
          // 第二步:设置请求头,告诉服务器请求体是 JSON
          xhr.setRequestHeader('Content-Type', 'application/json')
          // 第三步:对象转 JSON 字符串,随请求体发送
          xhr.send(JSON.stringify(config.data))
        } else {
          // 请求体不需要携带数据时正常发送
          xhr.send()
        }
      })
    }

    // 第四步:调用函数完成注册
    document.querySelector('.btn').addEventListener('click', () => {
      myAxios({
        url: 'http://hmajax.itheima.net/api/register',
        method: 'post',
        data: {
          username: 'itheima666',
          password: '123456'
        }
      })
        .then((res) => {
          console.log(res)
        })
        .catch((err) => {
          console.dir(err) // 账号被占用等错误信息从这里看
        })
    })
  </script>
</body>
</html>

关键行与易错点

  • xhr.setRequestHeader('Content-Type', 'application/json'):必须在 open() 之后、send() 之前调用,写在 open 前会直接抛错。
  • 请求头写的是 JSON,send 里就必须传 JSON.stringify(config.data);两者不匹配服务器会解析失败。
  • JSON.stringify 不能漏:直接把对象丢给 send,实际发出去的是 [object Object]。
  • if / else 两条分支都要有 xhr.send(),否则无 data 的普通请求就永远发不出去。
  • 注册接口是 POST,method 不能省略,否则走默认 GET,参数根本不会进请求体。
  • 同一个用户名注册第二次会返回非 2xx,此时走 .catch,用 console.dir 才能展开看到服务器返回的提示信息。

常见错误 ​

  1. 调用 myAxios(...).then 直接报 Cannot read properties of undefined (reading 'then')

    • 原因:函数体内写了 new Promise(...) 但漏了 return,函数返回 undefined。
    • 修法:return new Promise((resolve, reject) => { ... });写完先 console.log(myAxios({url:'...'})) 确认打印出 Promise 实例。
  2. Network 面板里请求一直 pending,.then 永不执行,控制台也不报错

    • 原因:只 xhr.open(...) 和绑定了 loadend,忘了 xhr.send();或 send() 写在了 if (config.data) 分支里,无 data 时不发送。
    • 修法:把 send() 放到 if/else 两条路径都必经的位置(无 data 时 xhr.send(),有 data 时 xhr.send(JSON.stringify(config.data))),或先写 xhr.send() 再补分支。
  3. 带 params 的请求 404 或参数丢失,URL 变成 .../listid=1

    • 原因:拼接时漏了 ?;或没判断 config.params 是否存在就无条件拼接,把 undefined 拼进 URL。
    • 修法:if (config.params) { config.url += '?' + new URLSearchParams(config.params).toString() },且该段必须在 xhr.open() 之前执行。
  4. 注册接口返回 400,后端收到的是 [object Object]

    • 原因:send(config.data) 直接传了 JS 对象,且没设 Content-Type,XHR 按表单默认格式序列化。
    • 修法:成对处理——xhr.setRequestHeader('Content-Type', 'application/json') + xhr.send(JSON.stringify(config.data)),两者缺一不可。
  5. 注册成功(201/204)却走进了 .catch

    • 原因:状态码判断写成 xhr.status === 200。
    • 修法:用区间 xhr.status >= 200 && xhr.status < 300 判成功,其余走 reject。
  6. 页面渲染出 北京市,上海市,天津市 一整串,或者显示 undefined

    • 原因:innerHTML = res.list 对数组隐式 toString() 用逗号连接;或 resolve(xhr.response) 忘了 JSON.parse。
    • 修法:res.list.map(v =>
    • ${v}
    • ).join('') 再赋值;resolve 前先 JSON.parse(xhr.response),并对 res.list 做 || [] 兜底。
  7. .catch 里 e.message 是 undefined,只能看到 [object Object]

    • 原因:reject 传的是 xhr.response 原始字符串或普通对象。
    • 修法:reject(new Error('请求失败')) 或 const err = new Error(...); err.response = xhr.response; reject(err),调试用 console.dir 而非 console.log。

练习 ​

  1. 加超时能力:给 myAxios 支持 config.timeout(毫秒),超时后走 .catch。

    • 提示:xhr.timeout = config.timeout,监听 ontimeout 事件 reject(new Error('请求超时'))。
    • 验收:把 timeout 设为 1,能在 .catch 里拿到超时错误,Network 中请求状态为 (canceled)。
  2. 加 baseURL 支持:myAxios({ baseURL: 'http://hmajax.itheima.net', url: '/api/province' }) 能正确请求。

    • 提示:在 params 拼接之前完成 URL 合并,注意判断 url 是否已是绝对地址(startsWith('http'))。
    • 验收:不传 baseURL 时行为与改造前完全一致(回归测试省份列表)。
  3. 渲染改造:把省份列表从字符串改成 <ul><li> 结构,并在数据为空时显示"暂无数据"。

    • 提示:Array.isArray(res.list) && res.list.length 双重判断。
    • 验收:正常数据出列表;手动把 URL 改成返回空数组的接口,页面显示"暂无数据"而非 undefined。
  4. 串行调用:用同一个 myAxios 完成"注册 → 用刚注册的账号登录"两步,打印登录结果。

    • 提示:async/await + try/catch,第二步依赖第一步的成功。
    • 验收:控制台先输出注册成功再输出登录 token;重复注册时只打印一次错误,第二步不执行。
  5. 边界加固:让 myAxios 在 url 本身已带 ?a=1 时再传 params,拼接结果仍合法。

    • 提示:判断 config.url.includes('?'),已有查询串时用 & 连接。
    • 验收:url: '/api/list?a=1' + params: {b:2} 得到 /api/list?a=1&b=2。

原视频对照 ​

#视频时长
1封装-简易axios-获取省份列表14:47
2封装-简易axios-获取地区列表12:28
3封装-简易axios-注册用户10:26

小结 ​

  1. 这套封装的结构本质只有一句话:配置对象进、Promise 出,所有能力(method / params / data)都是在这条主干上做"读配置 → 改请求"的增量改造。
  2. method 的默认值用逻辑短路 config.method || 'GET' 实现,这个模式可以原样复用到 timeout、headers 等任何"可选配置"上。
  3. params 的拼接时机必须在 open() 之前——参数是通过 URL 传给服务器的,URL 定了就改不了了;这是顺序问题,不是写法问题。
  4. 请求体是三件套:判断 data 存在 → 设 Content-Type → stringify 后 send,三者必须格式匹配,缺一环后端就收到脏数据。
  5. 成功判定用状态码区间 200 <= status < 300,不要写等号;reject 一律传 Error 实例(可挂 response),否则调用方拿不到可用信息。
  6. 排查顺序固定为:先看 Network 有没有请求 → 看标头(method / Content-Type)→ 看载荷(查询串 / 请求体)→ 最后才看 JS 逻辑,能省掉大半调试时间。
  7. 手写 myAxios 的价值是看清 axios 的分层(配置解析 / 请求发送 / Promise 包装),生产环境仍应使用 axios,但读它的源码和文档时你会知道每一层在做什么。