前端常见面试-请求篇

        对于前端来讲,请求是前端平常工做必备的,经过请求才能与后端进行数据交互,尤为在如今先后端分离的开发模式下,请求显得就更加剧要。所以,对于前端开发者来讲,掌握请求就很重要。下面将从http请求和常见的几个请求技术作具体的讲解css

1、XMLHttpRequest

        XMLHttpRequest一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,按照标准先后能够分为两个版本,具体阐述以下:html

版本以(老版本):
//新建一个XMLHttpRequest对象
var xhr=new XMLHttpRequest();

//进行请求
xhr.open('GET', 'url');
xhr.send();

//等待服务器响应
xhr.onreadystatechange = function(){
    //该函数会被调用四次,所以须要判断状态是否为4
    if ( xhr.readyState == 4 && xhr.status == 200 ) {
      alert( xhr.responseText );

    } else {

      alert( xhr.statusText );

    }
};

        在老版本中的,对应的具体属性说明以下:前端

  1. xhr.readyState:XMLHttpRequest对象的状态,等于4表示数据已经接收完毕。
  2. xhr.status:服务器返回的状态码,等于200表示一切正常。
  3. xhr.responseText:服务器返回的文本数据
  4. xhr.responseXML:服务器返回的XML格式的数据
  5. xhr.statusText:服务器返回的状态文本。

        老版本由于不是统一的标准,各个浏览器厂商在实现的时候都有必定的差别,并且在存在一些缺陷:vue

  1. 只支持文本数据的传送,没法用来读取和上传二进制文件。
  2. 传送和接收数据时,没有进度信息,只能提示有没有完成。
  3. 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。
版本二(标准后的版本):

        为了更好的使用XMLHttpRequest,w3school发布了标准版本,该版本弥补了版本一的缺陷,也被各大浏览器厂商接受并实现。具体为:node

  1. 能够设置HTTP请求的时限。
  2. 可使用FormData对象管理表单数据。
  3. 能够上传文件。
  4. 能够请求不一样域名下的数据(跨域请求)。
  5. 能够获取服务器端的二进制数据。
  6. 能够得到数据传输的进度信息。

固然,通常为了友好的进行兼容各个浏览器,会采用对浏览器进行判断并进行兼容性模式来获取XMLHttpRequest的对象jquery

var xhr;
if (window.XMLHttpRequest) { // Mozilla, Safari...
  xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
 try {
    xhr = new ActiveXObject('Msxml2.XMLHTTP');
 } catch (e) {
 try {
      xhr = new ActiveXObject('Microsoft.XMLHTTP'); //IE5,6
 } catch (e) {}
 }
}
// 请求成功回调函数
xhr.onload = e => {
    console.log('request success');
};
// 请求结束
xhr.onloadend = e => {
    console.log('request loadend');
};
// 请求出错
xhr.onerror = e => {
    console.log('request error');
};
// 请求超时
xhr.ontimeout = e => {
    console.log('request timeout');
};
// 请求回调函数.XMLHttpRequest标准又分为Level 1和Level 2,这是Level 1和的回调处理方式
// xhr.onreadystatechange = () => {
//  if (xhr.readyState !== 4) {
//  return;
//  }
//  const status = xhr.status;
//  if ((status >= 200 && status < 300) || status === 304) {
//  console.log('request success');
//  } else {
//  console.log('request error');
//  }
//  };

xhr.timeout = 0; // 设置超时时间,0表示永不超时
// 初始化请求
xhr.open('GET/POST/DELETE/...', '/url', true || false);
// 设置指望的返回数据类型 'json' 'text' 'document' ...
xhr.responseType = '';
// 设置请求头
xhr.setRequestHeader('', '');
// 发送请求
xhr.send(null || new FormData || 'a=1&b=2' || 'json字符串');

2、ajax请求

        AJAX 是一种与服务器交换数据的技术,能够在不从新载入整个页面的状况下更新网页的一部分,其实就是对XMLHttpRequest的封装,能够直接引入jquery工具包来进行调用ajax请求(jquery是一个js工具包,其特色是:写得少,作得多),具体的ajax经常使用方式以下:ios

方法 描述
$.ajax() 执行异步 AJAX 请求
$.ajaxPrefilter() 在每一个请求发送以前且被 $.ajax() 处理以前,处理自定义 Ajax 选项或修改已存在选项
$.ajaxSetup() 为未来的 AJAX 请求设置默认值
$.ajaxTransport() 建立处理 Ajax 数据实际传送的对象
$.get() 使用 AJAX 的 HTTP GET 请求从服务器加载数据
$.getJSON() 使用 HTTP GET 请求从服务器加载 JSON 编码的数据
$.getScript() 使用 AJAX 的 HTTP GET 请求从服务器加载并执行 JavaScript
$.param() 建立数组或对象的序列化表示形式(可用于 AJAX 请求的 URL 查询字符串)
$.post() 使用 AJAX 的 HTTP POST 请求从服务器加载数据
ajaxComplete() 规定 AJAX 请求完成时运行的函数
ajaxError() 规定 AJAX 请求失败时运行的函数
ajaxSend() 规定 AJAX 请求发送以前运行的函数
ajaxStart() 规定第一个 AJAX 请求开始时运行的函数
ajaxStop() 规定全部的 AJAX 请求完成时运行的函数
ajaxSuccess() 规定 AJAX 请求成功完成时运行的函数
load() 从服务器加载数据,并把返回的数据放置到指定的元素中
serialize() 编码表单元素集为字符串以便提交
serializeArray() 编码表单元素集为 names 和 values 的数组
优势:
  • 对原生XHR的封装
  • 针对MVC的编程
  • 完美的兼容性
  • 支持jsonp
缺点:
  • 不符合MVVM
  • 异步模型不够现代,不支持链式,代码可读性差
  • 整个Jquery太大,引入成本太高

        固然,咱们能够直接使用XMLHttpReqeust来进行实现本身的ajax封装,具体代码以下:es6

