UNPKG

kara-reactutil-mobileweb

Version:

kara项目移动端react公共模块功能

189 lines (159 loc) 6.25 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: index.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: index.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/** * HTTP请求 * @module http */ import path from 'lodash/fp/path' import assoc from 'lodash/fp/assoc' /** * @description 计算带参数的url * @param {String} url - 处理的url字符串 * @param {Object} params - 拼接在url后的参数 * @returns {String} * @inner */ function queryParams(url, params) { if (typeof params !== 'object') { return url } const query = Object.keys(params) .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`) .join('&amp;') return `${url}${url.indexOf('?') === -1 ? '?' : '&amp;'}${query}` } // 解析 function parseFetch(response) { switch (response.headers.get('content-type')) { case 'application/json': return response.json() // blob格式的body之所以不直接将response.blob值直接求取出来给到promise,由于少数接口在headers上附带了参数 case 'application/octet-stream': return response case 'text/plain': return response.text() case 'arrayBuffer': return response.arrayBuffer() case 'multipart/form-data': return response.formData() default: return response } } /** * 全局http请求的基于fetch polyfill的whatwg-fetch库; * 第二级参数兼容fetch标准,请求参考下面see标示链接 * @see {@link https://github.com/github/fetch#post-json} * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch} * @see {@link https://github.com/camsong/blog/issues/2} * @param {Object} config - 全局请求的配置设置参数 * @param {String} config.prefixG - 全局设定的请求前缀 * @param {Object} [config.versionG='v1.0.0'] - 全局默认默认请求版本号 * @param {Object} tokenStorage - token的增删改方法 * @param {Function} tokenStorage.getToken - 获取授权码相关参数token\refreshToken * @param {Function} tokenStorage.setToken - 设置授权码 * @param {Function} tokenStorage.removeToken - 移除授权码 * * @param {String} url - 请求url[注意把前缀除开] * @param {Object} [options] - 对fetch标准options参数进行扩展, 单个请求的参数设置在options上 * @param {String} [options.prefix] - API请求前缀 * @param {String} [options.version] - API请求版本号 * @param {Object} [options.params] - url上的query参数 * @param {Boolean} [options.withToken=true] - 是否附带token认证 * @param {Number} [options.timeout] - 超时处理,单位ms; * * @returns {Function(String, Object): *|Promise.&lt;TResult>} - 请求返回处理的promise对象 * @version v0.01 */ const invokeApi = ({ prefixG, versionG = 'v1.0.0', }, { getToken, setToken, removeToken }) => (url, options) => { const { params, version, prefix, withToken = true, ...opt } = options if (!prefixG) { throw new Error('请设置全局统一网关,即请求前缀') } const prefixUrl = `${prefix || prefixG}${version || versionG}` const uri = queryParams(`${prefixUrl}${url}`, params) const { token, refreshToken } = getToken() if (withToken &amp;&amp; !path(['headers', 'Authorization'], options)) { // TODO 这段逻辑可以转移到全局参数上设置。确保各应用的token存储由自己管理 if (!token) { throw new Error('请求授权') } assoc(['headers', 'Authorization'], token, opt) } if (!path(['headers', 'Content-Type'], options)) { assoc(['headers', 'Content-Type'], 'application/json', opt) } // 仅仅对全局最常用的JSON格式的Request数据进行类型矫正为String、其他类型转换后放Body上 if (path(['headers', 'Content-Type'], opt) === 'application/json' &amp;&amp; options.body) { opt.body = JSON.stringify(options.body) } const fetchPromise = async () => { try { const res = await fetch(uri, opt) if (res.status === 401 &amp;&amp; refreshToken) { const tokenRes = await fetch(`${prefixUrl}/auth/refreshtoken`, { headers: { 'Content-Type': 'application/json', refreshToken }, }) const tokenInfo = tokenRes.ok &amp;&amp; tokenRes.headers.get('content-type') === 'application/json' &amp;&amp; await tokenRes.json() if (path('resultCode', tokenInfo) === '000000') { setToken(tokenInfo.tokenInfo) assoc(['headers', 'Authorization'], getToken().token, opt) const reFetch = await fetch(`${prefixUrl}${url}`, opt) return reFetch.ok ? parseFetch(reFetch) : Promise.reject(reFetch) } removeToken() location.href = '/' return Promise.reject(tokenRes) } else if (res.status === 401 &amp;&amp; !refreshToken) { removeToken() location.href = '/' } return res.ok ? parseFetch(res) : Promise.reject(res) } catch (error) { return Promise.reject(error) } } if (options.timeout) { const abortPromise = new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('请求超时')) }, options.timeout) }) return Promise.race([fetchPromise, abortPromise]) } return fetchPromise } /** invokeApi */ export default invokeApi </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-http.html">http</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Tue Jun 20 2017 11:07:59 GMT+0800 (CST) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>