kara-reactutil-mobileweb
Version:
kara项目移动端react公共模块功能
189 lines (159 loc) • 6.25 kB
HTML
<!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('&')
return `${url}${url.indexOf('?') === -1 ? '?' : '&'}${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.<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 && !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' && options.body) {
opt.body = JSON.stringify(options.body)
}
const fetchPromise = async () => {
try {
const res = await fetch(uri, opt)
if (res.status === 401 && refreshToken) {
const tokenRes = await fetch(`${prefixUrl}/auth/refreshtoken`, {
headers: { 'Content-Type': 'application/json', refreshToken },
})
const tokenInfo = tokenRes.ok && tokenRes.headers.get('content-type') === 'application/json' && 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 && !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>