1. 异步和同步
异步和同步:客户端和服务器端相互通信的基础上
- 同步:阻塞代码执行,即客户端必须等待服务器端的响应,在等待的期间客户端不能做其他操作。
- 异步:不阻塞代码执行,即客户端不需要等待服务器端的响应,在服务器处理请求的过程中,客户端可以进行其他的操作。
2. ajax:
1. 概念
Ajax:异步的JavaScript 和 XML(ASynchronous JavaScript And XML) 。Ajax是一种异步请求数据的web开发技术,在无需重新加载整个网页的情况下,Ajax 通过异步请求加载后台数据,能够更新部分网页。AJAX请求获取的是数据而不是HTML文档,因此它也节省了网络带宽,让互联网用户的网络冲浪体验变得更加顺畅。
Ajax技术的核心是XMLHttpRequest对象
2. XMLHttpRequest对象
XHR对象,用于与服务器交互数据,这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。XHR对象是ajax功能实现所依赖的对象,ajax就是对xhr对象的封装。
1. 创建XHR对象
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
2. XHR对象的核心方法
3. XHR对象的核心属性
(1). XMLHttpRequest.onreadystatechange属性
只要 readyState 属性发生变化,就会调用相应的回调函数进行处理。XMLHttpRequest.onreadystatechange 会在 XMLHttpRequest 的readyState 属性发生改变触发 readystatechange 事件的时候被调用。
- 用法:
XMLHttpRequest.onreadystatechange = callback;
当 readyState 的值改变的时候,callback 函数会被调用。
(2).XMLHttpRequest.readyState 属性
XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。
readyState属性可取值
0:未初始化。尚未调用open()方法
1:启动。已调用open()方法,但尚未调用send()方法
2:发送。已调用send()方法,但尚未接受到响应
3:接收。已接收到部分响应数据
4:完成。已接收到全部响应数据。而且客户端已经在使用了。
(3). XMLHttpRequest.status属性
(4). responseText / responseXML
如需获得来自服务器的响应,使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。
3. 原生js操作XHR对象,与后台服务器进行数据交互
//*******例:get请求*******
//1.创建XHR对象
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
//2. 建立连接
/*
参数:
2.1. 请求方式:GET、POST。。。
2.2. 请求的URL:
2.3. 同步或异步请求:true(异步)或 false(同步)
*/
xmlhttp.open("GET","ajaxServlet?username=tom",true);
//3.发送请求
xmlhttp.send();
//4.接受并处理来自服务器的响应结果
//当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange。
xmlhttp.onreadystatechange=function(){
//判断readyState就绪状态是否为4,判断status响应状态码
if (xmlhttp.readyState==4){
if((xmlhttp.status>=200&&xmlhttp.status<300)||xmlhttp.status==304){
//获取服务器的响应结果
var responseText = xmlhttp.responseText;
alert(responseText);
}else{
alert("失败");
}
}
}
4. 手写ajax ---- 封装XHR
/*
options的属性和方法:
url表示请求地址
method表示请求方法
async表示是否是异步请求
data表示请求参数
success()成功的回调
error()失败的回调
*/
function ajax(options){
//0.处理请求参数
const res = [];
for(var key in options.data){
res.push(key + "=" + data[key]);
}
let myParam = res.join("&")
//1.创建XHR对象
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if(options.method.toLowerCase() == 'get'){
//2. 建立连接
xmlhttp.open("GET",options.url+"?"+myParam,options.async);
//3.发送请求
xmlhttp.send();
}else{
//2. 建立连接
xmlhttp.open("POST",options.url,options.async);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded")
//3.发送请求
xmlhttp.send(myParam);
}
//4.接受并处理来自服务器的响应结果
//当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange。
xmlhttp.onreadystatechange=function(){
//判断readyState就绪状态是否为4,判断status响应状态码
if (xmlhttp.readyState==4){
if(xmlhttp.status>=200&&xmlhttp.status<300){
options.success(xmlhttp.responseText);
}else{
options.error(xmlhttp.responseText);
}
}
}
}
//***********调用自己封装的ajax*************
ajax({
//请求的url地址
url:"http://www.microsoft.com",
//请求方式
method:"POST",
//请求是否异步,默认为异步,这也是ajax重要特性
async:true,
//参数值
data:{"id":"value"},
success:function(req){
//请求成功时处理
},
error:function(req){
//请求出错处理
}
});
5. jquery中的ajax使用
- jquery中的ajax使用
$.ajax({ //请求的url地址 url:"http://www.microsoft.com", //请求方式 type:"POST", //请求是否异步,默认为异步,这也是ajax重要特性 async:true, //参数值 data:{"id":"value"}, //返回格式为json dataType:"json", beforeSend:function(){ //请求前的处理 }, success:function(req){ //请求成功时处理 }, complete:function(){ //请求完成的处理 }, error:function(){ //请求出错处理 } });
3. axios
axios是前端最流行的ajax请求库,是对ajax的再次封装
(1). axios特点 / 优点
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防止CSRF
(2). vue项目中简单使用axios
-
结合vue-axios使用
vue-axios用于将axios集成到Vuejs的小包装器//1. 安装 /* npm install --save axios npm install --save vue-axios */ //2. 在主入口文件main.js中引用 import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios,axios); //3. 使用axios ------- this.axios //例: methods:{ getNewsList(){ this.axios.get('api/getNewsList').then((response)=>{ this.newsList=response.data.data; }).catch((response)=>{ console.log(response); }) } }
-
axios 改写为 Vue 的原型属性
//1. 安装 /* npm install --save axios */ //2. 在主入口文件main.js中引用 import axios from 'axios' //3. axios挂在vue的原型链上 Vue.prototype.$axios= axios //3. 使用axios ------- this.$axios //例: methods:{ getNewsList(){ this.$axios.get('api/getNewsList').then((response)=>{ this.newsList=response.data.data; }).catch((response)=>{ console.log(response); }) } }
(3). vue中axios封装(全局请求处理)以及api接口统一管理
1. 如何封装axios
- 在src目录下新建一个request.js文件,引入axios并对其进行封装。
- 创建axios实例
- 根据不同的项目环境比如开发环境、测试环境和生产环境,设置axios的baseUrl
- 设置请求超时时间
- 设置请求头
- 设置请求和响应拦截,可以在响应拦截中对一些请求错误做一些处理。
- 最后将axios实例暴漏出来。
// 简单示例
import axios from 'axios'
import { Message } from 'element-ui'
// 创建axios实例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
timeout: 30000 // 请求超时时间
})
// request拦截器
service.interceptors.request.use(config => {
// 判断是否有token[是否登陆了]
if (token) {
config.headers['Authorization'] = token // 让每个请求携带自定义token 请根据实际情况自行修改
config.headers['Accept'] = 'application/json'
}
return config
}, error => {
console.error(error) // for debug
Promise.reject(error)
})
// respone拦截器
service.interceptors.response.use(
response => {
// 什么状态码能进到这里?
if (response.status === 200 || response.status === 201 || response.status === 204) {
return response.data
} else {
console.warn(response)
const res = response
Message({
message: res.code + res.message,
type: 'error',
duration: 1.5 * 1000
})
}
const res = response.data
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload()// 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject('error')
} else {
return response.data
}
},
error => {
console.warn('err in service.interceptors.response' + error)
return Promise.reject(error)
}
)
export default service
2. 如果后端 token 失效,你会怎么做
项目中若前端未对token过期进行处理,token过期后仍然会停留在原页面,用户可以进行一系列的操作。但是由于后端有进行token过期的判断,会造成用户的所有请求报401错误。一般vue项目会对axios进行封装,在项目中src\utils目录下的request.js文件中进行错误处理,与后端商议好token过期的错误状态码,然后进行判断即可。
(4). axios拦截器
- axios作用流程
<script>
/*
axios请求响应拦截器语法
// 添加请求拦截器
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);
});
*/
/*
* 手动实现axios拦截器的大概逻辑
*/
function axios(){
this.interceptors = {
//InterceptorsManager就是拦截器对象构造函数
request:new InterceptorsManager(),
response:new InterceptorsManager()
}
}
axios.prototype.request = function(){
// chain是一个数组,存储整个axios作用流程的所有操作,dispatchRequest是真正的请求操作
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve();
// 请求拦截器处理
this.interceptors.request.handler.forEach((interceptor)=>{
//请求拦截器处理放在真正的请求之前
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 响应拦截器处理
this.interceptors.response.handler.forEach((interceptor)=>{
//响应拦截器处理放在真正的请求之后
chain.push(interceptor.fulfilled, interceptor.rejected);
});
//遍历chain数组,使用promise链式调用依次执行所有操作
while(chain.length){
promise = promise.then(chain.shift(),chain.shift());
}
return promise;
}
function InterceptorsManager(){
//存储拦截器设置的处理
this.handler = [];
}
InterceptorsManager.prototype.use = function(fullfilled,rejected){
this.handler.push({
fullfilled:fullfilled,
rejected:rejected
})
}
/*
* axios请求方法注册
* axios所有请求都是调用request方法来实现的
*/
const methods = ['get','post','delete'];
methods.forEach((method)=>{
axios.prototype[method] = function(){
//调用axios的request方法
this.request(method)
}
})
</script>
4. fetch
fetch是一种HTTP数据请求的方式,是浏览器提供原生的api,是XMLHttpRequest的一种替代方案。fetch不是ajax的进一步封装,而是原生js。
一、fetch优势:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 比较底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
二、fetch存在问题
- fetch是一个原生的API,所以使用起来并不是那么舒服,需要进行封装。
- fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
- fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
- fetch不支持中断请求,也不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
- fetch没有办法原生监测请求的进度,而XHR可以
umi-request
umi-request 是基于 fetch 封装的开源 http 请求库
5. 面试相关
- 前端发请求的技术有哪些?阐述他们的优缺点有哪些?
axios和fetch
一、axios特点 / 优点
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防止CSRF
二、fetch优势:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 比较底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
三、fetch存在问题
- fetch是一个原生的API,所以使用起来并不是那么舒服,需要进行封装。
- fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
- fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
- fetch不支持中断请求,也不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
- fetch没有办法原生监测请求的进度,而XHR可以