关于对axios和Fetch在vue中数据请求的理解

122 阅读10分钟

1. Axios 的使用

www.axios-js.com/zh-cn/docs/
axios:基于promise封装的ajax库,基于这个类库发送ajax请求,默认就是基于promise管理的,核心还是XMLHttpRequest
axios.get/head/delete/options 发送对应类别请求的方法

1. GET系列

		//axios.get(url[,config])  返回Promise的实例,可以用then catch async await
		// url: 请求网址 必须写
		// config: 配置项(对象) 可有可无
		//    baseURL:基础路径
		//    params: get类请求的参数 对象(自动将参数拼接url后面)
		//    timeout:请求超时时间
		//    withCredentials: false  是否允许携带跨域资源凭证 默认false
		//    responseType: 'json', 自动转化返回的数据格式 默认json
		//    validateStatus: function (status) {
		//       return status >= 200 && status < 300; // default
		//    },状态码成功的范围
		//    onUploadProgress:监控文件上传进度
		//    onDownloadProgress:监控文件下载进度

GET系列 axios.get([url],[config]) 请求URL地址、配置项


			
			axios.get("/api/articleList",{
				baseURL:"http://localhost:8888",
				params:{
					date:"2021-05-21"
				},
				timeout:1000,
				withCredentials:false,
				validateStatus: function (status) {
				    return status >= 200 && status < 400; 
				}
			}).then(value=>{
				console.log(value);
			})

配置项:

  1. params:[string/object] 基于问号参数方案,需要传递给服务器的信息;

如果传递的是个对象,axios内部会把对象变为 xxx=xxx&xxx=xxx 这样的字符串,然后基于问号参数传递给服务器;如果写的是一个字符串,则变为 0=字符串 的方式传递给服务器;我们一般都使用对象的方式!!

axios.get('http://127.0.0.1:9999/user/list', {
			    params:"zhufeng"
			})

axios.get('http://127.0.0.1:9999/user/list', {
			    params: {
			        departmentId: 0,
			        search: ''
			    }
	})


2.timeout:[number] 设置超时时间 写零是不设置,单位是MS

axios.get('http://127.0.0.1:9999/user/list', {
			    params: {
			        departmentId: 0,
			        search: ''
			    },
				timeout:0
		})
 3. withCredentials:[boolean] 跨域请求中是否允许携带资源凭证  默认是false<br />     4. responseType:[string] 把服务器返回的结果转换为对应的数据格式  默认是json「服务器返回的结果,我们都把其变为JSON格式的对象」、'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'<br />     5. onUploadProgress:[function] 监听文件上传的进度<br />     ----<br />     6. baseURL:[string] 请求地址的公共前缀<br />     7. validateStatus:[function] 预设服务器返回的HTTP状态码是多少才算请求成功,默认是以2开始的算成功

2.POST系列

axios.post/put/patch 发送对应类别请求的方法
POST系列 axios.post([url],[data],[config]) 请求URL地址、请求主体信息、配置项

axios.post(url,data[,config]) 返回Promise的实例
url: 请求网址 必须写
data: post类传递的参数 可有可无 对象 字符串
config: 配置项(对象) 可有可无
baseURL:基础路径
timeout:请求超时时间
withCredentials: false 是否允许携带跨域资源凭证 默认false
responseType: 'json', 自动转化返回的数据格式 默认json
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},状态码成功的范围
onUploadProgress:监控文件上传进度
onDownloadProgress:监控文件下载进度
headers:设置请求头信息
(大多数情况下,根据参数传递的格式,自动设置Content-Type的值)
transformRequest: 在发送参数之前,可以统一对参数进行处理


//问题:参数是对象格式,需求urlencoded格式
//方法1:参数直接改为urlencoded   不推荐
axios.post("/user/login",
					 "account=18310612838&password=" + md5("1234567890"), {
						 baseURL: "http://127.0.0.1:9999",
						 // headers: {
						 // 	"Content-Type": "application/x-www-form-urlencoded"
						 // },
						 timeout: 1000,
						 withCredentials: false,
						 validateStatus: function(status) {
							 return status >= 200 && status < 400; // default
						 }
					 }).then(value => {
	console.log(value.data);
})

