UNPKG

mux-fetch

Version:
359 lines (307 loc) 10 kB
/*! * mux-fetch.js v0.0.1-alpha.15 * (c) 2018-2019 空鱼 * Released under the MIT License. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('mux-lib'), require('isomorphic-fetch')) : typeof define === 'function' && define.amd ? define(['exports', 'mux-lib', 'isomorphic-fetch'], factory) : (global = global || self, factory(global['mux-fetch'] = global['mux-fetch'] || {}, global.muxLib, global.defaultFetch)); }(this, (function (exports, muxLib, defaultFetch) { 'use strict'; defaultFetch = defaultFetch && defaultFetch.hasOwnProperty('default') ? defaultFetch['default'] : defaultFetch; function compose(...funcs) { if (funcs.length === 0) { return muxLib.returnSelf; } if (funcs.length === 1) { return funcs[0]; } return funcs.reduce((a, b) => (...args) => b(a(...args))); } // 处理get的JSON数据 const normalizeParams = (obj, prefix = "?") => Object.entries(obj).reduce((p, [key, value]) => `${p}${key}=${encodeURIComponent(value ? value : "")}&`, prefix); // 处理formData的数据 const normalizeFormDataParams = params => { const myFormData = new FormData(); Object.keys(params).forEach(key => { myFormData.append(key, params[key]); }); return myFormData; }; // 生成一个get的url const normalize = (url, params = {}, prefix) => { return url + normalizeParams(params, prefix); }; const checkGlobalConfig = config => { // prefix 只能为 undefined 和 string if (config.prefix !== undefined) { muxLib.invariant(muxLib.isString(config.prefix), `[fetch] prefix should be string , but got ${typeof config.prefix}`); } // fetchOption 只能为 undefined 和 object if (config.fetchOption) { muxLib.invariant(muxLib.isPlainObject(config.fetchOption), `[fetch] fetchOption should be plain object , but got ${typeof config.fetchOption}`); } // responseHandle 只能为 undefined 和 function if (config.responseHandle) { muxLib.invariant(muxLib.isFunction(config.responseHandle), `[fetch] responseHandle should be function , but got ${typeof config.prefix}`); } // interceptor 只能为 undefined 和 object if (config.interceptor) { muxLib.invariant(muxLib.isPlainObject(config.interceptor), `[fetch] interceptor should be plain object , but got ${typeof config.interceptor}`); // 每一种的 interceptor 只能为 undefined 和 Array<Function> Object.keys(config.interceptor).forEach(key => { if (config.interceptor[key]) { muxLib.invariant(muxLib.isArray(config.interceptor[key]), `[fetch] each interceptor should be array , but got ${typeof config.interceptor[key]}`); config.interceptor[key].forEach(v => { muxLib.invariant(muxLib.isFunction(v), `[fetch] each interceptor should be Array<Function> , but got ${typeof v}`); }); } }); } }; const configFactory = (config, base = globalConfigMap.get("config") || DEFAULT_CONFIG) => { // 合并 prefix const prefix = config.prefix || base.prefix; // 合并 responseHandle const responseHandle = config.responseHandle || base.responseHandle; // 合并 fetchOption const fetchOption = Object.assign({}, base.fetchOption || {}, config.fetchOption || {}); // 合并 interceptor const interceptor = Object.keys(DEFAULT_CONFIG.interceptor).reduce((p, key) => { const configInterceptor = (config.interceptor || {})[key] || []; const baseInterceptor = (base.interceptor || {})[key] || []; const baseKeyInterceptor = muxLib.isArray(baseInterceptor) ? baseInterceptor : [baseInterceptor]; p[key] = compose(...baseKeyInterceptor, ...configInterceptor); return p; }, {}); return { prefix, fetchOption, responseHandle, interceptor }; }; /** * 默认配置 */ const DEFAULT_CONFIG = { prefix: "", fetchOption: {}, responseHandle: async res => { const data = await res.response.clone().json(); return { ...data, ...res.options }; }, interceptor: { requestInterceptor: compose(), responseInterceptor: compose(), errorInterceptor: compose() } }; /** * 请求类型 */ const JSON_TYPE = "application/json"; const FORM_DATA_TYPE = "multipart/form-data;"; /** * 匹配http,https */ const URL_HTTP_REG = /^http(s?)\:\/\//; const globalConfigMap = new Map([["config", DEFAULT_CONFIG]]); const setGlobalConfig = (config = {}) => { /** * 开始前,进行必要的检查 */ checkGlobalConfig(config); /** * 对参数进行处理 */ const params = configFactory(config); globalConfigMap.set("config", params); }; const blockConfigMap = new Map(); const setBlockConfig = (namespace, config = {}) => { /** * 开始前,进行必要的检查 */ checkGlobalConfig(config); /** * 对参数进行处理 */ const params = configFactory(config); blockConfigMap.set("namespace", namespace); blockConfigMap.set(namespace, params); }; /** * 默认加上请求方法,第二个参数约定为请求参数 */ const fastFetchFactory = (fetch, opts) => (api, params = {}, ...args) => fetch(api, { body: params || {}, ...opts }, ...args); /** * 默认的配置项 */ const createDefaultConfig = () => globalConfigMap.get("config"); const fetchWebapi = async (api, opts = {}, getConfig = createDefaultConfig) => { /** * getConfig 必须在运行时调用,才能保证获取的配置是最新的 * @returns interceptor * @returns prefix * @returns fetchOption */ const { interceptor, prefix, fetchOption, responseHandle } = getConfig(); const { requestInterceptor, responseInterceptor, errorInterceptor } = interceptor; let url, options, startTime, endTime; try { /** * 请求拦截器 */ const request = requestInterceptor({ api: URL_HTTP_REG.test(api) ? api : `${prefix}${api}`, options: Object.assign({}, fetchOption, opts) }); url = request.api; options = request.options; /** * 如果没有,默认使用fetch * 要求必须是返回promise的方法 */ const fetch = options.fetch || defaultFetch; /** * 打印请求开始时间 */ startTime = Date.now(); const response = await fetch(url, options); /** * 打印请求结束时间 */ endTime = Date.now(); /** * 返回响应拦截器的值 * * @example * const responseInterceptor = res =>res.clone().json() * */ const res = await responseHandle({ response, options: { startTime, endTime } }); return responseInterceptor(res); } catch (error) { errorInterceptor({ error, options: { type: "fetch", url, args: { options, startTime, endTime } } }); } }; // 快捷方法 fetchWebapi.get = fastFetchFactory(fetchWebapi, { method: "GET" }); fetchWebapi.post = fastFetchFactory(fetchWebapi, { method: "POST" }); fetchWebapi.put = fastFetchFactory(fetchWebapi, { method: "PUT" }); fetchWebapi.delete = fastFetchFactory(fetchWebapi, { method: "DELETE" }); fetchWebapi.upload = fastFetchFactory(fetchWebapi, { method: "POST", headersType: FORM_DATA_TYPE }); const fetch = (...args) => { let namespace, api, options; if (!args.length) { muxLib.invariant(false, "[fetch] fetch need one argument at least"); } /** * 第一种,简单的调用接口 * @example * fetch(api) */ if (args.length === 1) { api = args[0]; options = {}; } /** * 第二种,调用接口带参数 * @example * 1. fetch(api,options) * 2. fetch(namespace,api) * */ if (args.length === 2) { if (muxLib.isString(args[1])) { namespace = args[0]; api = args[1]; } else { api = args[0]; options = args[1]; } } /** * 第三种,调用接口加上区块的参数 * @example * fetch(namespace,api,options) */ if (args.length === 3) { namespace = args[0]; api = args[1]; options = args[2]; } if (!namespace) { return fetchWebapi(api, options); } else { const getConfig = () => blockConfigMap.get(namespace); return fetchWebapi(api, options, getConfig); } }; // 快捷方法 fetch.get = fastFetchFactory(fetch, { method: "GET" }); fetch.post = fastFetchFactory(fetch, { method: "POST" }); fetch.put = fastFetchFactory(fetch, { method: "PUT" }); fetch.delete = fastFetchFactory(fetch, { method: "DELETE" }); fetch.upload = fastFetchFactory(fetch, { method: "POST", headersType: FORM_DATA_TYPE }); exports.DEFAULT_CONFIG = DEFAULT_CONFIG; exports.FORM_DATA_TYPE = FORM_DATA_TYPE; exports.JSON_TYPE = JSON_TYPE; exports.URL_HTTP_REG = URL_HTTP_REG; exports.blockConfigMap = blockConfigMap; exports.checkGlobalConfig = checkGlobalConfig; exports.compose = compose; exports.configFactory = configFactory; exports.fastFetchFactory = fastFetchFactory; exports.fetch = fetch; exports.fetchWebapi = fetchWebapi; exports.globalConfigMap = globalConfigMap; exports.normalize = normalize; exports.normalizeFormDataParams = normalizeFormDataParams; exports.normalizeParams = normalizeParams; exports.setBlockConfig = setBlockConfig; exports.setGlobalConfig = setGlobalConfig; Object.defineProperty(exports, '__esModule', { value: true }); })));