vlambda博客
学习文章列表

前端网络请求Ajax原理与封装(碎片化学习)

前端网络请求封装

我们平时和服务端打交道都需要使用到网络请求,但是平时开发中我们一般都用别人封装好的比如 ajax、axios,或者使用更简单的原生fetch方法(以后再讲这个方法的封装)。我们学习的时候更要知其然知其所以然,所以今天我们就来看看如何封装一个最基础的网络请求函数。

了解Ajax

XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在Ajax编程中被大量使用

readyState的4个状态

  • 0 - (未初始化)还没有调用send()方法
  • 1 - (载入)已调用send()方法,正在发送请求
  • 2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
  • 3 - (交互)正在解析响应内容
  • 「4 - (完成)响应内容解析完成,可以在客户端调用了 (主要)」

请求状态码(Status)

「1XX:」 信息,服务器收到请求,需要请求者继续执行操作(不常用)

「2XX:」 成功,操作被成功接收并处理 。「常见:200-OK(正常返回)、201-Created(成功创建)、204 - No Content(网页未更新时,服务器正常处理但没返回内容)」

「3XX:」 重定向,需要进一步的操作以完成请求 。「常见:301 -  Moved Permanently (永久重定向, 请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI )、302 -  Found(临时重定向,资源临时被移动,客户端应继续使用原有URI )、304 -  Not Modified( 未修改。请求的资源未修改,不返回任何资源。客户端通常会缓存访问过的资源)」

「4XX:」 客户端错误状态 ,表示服务器无法处理请求。「常见:400 -  Bad Request (客户端请求语法错误,服务器无法理解 )、401 - Unauthorized(未授权,一般是需要先登录授权)、403 -  Forbidden ( 服务器理解请求,但是拒绝执行 ,一般用于某些页面权限的设置)、404 - Not Found(资源访问不到)」

「5XX:」 服务器错误,处理请求的过程中发生了错误 。常见:500( 服务器内部错误,无法完成请求 )、 503(超载或者在维护,暂时无法处理请求)

封装请求函数

回调函数版本

function ajax(options{
  // ES6解构并赋予默认值
  const { url, method = 'GET', sync = true, responseType = 'json' } = options;

  const xhr = new XMLHttpRequest();

  xhr.open(method, url, sync);

  // 设置响应的类型,默认为json
  xhr.responseType = responseType;

  xhr.onreadystatechange = () => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      // 成功的回调
      options.success(xhr.response);
    }
  };

  xhr.onerror = (err) => {
    // 错误的回调
    options.fail(err);
  };

  // 此处只处理 get 和 post 请求,还有 put、delete、options的请求就不处理了
  if (method === 'GET') {
    xhr.send();
  }

  // POST 请求需要发送请求体
  if (method === 'POST') {
    xhr.send(options.data);
  }
}

ajax({
  url'此处填写需要发送请求的地址',
  success(res) => {
    // 拿到服务端返回的数据
    console.log(res);
  },
  fail(err) => {
    console.log('错误处理', err);
  },
});

Promise 版本

Promise 版本我们只是在函数内返回了一个Promise,并将结果和错误抛出去,这种方式更加推荐,因为回调函数版本会形成“回调地狱”的问题。“回调地狱”指的是函数层级不断的嵌套。

function ajax(options{
  return new Promise((resolve, reject) => {
    // ES6解构并赋予默认值
    const { url, method = 'GET', sync = true, responseType = 'json' } = options;

    const xhr = new XMLHttpRequest();

    xhr.open(method, url, sync);

    xhr.responseType = responseType;

    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        resolve(xhr.response);
      }
    };

    xhr.onerror = (err) => {
      reject(err);
    };

    // 此处只处理 get 和 post 请求,还有 put、delete、options的请求就不处理了
    if (method === 'GET') {
      xhr.send();
    }

    if (method === 'POST') {
      xhr.setRequestHeader("Content-Type""application/x-www-form-urlencoded");
      xhr.send(options.data);
    }
  });
}


ajax({ url'此处填写需要发送请求的地址' })
  .then((res) => {
    // 拿到服务端返回结果
    console.log(res);
  })
  .catch((err) => {
    // 错误处理
    console.log(err);
  });