//方法2:参数直接传对象
axios.post("/user/login", {
	account: "18310612838",
	password: md5("1234567890")
}, {
	baseURL: "http://127.0.0.1:9999",
	timeout: 1000,
	withCredentials: false,
	validateStatus: function(status) {
		return status >= 200 && status < 400; // default
	},
	transformRequest: function(data) { //只支持 post put patch
		//console.log(data);
		//Qs.stringify() 将普通对象转化为urlencoded格式
		//console.log(Qs.stringify(data));
		return Qs.stringify(data); //return的结果,就是新参数的值,格式
	}
}).then(value => {
	console.log(value.data);
})

请求主体信息:
1. 我们DATA(请求主体)写的是一个对象,内部默认处理成为JSON格式的字符串,然后传递给服务器「因为:用AJAX基于请求主体传递给服务器的内容格式有限制 字符串{URLENCODED格式、JSON格式、普通...}、ArrayBuffer、Blob、FormData格式对象」

axios.post('http://127.0.0.1:9999/user/login', {
			    account: '18310612838',
			    password: '1234567890'
			})

  1. 如果服务器要求传递的格式不是JSON字符串,我们可以给DATA设置值是自己想要的字符串格式
axios.post('http://127.0.0.1:9999/user/login',
           `account=18310612838&password=${md5("1234567890")}`)
  ![](https://cdn.nlark.com/yuque/0/2022/png/32544531/1668139699521-467c167c-2cba-4858-813d-56d883dc5b41.png#averageHue=%23f9faf9&height=57&id=PASkV&originHeight=67&originWidth=503&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=425)

  如果要求传递的是 urlencoded 格式字符串,我们可以基于 Qs.stringify/parse 进行处理「引入QS库」<br />![](https://cdn.nlark.com/yuque/0/2022/png/32544531/1668139699816-b6f78eb5-c452-4ef3-a99a-2119fe07b418.png#averageHue=%23f9f4ef&id=LVMEP&originHeight=176&originWidth=512&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)

   
let data={
	account: '18310612838',
	password: '1234567890'
			}
axios.post('http://127.0.0.1:9999/user/login',Qs.stringify(data));

还有一种方法:transformRequest

  1. headers:[object] 设置请求头信息,例如:headers:{ 'Content-Type': 'application/x-www-form-urlencoded' } 设定客户端传递给服务器的内容格式是urlencoded格式
axios.post("http://127.0.0.1:9999/user/login",{
				account:"13041086186",
				password:md5("1234567890")
			},{
				transformRequest: data => {
				    if (isPlainObject(data)) return Qs.stringify(data);
				    return data;
				},
				headers:{ 'Content-Type': 'application/x-www-form-urlencoded'}
			})

配置项:
1.与GET系列一样,但是没有params
2.transformRequest:[function] POST系列,对请求主体的数据进行格式化处理

  专门是用来处理POST请求,请求主体的数据格式的<br />      + data传递的依然是个对象格式「常用写法」<br />      + transformRequest:(data,headers)=>{ return xxx; }
axios.post('http://127.0.0.1:9999/user/login', {
    account: '18310612838',
    password: md5('1234567890')
}, {
    transformRequest: data => {
        // data:我们传递的这个对象
        // return什么值,就是把其基于请求主体专递给服务器
        // 必须是纯粹的对象 
        if (isPlainObject(data)) return Qs.stringify(data);
        return data;
    }
})

// 对象.proto===Object.prototype Object.create(null)是纯粹对象

const isPlainObject = function isPlainObject(obj) {
    let proto, Ctor;
    if (!obj || Object.prototype.toString.call(obj) !== "[object Object]") return false;
    proto = Object.getPrototypeOf(obj);
    if (!proto) return true;
    Ctor = proto.hasOwnProperty('constructor') && proto.constructor;
    return typeof Ctor === "function" && Ctor === Object;
};

-------------------注释
  // 定义一个函数 isPlainObject,用于判断传入的参数是否是一个普通对象
const isPlainObject = function isPlainObject(obj) {
    let proto, Ctor; // 声明两个变量用于存储对象的原型和构造函数

    // 如果传入的参数是 null、undefined 或者不是对象类型,则直接返回 false
    if (!obj || Object.prototype.toString.call(obj) !== "[object Object]") return false;

    // 获取传入对象的原型
    proto = Object.getPrototypeOf(obj);

    // 如果原型不存在,则说明传入的对象是一个普通对象,直接返回 true
    if (!proto) return true;

    // 判断原型对象是否有 constructor 属性,并获取该属性的值赋给 Ctor
    Ctor = proto.hasOwnProperty('constructor') && proto.constructor;

    // 判断 Ctor 是否是一个函数且是否等于 Object 构造函数,如果是则返回 true,否则返回 false
    return typeof Ctor === "function" && Ctor === Object;
};

3.其他:

1.加密:md5

2. AXIOS内部做了一个非常有用的事情:

根据我们传递给服务器的内容格式,自动帮我们设置请求头中的 Content-Type ,让其和传递的格式相匹配「MIME类型」
urlencoded格式字符串 Content-Type:'application/x-www-form-urlencoded'
json格式字符串 Content-Type:'application/json'
FormData格式对象 Content-Type:'multipart/form-data'

axios.post('http://127.0.0.1:9999/user/login', {
    account: '18310612838',
    password: md5('1234567890')
}, {
    transformRequest: data => {
        // data:我们传递的这个对象
        // return什么值,就是把其基于请求主体专递给服务器
        if (isPlainObject(data)) return Qs.stringify(data);
        return data;
    }
}).then(response => {
    return response.data;
}).then(value => {
    console.log('请求成功', value);
}).catch(reason => {
    // 根据不同的情况做不同提示
});

3.基于axios发送的请求,返回结果都是promise实例

  • 数据请求成功会让promise状态为成功,promise值就是从服务器获取的结果
    + 数据请求失败会让promise状态为失败
    + 服务器有响应信息,但是状态码不是以2开始的:reason对象中有response属性,存储服务器返回的信息
    + 请求超时或者被中断 code:"ECONNABORTED" response:undefined
    + 断网了 navigator.onLine=false(断网)
axios.get('http://127.0.0.1:9999/user/list', {
    timeout: 1,
    params: {
        departmentId: 0,
        search: ''
    }
}).then(response => {
    console.log('请求成功:', response);
    // response对象
    //   + status/statusText HTTP状态码及其描述
    //   + request 原生的XHR对象
    //   + headers 存储响应头信息(对象)
    //   + config 存储发送请求时候的相关配置项
    //   + data 存储响应主体信息
    return response.data;
}).then(value => {
    console.log('响应主体信息:', value);
}).catch(reason => {
    console.log('请求失败:');
    console.dir(reason);
}); 
axios({
        method: 'get',
        url:'http://127.0.0.1:9999/user/list',
        params:{id:1},
        headers:{},
...
    }).then(res=>{
        console.log(res);
})
axios({
        method: 'post',
        url:'http://127.0.0.1:9999/user/list',
        data:{id:1},
        headers:{},
....
    }).then(res=>{
        console.log(res);
})

2. Axios的二次配置

把多个请求之间公共的部分进行提取,后期在业务中再次发送数据请求,公共部分无需再次编写

  • axios.defaults.xxx 默认配置
    + axios.interceptors.request/response 请求/响应拦截器

1.请求地址的公共前缀:这样后期再发请求的时候,URL地址中公共前缀部分就不需要写了
原理:请求URL地址不含“http(s)://”,发送请求的时候会把baseURL拼上去,然后再发请求;如果自己的URL包含了“http(s)://”这个部分,则以自己的为主,就不在去拼接baseURL了;

axios.defaults.baseURL = 'http://127.0.0.1:9999';

2.根据当前服务器的要求,对于POST系列请求,请求主体传递给服务器的格式都是:urlencoded格式字符串

axios.defaults.transformRequest = data => {
    if (isPlainObject(data)) return Qs.stringify(data);
    return data;
};

3.配置公共超时时间

axios.defaults.timeout = 60000;

4.配置公共跨域请求中是否允许携带资源凭证(允许)

axios.defaults.withCredentials = true

5.校验服务器返回状态码为多少才算请求成功:默认以2开始才算

axios.defaults.validateStatus = status => {
    return status >= 200 && status < 400;
};

6.基于拦截器进行公共部分提取
+ 请求拦截器:发生在 “配置项准备完毕” 和 “发送请求” 之间
+ 响应拦截器:发生在 “服务器返回结果” 和 “业务代码自己处理 .then” 之间

axios.interceptors.request.use(config => {
  // config对象包含的就是准备好的配置项,最后返回啥配置,就按照这些配置发请求
    return config;
});
axios.interceptors.response.use(response => {
    // 请求成功:把响应主体信息返回给业务层去使用
    return response.data;
}, reason => {
    // 请求失败:根据不同的失败原因做不同的提示
    if (reason && reason.response) {
        // @1 有返回结果,只不过状态码不对
        let {
            status
        } = reason.response;
        switch (+status) {
            case 403:
                alert('服务器不爱搭理你~~');
                break;
            case 404:
                alert('你傻啊,地址都错了~~');
                break;
            case 500:
                alert('服务器开小差了~~');
                break;
        }
    } else {
        // @2 请求超时或者中断 
        if (reason && reason.code === "ECONNABORTED") {
            alert('请求超时或者被中断了~~');
        }
        // @3 断网
        if (!navigator.onLine) {
            alert('当前网络出问题了~~');
        }
    }
    // 统一失败提示处理完,到业务代码处,我们还是要失败的状态,这样才能继续做一些自己单独想做的失败处理
    return Promise.reject(reason);
});

3.Fetch 的使用


developer.mozilla.org/zh-CN/docs/…
www.ruanyifeng.com/blog/2020/1…

  • omit:从不发送cookie。
  • same-origin:如果URL与调用脚本位于相同的源,则发送用户凭证(cookie,基本http认证等)。
  • include:始终发送用户凭据(cookie,基本http认证等),甚至用于跨源调用。
fetch('http://127.0.0.1:9999/user/list?departmentId=0&search=',{
				method: 'GET',
				headers: {},//请求头信息
				// 必须是字符串 或者 对象
				// body: JSON.stringify({id:1})// post参数
			}).then(function(response) {
				//需要使用fetch提供的json方法转化一下
				//注意:.json()和.text()方法只能执行一次
				//console.log(response.json());
				//数据放在promise,需要再.then
			    return response.json();
			}).then(function(myJson) {
			    console.log(myJson);
			});

fetch('./data.json').then(response => {
    // response中包含了服务器返回的信息:响应主体信息response.body「ReadableStream可读流信息」,我们需要把可读流信息变为指定的格式
    //   + Response.prototype.json/text/blob(文件流格式)/arrayBuffer(buffer)...
    //   + 执行这些方法中的任何一个,返回结果都是一个promise实例:如果可以把响应主体信息正常转换为指定的格式,则promise的状态是fulfilled、值是转换为的数据内容,如果不能正常转换,则状态是失败的...
    //   + 一但执行了其中的一个方法,再执行其他方法,会出问题
    return response.json();
}).then(value => {
    console.log(value);
});

fetch和axios的区别
他俩都是发送请求的
axios是基于promise封装的ajax类库
fetch是浏览器原生的API
传参字段不一样,axios是放在params或者data里,fetch(post)是放在body里
node环境中不支持fetch,需要引入node-fetch文件才能支持
axios中的配置和拦截器等功能,fetch中都没有。