首先先来讲一下为何要用fetch而不是axios吧,主要有如下两点:前端
为何要单独说一下fetch的response呢,我的认为这一点既是fetch的缺点又是fetch的优势,咱们先来对比一下正常的请求fetch和axios的区别node
// fetch
fetch(url)
.then(res => { // 第一层res
res.json() // 须要json事后才是咱们想要的数据
.then(r => { // 第二层res
console.log(r) // 获取到最后数据
})
});
// axios
axios(url)
.then(res=>{ // 第一层res
console.log(res); // 获取到咱们想要的数据
});
复制代码
如上面所示,咱们须要先对fetch的res进行res.json()以后才拿到咱们想要的json数据,而axios帮咱们作了,使用起来更简单~react
这算是一个缺点吧~可是!!!咱们经过封装彻底能够解决的,接下来就是为啥这也是fetch的优势了,首先来讲说为啥fetch须要两层才能够,第一层进行的是res.json(),由于fetch的response是一个综合各类方法的对象,并非请求的数据,也就是说其实fetch不只能够是一个json对象,还能够是其余不少的,若是咱们须要的是json对象,就res.json(),若是须要的是文本字符串,能够res.text(),它还能够直接获取blob内容,res.blob()。综上所述,fetch是真的真的很强大,就看你擅不擅长封装使用了。ios
事先声明,我上面吹了那么久,其实我我的以为我也不算太会使用哈,下面的封装也就是简单的封装,各位看官按需使用,能够在我基础之上针对本身的项目进行更好的封装,或者就直接本身封装就能够了。git
上面讲了fetch的几个缺点,其实这些缺点都是能够经过封装以及插件来进行弥补的。github
import fetch from 'isomorphic-unfetch';
import qs from 'query-string';
import { filterObject } from './util';
// initial fetch
const nextFetch = Object.create(null);
// browser support methods
// ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PATCH', 'PUT']
const HTTP_METHOD = ['get', 'post', 'put', 'patch', 'delete'];
// can send data method
const CAN_SEND_METHOD = ['post', 'put', 'delete', 'patch'];
HTTP_METHOD.forEach(method => {
// is can send data in opt.body
const canSend = CAN_SEND_METHOD.includes(method);
nextFetch[method] = (path, { data, query, timeout = 5000 } = {}) => {
let url = path;
const opts = {
method,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json'
},
credentials: 'include',
timeout,
mode: 'same-origin',
cache: 'no-cache'
};
if (query) {
url += `${url.includes('?') ? '&' : '?'}${qs.stringify(
filterObject(query, Boolean),
)}`;
}
if (canSend && data) {
opts.body = qs.stringify(filterObject(data, Boolean));
}
console.info('Request Url:', url);
return fetch(url, opts)
.then(res => res.json())
.then(({ errcode = 0, errmsg, data }) => {
if (errcode !== 0) {
const err = new Error(errmsg);
err.message = errmsg;
err.code = errcode;
err.data = data;
throw err;
}
return data;
});
};
});
export default nextFetch;
复制代码
封装完以后的使用:express
// /redux/sagas/user/userList.js
...
import nextFetch from '../../../core/nextFetch';
export function* userList() {
while (true) {
yield take(FETCH_USER_LIST);
try {
// 新写法
const data = yield nextFetch.get(api.getUserList);
// 原来的写法
// const res = yield fetch(api.getUserList);
// const { data } = yield res.json();
yield put(fetchUserListDataSuccess(data));
} catch (error) {
console.log(error.code, error.message, error.data);
yield put(fetchUserListDataFali(error));
}
}
}
复制代码
为何使用的是
isomorphic-unfetch
, 由于Next.js是服务端渲染,这个标榜的是先后端都通用~之前我用的服务端渲染框架由于是分离的,先后端使用的是不一样的fetch(前端是whatwg-fetch,后端是node-fetch)。json
上面是我本身的封装方式,我默认后端返回的是一个json格式的数据,而后里面有三个字段
{ data, errcode, errmsg }
,而且成功的响应code = 0
。小伙伴们根据本身的项目结构适当进行更改。redux
这个就很简单了,redux的中间件系统,为何增长中间件呢,由于上面咱们增长了fetch的error处理,那么咱们就能够对失败的请求在中间件这个地方进行提早处理~axios
// /redux/store.js
import userMiddleware from '../middlewares/client/user';
...
// 增长redux中间件
const bindMiddleware = (middleware) => {
// add route middleware
middleware.push(userMiddleware);
...
return applyMiddleware(...middleware);
};
// /middles/client/user.js
import { message } from 'antd';
import {
FETCH_USER_LIST_FAIL
} from '../../constants/ActionTypes';
export default ({ getState }) => next => action => {
// redux中间件
const ret = next(action);
switch (action.type) {
case FETCH_USER_LIST_FAIL: {
message.error('获取用户列表失败, 请稍后重试');
break;
}
default:
}
return ret;
};
复制代码
效果如图所示:
今天这个就很简单了,也不是什么高级的东西,都是随手拿来用的,只不过封装起来方便使用一些,感受这个脚手架到这真的能够直接进行项目的开发了,可能还差一个前端日志功能吧,下面有时间写写前端日志~