客户端服务器端通信方式ajax (ajax JQ的类库 /axios类库) /jsonp / fetch
fetch是Es6新提供的API:基于不同于XMLHttpRequest的方式,基于客户端和服务器端的数据通信,而且本身是基于promise管理请求结果的(发送请求返回promi实例)
语法:
Promise<Response> fetch(input[, init]); :返回promise实例 input:URL地址 init:配置项
fetch目前不如XMLHttpRequest的机制完善(例如fetch中没有设置请求超时和请求中断的方法)
Response内置类
Response.prototype
这些方法的目的是:把body可读流对象解析出指定格式的数据 例如调用Response.json()会返回一个json格式对象的数据
执行方法会返回一个全新的promise,实例存储的值是想要的数据:服务器返回的响应主体内容有很多,当我们想执行某个方法转换为想要格式的时候,可能会成功,也可能会失败,所以在次基于promise管理
Headers内置类
headers:Headers内置类的实例对象(可以对请求头响应头信息做管理)
ReadableStream内置类
body:ReadableStream内置类的实例对象(可读流 存储服务器返回的响应主体信息)
init 配置项
一个配置项对象,包括所有对请求的设置。可选的参数有:
[扫盲] 客户端基于请求主体传递给服务器的格式
代码
import { Message } from 'element-ui';
//创造一个中断控制器
let controller = new AbortController();
//自定义请求头信息{Headers对象 & 普通对象}
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded')
headers.append('name', 'lisa')
fetch('/api/getTaskList', {
method: 'GET',//请求方式:GET*/POST/DELETE/HEAD/PUT...
headers,//设置请求头信息
body: '',//设置请求主体信息(只有post系列请求才可以设置,get系列请求会报错,格式有要求:json字符串,URLENCODED格式字符串,普通字符串,FormData格式对象,Buffer/bolb格式...不能是普通对象,并且要根据请求主体的数据格式,配置相关的请求头(Content-Type)
credentials: 'include',//是否允许携带资源凭证 include(同源跨域都允许)same-origin(同源才允许)omit都不允许
//给fetch请求设置信号器
signal: controller.signal
})
.then(response => {
let { status, statusText } = response;
if (!/^2\d{2}$/.test(status)) {
//失败:状态码不对
return Promise.reject({
code: 100,
status,
statusText
});
}
//转换如果失败,走到catch,转换成功走下一个THEN
return response.json().catch(resone => {
return Promise.reject({
code: 200,
message: resone.message
});
});
})
.then(value => {
console.log('成功', value);
})
.catch(resone => {
//状态码不是2开始的[code=100],转换响应主体格式失败[code=200],请求中断[code=20],断网
let { code, status } = resone || {};
if (code === 100) {
switch (+status) {
case 404:
Message.error('请求地址错误');
//...
}
} else if (code === 200) {
Message.error('请求格式转换失败');
} else if (code === 20) {
Message.error('请求中断');
} else {
Message.error('网路出现异常');
}
});
//中断请求
// controller.abort();
封装request([config])
// 核心方法
// 快捷方法
import qs from 'qs';
import { isPlainObject } from '../assets/utils';
import { message } from 'antd';
/* 核心方法 */
const http = function http(config) {
// init config & validate
if (!isPlainObject(config)) config = {};
config = Object.assign({
url: '',
method: 'GET',
credentials: 'include',
headers: null,
body: null,
params: null,
responseType: 'json',
signal: null
}, config);
if (!isPlainObject(config.headers)) config.headers = {};
if (config.params !== null && !isPlainObject(config.params)) config.params = null;
let { url, method, credentials, headers, body, params, responseType, signal } = config;
// 处理URL:params存在,我们需要把params中的每一项拼接到URL末尾
if (params) url += `${url.includes('?') ? '&' : '?'}${qs.stringify(params)}`;
// 处理请求主体:只针对于POST系列请求;body是个纯粹对象,根据当前后台要求,把其变为urlencoded格式!
if (isPlainObject(body)) {
body = qs.stringify(body);
headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
// 类似于Axios的请求拦截器,例如:把存储在客户端本地的token信息携带给服务器「根据当前后台要求处理」
let token = localStorage.getItem('token');
if (token) headers['authorzation'] = token;
// 发送请求
method = method.toUpperCase();
config = {
method,
credentials,
headers,
cache: 'no-cache',
mode: 'cors'
};
if (/^(POST|PUT|PATCH)$/i.test(method) && body) config.body = body;
if (signal) config.signal = signal;
return fetch(url, config).then(response => {
// 成功则返回响应主体信息
let { status, statusText } = response,
result;
if (!/^(2|3)\d{2}$/.test(status)) return Promise.reject({ code: -1, status, statusText });
switch (responseType.toLowerCase()) {
case 'text':
result = response.text();
break;
case 'arraybuffer':
result = response.arrayBuffer();
break;
case 'blob':
result = response.blob();
break;
default:
result = response.json();
}
return result.then(null, reason => Promise.reject({ code: -2, reason }));
}).catch(reason => {
// 根据不同的失败情况做不同的统一提示
/* let code = reason?.code;
if (+code === -1) {
// 状态码问题
switch (+reason.status) {
case 404:
// ...
break;
}
} else if (+code === -1) {
// 读取数据出现问题
} else if (+code === 20) {
// 请求被中断
} else {
// 网络问题
} */
message.error('小主,当前网络出现异常,请稍后再试~~');
return Promise.reject(reason);
});
};
/* 快捷方法 */
['GET', 'HEAD', 'DELETE', 'OPTIONS'].forEach(item => {
http[item.toLowerCase()] = function (url, config) {
if (!isPlainObject(config)) config = {};
config['url'] = url;
config['method'] = item;
return http(config);
};
});
['POST', 'PUT', 'PATCH'].forEach(item => {
http[item.toLowerCase()] = function (url, body, config) {
if (!isPlainObject(config)) config = {};
config['url'] = url;
config['method'] = item;
config['body'] = body;
return http(config);
};
});
export default http;