Last active
February 14, 2017 20:51
-
-
Save s00d/58f0a3c1c3dcddc845c137c7ec255dd3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import qs from 'query-string' | |
import template from 'string-template' | |
import isPlainObject from 'lodash/isPlainObject' | |
import merge from './cheap-merge' | |
import promisify from './promisify' | |
const defaultOptions = { | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json' | |
}, | |
method: 'GET', | |
// 强制返回的结果按 JSON 处理,用于 File 协议的请求 | |
forceJSON: false | |
} | |
const mutators = [] | |
export function configure ({ mutate, mutator, ...options }) { | |
if (mutate) { | |
process.env.NODE_ENV === 'production' || console.warn('`mutate` is deprecated. use `mutator` instead.') | |
mutator = mutate | |
} | |
if (mutator) { | |
mutators.push(mutator) | |
} | |
merge(defaultOptions, options) | |
} | |
/** | |
* request | |
* | |
* request({ | |
* url: 'path', | |
* query: { ... }, | |
* params: { ... }, | |
* body: { ... } | |
* headers: { ... } | |
* }) | |
* request('path') | |
* request('path', { ... }) | |
* | |
* @param {String|Object} options Options | |
* @return {Promise} Promise | |
*/ | |
export default function request (...args) { | |
if (args.length === 0) { | |
process.env.NODE_ENV === 'production' || console.warn('URL or Options is Required!') | |
return | |
} | |
if (typeof args[0] === 'string') { | |
if (args[1] === undefined) { | |
args[1] = {} | |
} else if (!isPlainObject(args[1])) { | |
process.env.NODE_ENV === 'production' || console.warn('Options MUST be Object!') | |
return | |
} | |
args[1].url = args[0] | |
args[0] = args[1] | |
} | |
if (!isPlainObject(args[0])) { | |
process.env.NODE_ENV === 'production' || console.warn('Options MUST be Object!') | |
return | |
} | |
return new Promise((resolve, reject) => { | |
promisify(parseOptions(merge({}, defaultOptions, args[0]))) | |
.then(({ url, ...options }) => fetch(url, options)) | |
.then(res => { | |
const { forceJSON } = args[0] | |
if (res && (isHttpOk(res) || isFileOk(res))) { | |
getBody(res, forceJSON).then(resolve, reject) | |
} else { | |
getBody(res, forceJSON).then(reject) | |
} | |
}) | |
.catch(reject) | |
}) | |
} | |
function isHttpOk (res) { | |
return res.status >= 200 && res.status < 400 | |
} | |
// 支持 file 协议的访问 | |
function isFileOk (res) { | |
return res.status === 0 && (res.url.indexOf('file://') === 0 || res.url === '') | |
} | |
function getBody (res, forceJSON) { | |
const type = res.headers.get('Content-Type') | |
return (forceJSON || (type && type.indexOf('json') !== -1)) ? res.json() : res.text() | |
} | |
function parseOptions ({ url = '', query, params, body, mutate, mutator, ...options }) { | |
if (body) { | |
if (typeof body === 'object') { | |
if (/^(POST|PUT|PATCH)$/i.test(options.method)) { | |
body = JSON.stringify(body) | |
} else { | |
url += ((url.indexOf('?') !== -1) ? '&' : '?') + qs.stringify(body) | |
body = null | |
} | |
} | |
if (body) { | |
options.body = body | |
} | |
} | |
if (query) { | |
if (typeof query === 'object') { | |
query = qs.stringify(query) | |
} | |
if (query) { | |
url += ((url.indexOf('?') !== -1) ? '&' : '?') + query | |
} | |
} | |
// 替换地址中的宏变量:{xyz} | |
if (params) { | |
url = template(url, params) | |
} | |
options.url = url | |
if (mutate) { | |
process.env.NODE_ENV === 'production' || console.warn('`mutate` is deprecated. use `mutator` instead.') | |
mutator = mutate | |
} | |
// mutate must be a function and could return a promise | |
// useful for adding authorization | |
return iterateMutators(options, mutator ? mutators.concat(mutator) : mutators.slice(0)) | |
} | |
function iterateMutators (options, mutators) { | |
function iterator (options) { | |
const mutator = mutators.shift() | |
if (!mutator) { | |
return options | |
} | |
return promisify(mutator(options)).then(iterator) | |
} | |
return iterator(options) | |
} | |
export function get (url, options = {}) { | |
options.url = url | |
options.method = 'GET' | |
return request(options) | |
} | |
export function post (url, options = {}) { | |
options.url = url | |
options.method = 'POST' | |
return request(options) | |
} | |
export function put (url, options = {}) { | |
options.url = url | |
options.method = 'PUT' | |
return request(options) | |
} | |
export function patch (url, options = {}) { | |
options.url = url | |
options.method = 'PATCH' | |
return request(options) | |
} | |
export function del (url, options = {}) { | |
options.url = url | |
options.method = 'DELETE' | |
return request(options) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import isPlainObject from 'lodash/isPlainObject' | |
import assignWith from 'lodash/assignWith' | |
/** | |
* 合并对象 | |
* 当一级属性是对象时执行合并,否则执行覆盖,例: | |
* merge({a: {b: 1}}, {a: {c: 1}}) => {a: {b: 1, c: 1}} | |
* merge({a: {b: { x: 1 }}}, {a: {b: { y: 2 }}}) => {a: {b: { y: 2 }}} | |
* @method | |
* @param {object} object 目标对象 | |
* @param {array} sources 待合入对象列表 | |
* @return {object} 目标对象 | |
*/ | |
export default (object, ...sources) => assignWith(object, ...sources, (objValue, srcValue) => { | |
if (isPlainObject(srcValue)) { | |
if (!isPlainObject(objValue)) { | |
objValue = {} | |
} | |
return { ...objValue, ...srcValue } | |
} | |
return srcValue | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function promisify (val, rejectIfFalsy) { | |
if (val && val.then && typeof val.then === 'function') { | |
return val | |
} | |
return rejectIfFalsy ? val ? Promise.resolve(val) : Promise.reject(val) : Promise.resolve(val) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import request, { configure, get, post, put, patch, del } from './a_request' | |
configure({ | |
forceJSON: true, | |
mutate (options) { | |
options.mutate1 = 'mutate1' | |
return options | |
} | |
}) | |
request({ | |
method: 'POST', | |
url: 'test', | |
body: { | |
x: 1 | |
}, | |
params: { | |
x: 1 | |
}, | |
query: { | |
x: 1 | |
}, | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json' | |
}, | |
mutator (options) { | |
url = options.url | |
return Promise.resolve({}) | |
} | |
}).finally(() => { | |
done() | |
}) | |
request({ | |
url: '' | |
}).then(json => { | |
}).catch(err => { | |
}) | |
del('ok', { | |
body, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment