/** * Request 2.0.1 * @Class Request * @description luch-request 2.0.1 http请求插件 * @Author lu-ch * @Date 2020-05-01 * @Email webwork.s@qq.com * http://ext.dcloud.net.cn/plugin?id=392 * hbuilderx:2.6.15 */ import buildURL from '../helpers/buildURL' import buildFullPath from './buildFullPath' import { isBoolean } from '../utils' export default class Request { config = { baseUrl: '', header: {}, method: 'GET', dataType: 'json', // #ifndef MP-ALIPAY || APP-PLUS responseType: 'text', // #endif custom: {}, // #ifdef MP-ALIPAY || MP-WEIXIN timeout: 30000, // #endif // #ifdef APP-PLUS sslVerify: true, // #endif // #ifdef H5 withCredentials: false // #endif } /** * @property {Function} request 请求拦截器 * @property {Function} response 响应拦截器 * @type {{request: Request.interceptor.request, response: Request.interceptor.response}} */ interceptor = { /** * @param {Request~requestCallback} cb - 请求之前拦截,接收一个函数(config, cancel)=> {return config}。第一个参数为全局config,第二个参数为函数,调用则取消本次请求。 */ request: (cb) => { if (cb) { this.requestBeforeFun = cb } }, /** * @param {Request~responseCallback} cb 响应拦截器,对响应数据做点什么 * @param {Request~responseErrCallback} ecb 响应拦截器,对响应错误做点什么 */ response: (cb, ecb) => { if (cb) { this.requestComFun = cb } if (ecb) { this.requestComFail = ecb } } } requestBeforeFun = (config) => { return config } requestComFun = (response) => { return response } requestComFail = (response) => { return response } /** * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject) * @param { Number } statusCode - 请求响应体statusCode(只读) * @return { Boolean } 如果为true,则 resolve, 否则 reject */ validateStatus(statusCode) { return statusCode === 200 } /** * @Function * @param {Request~setConfigCallback} f - 设置全局默认配置 */ setConfig(f) { this.config = f(this.config) } /** * @Function * @param {Object} options - 请求配置项 * @prop {String} options.url - 请求路径 * @prop {Object} options.data - 请求参数 * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型 * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse * @prop {Object} [options.header = config.header] - 请求header * @prop {Object} [options.method = config.method] - 请求方法 * @returns {Promise} */ async request(options = {}) { return new Promise((resolve, reject) => { options.baseUrl = this.config.baseUrl options.dataType = options.dataType || this.config.dataType // #ifndef MP-ALIPAY || APP-PLUS options.responseType = options.responseType || this.config.responseType // #endif // #ifdef MP-ALIPAY || MP-WEIXIN options.timeout = options.timeout || this.config.timeout // #endif // #ifdef H5 options.withCredentials = isBoolean(options.withCredentials) ? options.withCredentials : this.config.withCredentials // #endif options.url = options.url || '' options.data = options.data || {} options.params = options.params || {} options.header = {...this.config.header, ...(options.header || {})} options.method = options.method || this.config.method options.custom = {...this.config.custom,...(options.custom || {})} // #ifdef APP-PLUS options.sslVerify = options.sslVerify === undefined ? this.config.sslVerify : options.sslVerify // #endif options.getTask = options.getTask || this.config.getTask let next = true const cancel = (t = 'handle cancel', config = options) => { const err = { errMsg: t, config: config } reject(err) next = false } const handleRe = {...this.requestBeforeFun(options, cancel)} const _config = {...handleRe} if (!next) return const requestTask = uni.request({ url: buildURL(buildFullPath(_config.baseUrl, _config.url), _config.params), data: _config.data, header: _config.header, method: _config.method, // #ifdef MP-ALIPAY || MP-WEIXIN timeout: _config.timeout, // #endif dataType: _config.dataType, // #ifndef MP-ALIPAY || APP-PLUS responseType: _config.responseType, // #endif // #ifdef APP-PLUS sslVerify: _config.sslVerify, // #endif // #ifdef H5 withCredentials: _config.withCredentials, // #endif complete: (response) => { response.config = handleRe if (this.validateStatus(response.statusCode)) { // 成功 response = this.requestComFun(response) resolve(response) } else { response = this.requestComFail(response) reject(response) } } }) if (handleRe.getTask) { handleRe.getTask(requestTask, handleRe) } }) } get(url, options = {}) { return this.request({ url, method: 'GET', ...options }) } post(url, data, options = {}) { return this.request({ url, data, method: 'POST', ...options }) } // #ifndef MP-ALIPAY put(url, data, options = {}) { return this.request({ url, data, method: 'PUT', ...options }) } // #endif // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU delete(url, data, options = {}) { return this.request({ url, data, method: 'DELETE', ...options }) } // #endif // #ifdef APP-PLUS || H5 || MP-WEIXIN connect(url, data, options = {}) { return this.request({ url, data, method: 'CONNECT', ...options }) } // #endif // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU head(url, data, options = {}) { return this.request({ url, data, method: 'HEAD', ...options }) } // #endif // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU options(url, data, options = {}) { return this.request({ url, data, method: 'OPTIONS', ...options }) } // #endif // #ifdef APP-PLUS || H5 || MP-WEIXIN trace(url, data, options = {}) { return this.request({ url, data, method: 'TRACE', ...options }) } // #endif upload(url, { // #ifdef APP-PLUS || H5 files, // #endif // #ifdef MP-ALIPAY fileType, // #endif filePath, name, // #ifdef H5 file, // #endif header = {}, formData = {}, custom = {}, params = {}, getTask }) { return new Promise((resolve, reject) => { let next = true const globalHeader = {...this.config.header} delete globalHeader['content-type'] delete globalHeader['Content-Type'] const pubConfig = { baseUrl: this.config.baseUrl, url, // #ifdef MP-ALIPAY fileType, // #endif filePath, method: 'UPLOAD', name, header: {...globalHeader, ...header}, formData, params, custom: {...this.config.custom, ...custom}, getTask: getTask || this.config.getTask } // #ifdef APP-PLUS || H5 if (files) { pubConfig.files = files } // #endif // #ifdef H5 if (file) { pubConfig.file = file } // #endif const cancel = (t = 'handle cancel', config = pubConfig) => { const err = { errMsg: t, config: config } reject(err) next = false } const handleRe = {...this.requestBeforeFun(pubConfig, cancel)} const _config = { url: buildURL(buildFullPath(handleRe.baseUrl, handleRe.url), handleRe.params), // #ifdef MP-ALIPAY fileType: handleRe.fileType, // #endif filePath: handleRe.filePath, name: handleRe.name, header: handleRe.header, formData: handleRe.formData, complete: (response) => { response.config = handleRe try { // 对可能字符串不是json 的情况容错 if (typeof response.data === 'string') { response.data = JSON.parse(response.data) } // eslint-disable-next-line no-empty } catch (e) { } if (this.validateStatus(response.statusCode)) { // 成功 response = this.requestComFun(response) resolve(response) } else { response = this.requestComFail(response) reject(response) } } } // #ifdef APP-PLUS || H5 if (handleRe.files) { _config.files = handleRe.files } // #endif // #ifdef H5 if (handleRe.file) { _config.file = handleRe.file } // #endif if (!next) return const requestTask = uni.uploadFile(_config) if (handleRe.getTask) { handleRe.getTask(requestTask, handleRe) } }) } download(url, options = {}) { return new Promise((resolve, reject) => { let next = true const pubConfig = { baseUrl: this.config.baseUrl, url, method: 'DOWNLOAD', header: {...this.config.header, ...(options.header || {})}, params: options.params || {}, custom: {...this.config.custom, ...(options.custom || {})}, getTask: options.getTask || this.config.getTask } const cancel = (t = 'handle cancel', config = pubConfig) => { const err = { errMsg: t, config: config } reject(err) next = false } const handleRe = {...this.requestBeforeFun(pubConfig, cancel)} if (!next) return const requestTask = uni.downloadFile({ url: buildURL(buildFullPath(handleRe.baseUrl, handleRe.url), handleRe.params), header: handleRe.header, complete: (response) => { response.config = handleRe if (this.validateStatus(response.statusCode)) { // 成功 response = this.requestComFun(response) resolve(response) } else { response = this.requestComFail(response) reject(response) } } }) if (handleRe.getTask) { handleRe.getTask(requestTask, handleRe) } }) } } /** * setConfig回调 * @return {Object} - 返回操作后的config * @callback Request~setConfigCallback * @param {Object} config - 全局默认config */ /** * 请求拦截器回调 * @return {Object} - 返回操作后的config * @callback Request~requestCallback * @param {Object} config - 全局config * @param {Function} [cancel] - 取消请求钩子,调用会取消本次请求 */ /** * 响应拦截器回调 * @return {Object} - 返回操作后的response * @callback Request~responseCallback * @param {Object} response - 请求结果 response */ /** * 响应错误拦截器回调 * @return {Object} - 返回操作后的response * @callback Request~responseErrCallback * @param {Object} response - 请求结果 response */