const http = {
  /**
   * js封装ajax请求
   * >>使用new XMLHttpRequest 建立请求对象,因此不考虑低端IE浏览器(IE6及如下不支持XMLHttpRequest)
   * >>使用es6语法,若是须要在正式环境使用,则能够用babel转换为es5语法 https://babeljs.cn/docs/setup/#installation
   *  @param settings 请求参数模仿jQuery ajax
   *  调用该方法,data参数须要和请求头Content-Type对应
   *  Content-Type                        data                                     描述
   *  application/x-www-form-urlencoded   'name=哈哈&age=12'或{name:'哈哈',age:12}  查询字符串,用&分割
   *  application/json                     name=哈哈&age=12'                        json字符串
   *  multipart/form-data                  new FormData()                           FormData对象,当为FormData类型,不要手动设置Content-Type
   *  注意:请求参数若是包含日期类型.是否能请求成功须要后台接口配合
   */
  ajax: (settings = {}) => {
    // 初始化请求参数
    let _s = Object.assign({
      url: '', // string
      type: 'GET', // string 'GET' 'POST' 'DELETE'
      dataType: 'json', // string 指望的返回数据类型:'json' 'text' 'document' ...
      async: true, //  boolean true:异步请求 false:同步请求 required
      data: null, // any 请求参数,data须要和请求头Content-Type对应
      headers: {}, // object 请求头
      timeout: 1000, // string 超时时间:0表示不设置超时
      beforeSend: (xhr) => {
      },
      success: (result, status, xhr) => {
      },
      error: (xhr, status, error) => {
      },
      complete: (xhr, status) => {
      }
    }, settings);
    // 参数验证
    if (!_s.url || !_s.type || !_s.dataType || !_s.async) {
      alert('参数有误');
      return;
    }
    // 建立XMLHttpRequest请求对象
    let xhr = new XMLHttpRequest();
    // 请求开始回调函数
    xhr.addEventListener('loadstart', e => {
      _s.beforeSend(xhr);
    });
    // 请求成功回调函数
    xhr.addEventListener('load', e => {
      const status = xhr.status;
      if ((status >= 200 && status < 300) || status === 304) {
        let result;
        if (xhr.responseType === 'text') {
          result = xhr.responseText;
        } else if (xhr.responseType === 'document') {
          result = xhr.responseXML;
        } else {
          result = xhr.response;
        }
        // 注意:状态码200表示请求发送/接受成功,不表示业务处理成功
        _s.success(result, status, xhr);
      } else {
        _s.error(xhr, status, e);
      }
    });
    // 请求结束
    xhr.addEventListener('loadend', e => {
      _s.complete(xhr, xhr.status);
    });
    // 请求出错
    xhr.addEventListener('error', e => {
      _s.error(xhr, xhr.status, e);
    });
    // 请求超时
    xhr.addEventListener('timeout', e => {
      _s.error(xhr, 408, e);
    });
    let useUrlParam = false;
    let sType = _s.type.toUpperCase();
    // 若是是"简单"请求,则把data参数组装在url上
    if (sType === 'GET' || sType === 'DELETE') {
      useUrlParam = true;
      _s.url += http.getUrlParam(_s.url, _s.data);
    }
    // 初始化请求
    xhr.open(_s.type, _s.url, _s.async);
    // 设置指望的返回数据类型
    xhr.responseType = _s.dataType;
    // 设置请求头
    for (const key of Object.keys(_s.headers)) {
      xhr.setRequestHeader(key, _s.headers[key]);
    }
    // 设置超时时间
    if (_s.async && _s.timeout) {
      xhr.timeout = _s.timeout;
    }
    // 发送请求.若是是简单请求,请求参数应为null.不然,请求参数类型须要和请求头Content-Type对应
    xhr.send(useUrlParam ? null : http.getQueryData(_s.data));
  },
  // 把参数data转为url查询参数
  getUrlParam: (url, data) => {
    if (!data) {
      return '';
    }
    let paramsStr = data instanceof Object ? http.getQueryString(data) : data;
    return (url.indexOf('?') !== -1) ? paramsStr : '?' + paramsStr;
  },
  // 获取ajax请求参数
  getQueryData: (data) => {
    if (!data) {
      return null;
    }
    if (typeof data === 'string') {
      return data;
    }
    if (data instanceof FormData) {
      return data;
    }
    return http.getQueryString(data);
  },
  // 把对象转为查询字符串
  getQueryString: (data) => {
    let paramsArr = [];
    if (data instanceof Object) {
      Object.keys(data).forEach(key => {
        let val = data[key];
        // todo 参数Date类型须要根据后台api酌情处理
        if (val instanceof Date) {
          // val = dateFormat(val, 'yyyy-MM-dd hh:mm:ss');
        }
        paramsArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
      });
    }
    return paramsArr.join('&');
  }
}

3、vue-resource请求

        vue-resource是Vue.js的一款插件,它能够经过XMLHttpRequest或JSONP发起请求并处理响应。也就是说,$.ajax能作的事情,vue-resource插件同样也能作到,并且vue-resource的API更为简洁。另外,vue-resource还提供了很是有用的inteceptor功能,使用inteceptor能够在请求前和请求后附加一些行为,好比使用inteceptor在ajax请求时显示loading界面。面试

特色
  1. 体积小
    vue-resource很是小巧,在压缩之后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多。
  2. 支持主流的浏览器
    和Vue.js同样,vue-resource除了不支持IE 9如下的浏览器,其余主流的浏览器都支持。
  3. 支持Promise API和URI Templates
    Promise是ES6的特性,Promise的中文含义为“先知”,Promise对象用于异步计算。
    URI Templates表示URI模板,有些相似于ASP.NET MVC的路由模板。
  4. 支持拦截器
    拦截器是全局的,拦截器能够在请求发送前和发送请求后作一些处理。
    拦截器在一些场景下会很是有用,好比请求发送前在headers中设置access_token,或者在请求失败时,提供共通的处理方式。
