/* * @Author: Pengjiantian * @Date: 2020-02-27 16:45:21 * @Last Modified by: Pengjiantian * @Last Modified time: 2020-02-27 16:45:21 */ // 基础请求封装 export default class BaseFetch { /** * constructor 构造函数 * @param {Object} conf 实例全局配置,配置项基本同 defaultConf */ constructor(conf = {}) { this.defaultConf = { timeout: 30000, method: 'post', headers: { 'Content-Type': 'application/json;charset=UTF-8' } } this.specialBodyKeys = ['body', 'method', 'headers'] this.init(conf) } /** * 初始化,合并配置 * @param {Object} conf 全局配置 */ init(conf) { const { defaultConf } = this this.conf = Object.assign({}, { ...defaultConf }, { ...conf }) } /** * post 请求处理 * @param {String} api 接口地址 * @param {Object|String} body 请求参数 * @param {Object} conf 请求配置信息 */ toPost(api, body = {}, conf = {}) { return this.toFetch(api, body, { method: 'post', ...conf }) } /** * get 请求处理 * @param {String} api 接口地址 * @param {Object|String} body 请求参数 * @param {Object} conf 请求配置信息 */ toGet(api, body = {}, conf = {}) { return this.toFetch(api, body, { method: 'get', ...conf }) } /** * mixConf 合并配置项 * @param {Object} conf 请求配置项 * @param {Object} body 参数或包含参数的配置项 @example {data: {name: 'someone'}} * @param {Object} conf 请求配置信息 */ mixConf(api, body = {}, conf = {}) { const { specialBodyKeys } = this let mixConf = { ...this.conf, ...conf } if (typeof body === 'string') { mixConf = { ...mixConf, body } } if (typeof body === 'object') { // body包含配置项,则body为配置信息 if (Object.keys(body).some(key => specialBodyKeys.includes(key))) { mixConf = { ...mixConf, ...body } } else { mixConf = { ...mixConf, body } } } const { method, body: mixBody, headers, ...other } = mixConf const url = this.getUrl(api, mixConf) let result = headers === false ? { url, method, ...other } : { url, method, headers, ...other } if (method.toLocaleLowerCase() !== 'get') { result = { ...result, body: this.getBody(mixConf) } } return result } /** * joinPath拼接路径,去重中间重复连接符/ * @param {Array} pathArr 路径数组 * @param {Boolean} isReplaceFirst 是否去除第一个路径前的/ */ joinPath(pathArr, isReplaceFirst = false) { return pathArr.reduce((pre, curr, index) => { const nextPath = curr.replace(/^\/+/, '') curr = index === 0 && !isReplaceFirst ? curr : nextPath pre = pre === '' ? curr : `${pre.replace(/\/+$/, '')}/${nextPath}` return pre }, '') } /** * getUrl 获取请求url完整地址 * @param {String} api请求地址 * @param {Object} mixConf 混入后的请求配置 */ getUrl(api, mixConf) { const { method, body } = mixConf if (method.toLocaleLowerCase() === 'get') { const str = this.getUrlbody(api, body) api = api.includes('?') ? `${api}&${str}` : `${api}?${str}` } return api } /** * getUrlbody 拼接url字符串 * @param {String} api 接口地址 * @param {Object|String} body 请求参数 * @param {Object} conf 请求配置信息 */ getUrlbody(api, body) { if (typeof body === 'object') { body = Object.keys(body).reduce((pre, curr) => { const val = typeof body[curr] === 'object' ? JSON.stringify(body[curr]) : body[curr] pre = pre === '' ? pre : `${pre}&` pre = `${pre}${curr}=${val}` return pre }, '') } return body } /** * getBody 根据headers信息, * @param {Object} mixConf 请求配置项 */ getBody(mixConf) { let { body, headers } = mixConf if (typeof headers === 'object') { Object.keys(headers).forEach(key => { if (key.toLocaleLowerCase() === 'content-type') { // json string if ( headers[key].includes('application/json') && typeof body !== 'string' ) { body = JSON.stringify(body) } // body if (headers[key].includes('application/x-www-form-urlencoded')) { body = this.getUrlbody(body) } // file if ( headers[key].includes('multipart/form-data') && !(body instanceof FormData) ) { const formData = new FormData() Object.keys(body).forEach(key => { formData.append(key, body[key]) }) } } }) } return body } /** * 请求统一入口 * @param {String} api 接口地址 * @param {Object|String} body 请求参数 * @param {Object} conf 请求配置信息 */ toFetch(api, body = {}, conf = {}) { const { url, ...other } = this.mixConf(api, body, conf) return new Promise((resolve, reject) => { fetch(url, other).then(res => { if (res.ok) { resolve(res.json()) } reject(new Error(`接口:${url},请求异常!`)) }) }) } }