经常使用api
  1. get(url, [options])
  2. head(url, [options])
  3. delete(url, [options])
  4. jsonp(url, [options])
  5. post(url, [body], [options])
  6. put(url, [body], [options])
  7. patch(url, [body], [options])
客户端请求方法 服务端处理方法
this.$http.get(...) Getxxx
this.$http.post(...) Postxxx
this.$http.put(...) Putxxx
this.$http.delete(...) Deletexxx
option详解
参数 类型 描述
url string 请求的URL
method string 请求的HTTP方法,例如:'GET', 'POST'或其余HTTP方法
body Object, FormData string request body
params Object 请求的URL参数对象
headers Object request header
timeout number 单位为毫秒的请求超时时间 (0 表示无超时时间)
before function(request) 请求发送前的处理函数,相似于jQuery的beforeSend函数
progress function(event) ProgressEvent回调处理函数
credentials boolean 表示跨域请求时是否须要使用凭证
emulateHTTP boolean 发送PUT, PATCH, DELETE请求时以HTTP POST的方式发送,并设置请求头的X-HTTP-Method-Override
emulateJSON boolean 将request body以application/x-www-form-urlencoded content type发送

4、fetch

  1. fetch是基于promise实现的,也能够结合async/await
  2. fetch请求默认是不带cookie的,须要设置fetch(URL,{credentials:’include’})。 
  3. Credentials有三种参数:same-origin,include,*
  4. 服务器返回400 500 状态码时并不会reject,只有网络出错致使请求不能完成时,fetch才会被reject
  5. 全部版本的 IE 均不支持原生 Fetch
  6. fetch是widow的一个方法
fetch(url).then(function(response) {
 return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function(e) {
  console.log("Oops, error");
});

        可配合es6的箭头函数进行使用ajax

fetch(url).then(response => response.json())
 .then(data => console.log(data))
 .catch(e => console.log("Oops, error", e))

5、axios

        Axios 是一个基于 promise 的 HTTP 库,能够用在浏览器和 node.js 中

特色
  • 从浏览器中建立XMLHttpRequests
  • 从 node.js 建立http请求
  • 支持PromiseAPI
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防护XSRF
经常使用api
  1. axios.request(config)
  2. axios.get(url[, config])
  3. axios.delete(url[, config])
  4. axios.head(url[, config])
  5. axios.options(url[, config])
  6. axios.post(url[, data[, config]])
  7. axios.put(url[, data[, config]])
  8. axios.patch(url[, data[, config]]
实例

get请求

// 为给定 ID 的 user 建立请求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可选地,上面的请求能够这样作
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

post请求

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

并发请求

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求如今都执行完成
  }));

拦截器

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求以前作些什么
    return config;
  }, function (error) {
    // 对请求错误作些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据作点什么
    return response;
  }, function (error) {
    // 对响应错误作点什么
    return Promise.reject(error);
  });

取消请求

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 处理错误
  }
});

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');

        固然,不管选择哪种方式都须要自身结合业务的须要和自个人认知,没有哪一个绝对的优秀,也没有哪一个绝对不优秀。根据自身的经验以及相关资料的查找,总结了《前端常见面试》这个系列 ,后续若是有更多的内容,我也会逐步去更新或者补充这个系列,指望可以对你们都有所帮助,欢迎你们转发和点赞关注。本系列的相关文章以下:

  1. 前端常见面试-css篇
  2. 前端常见面试-存储/缓存篇
  3. 前端常见面试-js篇
  4. 前端常见面试-进阶篇
  5. 前端常见面试-vue篇
相关文章
相关标签/搜索