├── src └── lib │ ├── luch-request.js │ ├── core │ ├── dispatchRequest.js │ ├── settle.js │ ├── buildFullPath.js │ ├── defaults.js │ ├── InterceptorManager.js │ ├── mergeConfig.js │ └── Request.js │ ├── helpers │ ├── combineURLs.js │ ├── isAbsoluteURL.js │ └── buildURL.js │ ├── utils.js │ ├── adapters │ └── index.js │ ├── luch-request.d.ts │ └── utils │ └── clone.js ├── DCloud └── luch-request │ ├── index.js │ ├── core │ ├── dispatchRequest.js │ ├── settle.js │ ├── buildFullPath.js │ ├── defaults.js │ ├── InterceptorManager.js │ ├── mergeConfig.js │ └── Request.js │ ├── helpers │ ├── combineURLs.js │ ├── isAbsoluteURL.js │ └── buildURL.js │ ├── utils.js │ ├── adapters │ └── index.js │ ├── index.d.ts │ └── utils │ └── clone.js ├── test ├── dev-test │ ├── static │ │ └── logo.jpg │ ├── utils │ │ └── luch-request │ │ │ ├── index.js │ │ │ ├── core │ │ │ ├── dispatchRequest.js │ │ │ ├── settle.js │ │ │ ├── buildFullPath.js │ │ │ ├── defaults.js │ │ │ ├── InterceptorManager.js │ │ │ ├── mergeConfig.js │ │ │ └── Request.js │ │ │ ├── helpers │ │ │ ├── combineURLs.js │ │ │ ├── isAbsoluteURL.js │ │ │ └── buildURL.js │ │ │ ├── utils.js │ │ │ ├── adapters │ │ │ └── index.js │ │ │ └── index.d.ts │ ├── main.js │ ├── App.vue │ ├── pages.json │ ├── uni.scss │ ├── api │ │ └── service.js │ ├── manifest.json │ └── pages │ │ └── index │ │ └── index.vue └── types-test.ts ├── example └── request-demo │ ├── utils │ └── luch-request │ │ ├── index.js │ │ ├── core │ │ ├── dispatchRequest.js │ │ ├── settle.js │ │ ├── buildFullPath.js │ │ ├── defaults.js │ │ ├── InterceptorManager.js │ │ ├── mergeConfig.js │ │ └── Request.js │ │ ├── helpers │ │ ├── combineURLs.js │ │ ├── isAbsoluteURL.js │ │ └── buildURL.js │ │ ├── utils.js │ │ ├── adapters │ │ └── index.js │ │ └── index.d.ts │ ├── static │ └── logo.jpg │ ├── main.js │ ├── App.vue │ ├── pages.json │ ├── api │ ├── goods.js │ └── service.js │ ├── uni.scss │ ├── pages │ ├── goods-list │ │ └── goods-list.vue │ └── index │ │ └── index.vue │ └── manifest.json ├── docs ├── .vuepress │ ├── public │ │ └── assets │ │ │ └── img │ │ │ └── logo.jpg │ ├── components │ │ └── cm-notice.vue │ └── config.js ├── resources │ └── article.md ├── acknowledgement │ └── README.md ├── README.md ├── issue │ └── README.md └── handbook │ └── README.md ├── babel.config.js ├── .npmignore ├── .gitignore ├── node ├── zipDCloudDemo.js └── zipDCloudPlugin.js ├── gruntfile.js ├── .eslintrc.js ├── .github └── .workflow │ └── doc_pub.yml ├── LICENSE.txt ├── rollup.config.js ├── history.md ├── package.json └── tsconfig.json /src/lib/luch-request.js: -------------------------------------------------------------------------------- 1 | import Request from './core/Request' 2 | export default Request 3 | -------------------------------------------------------------------------------- /DCloud/luch-request/index.js: -------------------------------------------------------------------------------- 1 | import Request from './core/Request' 2 | export default Request 3 | -------------------------------------------------------------------------------- /test/dev-test/static/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lei-mu/luch-request/HEAD/test/dev-test/static/logo.jpg -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/index.js: -------------------------------------------------------------------------------- 1 | import Request from './core/Request' 2 | export default Request 3 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/index.js: -------------------------------------------------------------------------------- 1 | import Request from './core/Request' 2 | export default Request 3 | -------------------------------------------------------------------------------- /example/request-demo/static/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lei-mu/luch-request/HEAD/example/request-demo/static/logo.jpg -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/img/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lei-mu/luch-request/HEAD/docs/.vuepress/public/assets/img/logo.jpg -------------------------------------------------------------------------------- /src/lib/core/dispatchRequest.js: -------------------------------------------------------------------------------- 1 | import adapter from '../adapters/index' 2 | 3 | 4 | export default (config) => { 5 | return adapter(config) 6 | } 7 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/dispatchRequest.js: -------------------------------------------------------------------------------- 1 | import adapter from '../adapters/index' 2 | 3 | 4 | export default (config) => { 5 | return adapter(config) 6 | } 7 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/dispatchRequest.js: -------------------------------------------------------------------------------- 1 | import adapter from '../adapters/index' 2 | 3 | 4 | export default (config) => { 5 | return adapter(config) 6 | } 7 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-env'], 3 | plugins: [ "@babel/plugin-transform-arrow-functions", "@babel/plugin-proposal-class-properties" ] 4 | }; 5 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/dispatchRequest.js: -------------------------------------------------------------------------------- 1 | import adapter from '../adapters/index' 2 | 3 | 4 | export default (config) => { 5 | return adapter(config) 6 | } 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | **/.* 2 | *.iml 3 | example/ 4 | node_modules/ 5 | dist/ 6 | docs/ 7 | DCloud/ 8 | test/ 9 | node/ 10 | zipDist/ 11 | babel.config.js 12 | gruntfile.js 13 | rollup.config.js 14 | tsconfig.json 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | .tscache 4 | .DS_Store 5 | .hbuilderx 6 | yarn-error.log 7 | node_modules/ 8 | dist 9 | DCloud/* 10 | !DCloud/luch-request/ 11 | 12 | 13 | zipDist/ 14 | 15 | example/* 16 | !/example/request-demo 17 | -------------------------------------------------------------------------------- /test/dev-test/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import { http } from '@/api/service.js' // 全局挂载引入,配置相关在该index.js文件里修改 4 | 5 | Vue.prototype.$http = http 6 | Vue.config.productionTip = false 7 | 8 | App.mpType = 'app' 9 | 10 | const app = new Vue({ 11 | ...App 12 | }) 13 | app.$mount() 14 | -------------------------------------------------------------------------------- /example/request-demo/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import { http } from '@/api/service.js' // 全局挂载引入,配置相关在该index.js文件里修改 4 | 5 | Vue.prototype.$http = http 6 | Vue.config.productionTip = false 7 | 8 | App.mpType = 'app' 9 | 10 | const app = new Vue({ 11 | ...App 12 | }) 13 | app.$mount() 14 | -------------------------------------------------------------------------------- /test/dev-test/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /example/request-demo/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /test/dev-test/pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages 3 | { 4 | "path": "pages/index/index", 5 | "style": { 6 | } 7 | } 8 | ], 9 | "globalStyle": { 10 | "navigationBarTextStyle": "black", 11 | "navigationBarTitleText": "luch-request dev-test", 12 | "navigationBarBackgroundColor": "#F8F8F8", 13 | "backgroundColor": "#F8F8F8" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /node/zipDCloudDemo.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var archiver = require('archiver') 3 | 4 | var output = fs.createWriteStream('zipDist/request-demo.zip') 5 | 6 | var archive = archiver('zip') 7 | 8 | archive.on('error', function(err){ 9 | throw err 10 | }) 11 | const buildDemo = () => { 12 | archive.pipe(output) 13 | archive.directory('DCloud/request-demo', 'request-demo') 14 | archive.finalize() 15 | } 16 | 17 | buildDemo() 18 | -------------------------------------------------------------------------------- /node/zipDCloudPlugin.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var archiver = require('archiver') 3 | 4 | var output = fs.createWriteStream('zipDist/luch-request.zip') 5 | 6 | var archive = archiver('zip') 7 | 8 | archive.on('error', function(err){ 9 | throw err 10 | }) 11 | const buildRequest = () => { 12 | archive.pipe(output) 13 | archive.directory('DCloud/luch-request', 'luch-request') 14 | archive.finalize() 15 | } 16 | buildRequest() 17 | -------------------------------------------------------------------------------- /src/lib/helpers/combineURLs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Creates a new URL by combining the specified URLs 5 | * 6 | * @param {string} baseURL The base URL 7 | * @param {string} relativeURL The relative URL 8 | * @returns {string} The combined URL 9 | */ 10 | export default function combineURLs(baseURL, relativeURL) { 11 | return relativeURL 12 | ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') 13 | : baseURL 14 | } 15 | -------------------------------------------------------------------------------- /DCloud/luch-request/helpers/combineURLs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Creates a new URL by combining the specified URLs 5 | * 6 | * @param {string} baseURL The base URL 7 | * @param {string} relativeURL The relative URL 8 | * @returns {string} The combined URL 9 | */ 10 | export default function combineURLs(baseURL, relativeURL) { 11 | return relativeURL 12 | ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') 13 | : baseURL 14 | } 15 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | require('load-grunt-tasks')(grunt) // npm install --save-dev load-grunt-tasks 3 | 4 | grunt.initConfig({ 5 | babel: { 6 | options: { 7 | sourceMap: true, 8 | presets: ['@babel/preset-env'] 9 | }, 10 | dist: { 11 | files: { 12 | 'dist/app.js': 'src/index.js' 13 | } 14 | } 15 | } 16 | }) 17 | 18 | grunt.registerTask('default', ['babel']) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/helpers/combineURLs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Creates a new URL by combining the specified URLs 5 | * 6 | * @param {string} baseURL The base URL 7 | * @param {string} relativeURL The relative URL 8 | * @returns {string} The combined URL 9 | */ 10 | export default function combineURLs(baseURL, relativeURL) { 11 | return relativeURL 12 | ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') 13 | : baseURL 14 | } 15 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/helpers/combineURLs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Creates a new URL by combining the specified URLs 5 | * 6 | * @param {string} baseURL The base URL 7 | * @param {string} relativeURL The relative URL 8 | * @returns {string} The combined URL 9 | */ 10 | export default function combineURLs(baseURL, relativeURL) { 11 | return relativeURL 12 | ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') 13 | : baseURL 14 | } 15 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly", 11 | "uni": true 12 | }, 13 | parser: "babel-eslint", 14 | "parserOptions": { 15 | "ecmaVersion": 2018, 16 | }, 17 | "rules": { 18 | semi: ['error', 'never'], // 结尾不用写分号 19 | "indent": ["error", 2] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/request-demo/pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | { 4 | "path": "pages/index/index", 5 | "style": { 6 | } 7 | } 8 | ,{ 9 | "path" : "pages/goods-list/goods-list", 10 | "style" : {} 11 | } 12 | ], 13 | "globalStyle": { 14 | "navigationBarTextStyle": "black", 15 | "navigationBarTitleText": "luch-request demo", 16 | "navigationBarBackgroundColor": "#F8F8F8", 17 | "backgroundColor": "#F8F8F8" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docs/.vuepress/components/cm-notice.vue: -------------------------------------------------------------------------------- 1 | 4 | 20 | 31 | -------------------------------------------------------------------------------- /src/lib/core/settle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Resolve or reject a Promise based on response status. 3 | * 4 | * @param {Function} resolve A function that resolves the promise. 5 | * @param {Function} reject A function that rejects the promise. 6 | * @param {object} response The response. 7 | */ 8 | export default function settle(resolve, reject, response) { 9 | const validateStatus = response.config.validateStatus 10 | const status = response.statusCode 11 | if (status && (!validateStatus || validateStatus(status))) { 12 | resolve(response) 13 | } else { 14 | reject(response) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/settle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Resolve or reject a Promise based on response status. 3 | * 4 | * @param {Function} resolve A function that resolves the promise. 5 | * @param {Function} reject A function that rejects the promise. 6 | * @param {object} response The response. 7 | */ 8 | export default function settle(resolve, reject, response) { 9 | const validateStatus = response.config.validateStatus 10 | const status = response.statusCode 11 | if (status && (!validateStatus || validateStatus(status))) { 12 | resolve(response) 13 | } else { 14 | reject(response) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/settle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Resolve or reject a Promise based on response status. 3 | * 4 | * @param {Function} resolve A function that resolves the promise. 5 | * @param {Function} reject A function that rejects the promise. 6 | * @param {object} response The response. 7 | */ 8 | export default function settle(resolve, reject, response) { 9 | const validateStatus = response.config.validateStatus 10 | const status = response.statusCode 11 | if (status && (!validateStatus || validateStatus(status))) { 12 | resolve(response) 13 | } else { 14 | reject(response) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/settle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Resolve or reject a Promise based on response status. 3 | * 4 | * @param {Function} resolve A function that resolves the promise. 5 | * @param {Function} reject A function that rejects the promise. 6 | * @param {object} response The response. 7 | */ 8 | export default function settle(resolve, reject, response) { 9 | const validateStatus = response.config.validateStatus 10 | const status = response.statusCode 11 | if (status && (!validateStatus || validateStatus(status))) { 12 | resolve(response) 13 | } else { 14 | reject(response) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/helpers/isAbsoluteURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Determines whether the specified URL is absolute 5 | * 6 | * @param {string} url The URL to test 7 | * @returns {boolean} True if the specified URL is absolute, otherwise false 8 | */ 9 | export default function isAbsoluteURL(url) { 10 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). 11 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed 12 | // by any combination of letters, digits, plus, period, or hyphen. 13 | return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url) 14 | } 15 | -------------------------------------------------------------------------------- /DCloud/luch-request/helpers/isAbsoluteURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Determines whether the specified URL is absolute 5 | * 6 | * @param {string} url The URL to test 7 | * @returns {boolean} True if the specified URL is absolute, otherwise false 8 | */ 9 | export default function isAbsoluteURL(url) { 10 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). 11 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed 12 | // by any combination of letters, digits, plus, period, or hyphen. 13 | return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url) 14 | } 15 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/helpers/isAbsoluteURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Determines whether the specified URL is absolute 5 | * 6 | * @param {string} url The URL to test 7 | * @returns {boolean} True if the specified URL is absolute, otherwise false 8 | */ 9 | export default function isAbsoluteURL(url) { 10 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). 11 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed 12 | // by any combination of letters, digits, plus, period, or hyphen. 13 | return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url) 14 | } 15 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/helpers/isAbsoluteURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Determines whether the specified URL is absolute 5 | * 6 | * @param {string} url The URL to test 7 | * @returns {boolean} True if the specified URL is absolute, otherwise false 8 | */ 9 | export default function isAbsoluteURL(url) { 10 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). 11 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed 12 | // by any combination of letters, digits, plus, period, or hyphen. 13 | return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url) 14 | } 15 | -------------------------------------------------------------------------------- /example/request-demo/api/goods.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 商品相关api 3 | */ 4 | import { 5 | http 6 | } from '@/api/service.js' 7 | 8 | /** 9 | * 查询商品列表 10 | * @param {Object} params - 查询参数 11 | */ 12 | export const getGoodsList = (params) => { 13 | return http.get('/api/user/list', { 14 | params 15 | }) 16 | } 17 | 18 | // 通用请求方法middleware 演示。文档:https://www.quanzhan.co/luch-request/guide/3.x/#middleware 19 | /** 20 | * 查询商品信息 21 | * @param {Object} data - 查询数据 22 | * @param {Object} params - 查询params参数 23 | */ 24 | export const getGoodsInfo = (data, params) => { 25 | return http.middleware({ 26 | method: 'POST', // 必须大写 27 | url: '/api/user/update', 28 | data: data, 29 | params: params, 30 | custom: { 31 | auth: true 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /src/lib/core/buildFullPath.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import isAbsoluteURL from '../helpers/isAbsoluteURL' 4 | import combineURLs from '../helpers/combineURLs' 5 | 6 | /** 7 | * Creates a new URL by combining the baseURL with the requestedURL, 8 | * only when the requestedURL is not already an absolute URL. 9 | * If the requestURL is absolute, this function returns the requestedURL untouched. 10 | * 11 | * @param {string} baseURL The base URL 12 | * @param {string} requestedURL Absolute or relative URL to combine 13 | * @returns {string} The combined full path 14 | */ 15 | export default function buildFullPath(baseURL, requestedURL) { 16 | if (baseURL && !isAbsoluteURL(requestedURL)) { 17 | return combineURLs(baseURL, requestedURL) 18 | } 19 | return requestedURL 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/core/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 默认的全局配置 3 | */ 4 | 5 | 6 | export default { 7 | baseURL: '', 8 | header: {}, 9 | method: 'GET', 10 | dataType: 'json', 11 | paramsSerializer: null, 12 | // #ifndef MP-ALIPAY 13 | responseType: 'text', 14 | // #endif 15 | custom: {}, 16 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 17 | timeout: 60000, 18 | // #endif 19 | // #ifdef APP-PLUS 20 | sslVerify: true, 21 | // #endif 22 | // #ifdef H5 23 | withCredentials: false, 24 | // #endif 25 | // #ifdef APP-PLUS 26 | firstIpv4: false, 27 | // #endif 28 | validateStatus: function validateStatus(status) { 29 | return status >= 200 && status < 300 30 | }, 31 | // 是否尝试将响应数据json化 32 | forcedJSONParsing: true 33 | } 34 | -------------------------------------------------------------------------------- /.github/.workflow/doc_pub.yml: -------------------------------------------------------------------------------- 1 | # action 的名称 2 | name: doc_pub 3 | 4 | # 触发条件:在 push 到 docs 分支后 5 | on: 6 | push: 7 | branches: 8 | - docs 9 | 10 | # 任务 11 | jobs: 12 | build-and-deploy: 13 | # 服务器环境:最新版 Ubuntu 14 | runs-on: ubuntu-latest 15 | steps: 16 | # 拉取代码 17 | - name: Checkout 18 | uses: actions/checkout@docs 19 | with: 20 | persist-credentials: false 21 | 22 | - name: vuepress-deploy 23 | uses: jenkey2011/vuepress-deploy@master 24 | env: 25 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} 26 | TARGET_REPO: lei-mu/luch-request 27 | TARGET_BRANCH: gh_pages 28 | BUILD_SCRIPT: npm && npm run docs:build 29 | BUILD_DIR: docs/.vuepress/dist/ 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/buildFullPath.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import isAbsoluteURL from '../helpers/isAbsoluteURL' 4 | import combineURLs from '../helpers/combineURLs' 5 | 6 | /** 7 | * Creates a new URL by combining the baseURL with the requestedURL, 8 | * only when the requestedURL is not already an absolute URL. 9 | * If the requestURL is absolute, this function returns the requestedURL untouched. 10 | * 11 | * @param {string} baseURL The base URL 12 | * @param {string} requestedURL Absolute or relative URL to combine 13 | * @returns {string} The combined full path 14 | */ 15 | export default function buildFullPath(baseURL, requestedURL) { 16 | if (baseURL && !isAbsoluteURL(requestedURL)) { 17 | return combineURLs(baseURL, requestedURL) 18 | } 19 | return requestedURL 20 | } 21 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 默认的全局配置 3 | */ 4 | 5 | 6 | export default { 7 | baseURL: '', 8 | header: {}, 9 | method: 'GET', 10 | dataType: 'json', 11 | paramsSerializer: null, 12 | // #ifndef MP-ALIPAY 13 | responseType: 'text', 14 | // #endif 15 | custom: {}, 16 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 17 | timeout: 60000, 18 | // #endif 19 | // #ifdef APP-PLUS 20 | sslVerify: true, 21 | // #endif 22 | // #ifdef H5 23 | withCredentials: false, 24 | // #endif 25 | // #ifdef APP-PLUS 26 | firstIpv4: false, 27 | // #endif 28 | validateStatus: function validateStatus(status) { 29 | return status >= 200 && status < 300 30 | }, 31 | // 是否尝试将响应数据json化 32 | forcedJSONParsing: true 33 | } 34 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/buildFullPath.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import isAbsoluteURL from '../helpers/isAbsoluteURL' 4 | import combineURLs from '../helpers/combineURLs' 5 | 6 | /** 7 | * Creates a new URL by combining the baseURL with the requestedURL, 8 | * only when the requestedURL is not already an absolute URL. 9 | * If the requestURL is absolute, this function returns the requestedURL untouched. 10 | * 11 | * @param {string} baseURL The base URL 12 | * @param {string} requestedURL Absolute or relative URL to combine 13 | * @returns {string} The combined full path 14 | */ 15 | export default function buildFullPath(baseURL, requestedURL) { 16 | if (baseURL && !isAbsoluteURL(requestedURL)) { 17 | return combineURLs(baseURL, requestedURL) 18 | } 19 | return requestedURL 20 | } 21 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 默认的全局配置 3 | */ 4 | 5 | 6 | export default { 7 | baseURL: '', 8 | header: {}, 9 | method: 'GET', 10 | dataType: 'json', 11 | paramsSerializer: null, 12 | // #ifndef MP-ALIPAY 13 | responseType: 'text', 14 | // #endif 15 | custom: {}, 16 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 17 | timeout: 60000, 18 | // #endif 19 | // #ifdef APP-PLUS 20 | sslVerify: true, 21 | // #endif 22 | // #ifdef H5 23 | withCredentials: false, 24 | // #endif 25 | // #ifdef APP-PLUS 26 | firstIpv4: false, 27 | // #endif 28 | validateStatus: function validateStatus(status) { 29 | return status >= 200 && status < 300 30 | }, 31 | // 是否尝试将响应数据json化 32 | forcedJSONParsing: true 33 | } 34 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/buildFullPath.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import isAbsoluteURL from '../helpers/isAbsoluteURL' 4 | import combineURLs from '../helpers/combineURLs' 5 | 6 | /** 7 | * Creates a new URL by combining the baseURL with the requestedURL, 8 | * only when the requestedURL is not already an absolute URL. 9 | * If the requestURL is absolute, this function returns the requestedURL untouched. 10 | * 11 | * @param {string} baseURL The base URL 12 | * @param {string} requestedURL Absolute or relative URL to combine 13 | * @returns {string} The combined full path 14 | */ 15 | export default function buildFullPath(baseURL, requestedURL) { 16 | if (baseURL && !isAbsoluteURL(requestedURL)) { 17 | return combineURLs(baseURL, requestedURL) 18 | } 19 | return requestedURL 20 | } 21 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 默认的全局配置 3 | */ 4 | 5 | 6 | export default { 7 | baseURL: '', 8 | header: {}, 9 | method: 'GET', 10 | dataType: 'json', 11 | paramsSerializer: null, 12 | // #ifndef MP-ALIPAY 13 | responseType: 'text', 14 | // #endif 15 | custom: {}, 16 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 17 | timeout: 60000, 18 | // #endif 19 | // #ifdef APP-PLUS 20 | sslVerify: true, 21 | // #endif 22 | // #ifdef H5 23 | withCredentials: false, 24 | // #endif 25 | // #ifdef APP-PLUS 26 | firstIpv4: false, 27 | // #endif 28 | validateStatus: function validateStatus(status) { 29 | return status >= 200 && status < 300 30 | }, 31 | // 是否尝试将响应数据json化 32 | forcedJSONParsing: true 33 | } 34 | -------------------------------------------------------------------------------- /docs/resources/article.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | title: 相关文章 4 | --- 5 | 6 | 前言 7 | ------------ 8 | 9 | 以下为本人遇到的和luch-request有关的文章,除了本人的文章,其他的本人不保证可行性。
10 | 如果你也有luch-request 相关的文章想放到这里,可以给我发邮件或者点击下方的`帮助我改善此页面`进行编辑
11 | 如果你不想自己的文章/名字显示到这里,也可以发邮件联系或者qq
12 | 侵权删
13 | 14 | jwt 无痛刷新 15 | ------------ 16 | 17 | #### luch[官方] 18 | [luch-request jwt 无痛刷新最佳实践[推荐]](https://quanzhan.co/archives/51) 19 | 20 | 21 | #### learnku php_yt 22 | uniapp 小程序 Laravel+jwt 权限认证完整系列 23 | 24 | #### dcloud kysin 25 | axios如何利用promise无痛刷新token 26 |
27 | axios如何利用promise无痛刷新token二 28 |
29 | axios+async/await无痛刷新token 30 | 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2022] [luch] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/types-test.ts: -------------------------------------------------------------------------------- 1 | import LuchRequest from "../src/lib/luch-request" 2 | const luchRequest = new LuchRequest(); 3 | 4 | luchRequest.setConfig(config => { 5 | return config 6 | }) 7 | luchRequest.post("url", { 123: 60 }, { 8 | baseURL: "/api" 9 | }).then(response=>{ 10 | response.config 11 | }) 12 | // LuchRequestAbstract 13 | luchRequest 14 | 15 | // LuchRequestConfig 16 | luchRequest.config 17 | 18 | const data = new FormData() 19 | // LuchRequestAbstract.interceptors 20 | luchRequest.interceptors.request.use(config => { 21 | return config 22 | }, (config) => { 23 | return Promise.reject(config) 24 | }) 25 | luchRequest.interceptors.response.use( 26 | response => { 27 | return response.data 28 | }, 29 | (response) => { 30 | return Promise.reject(response) 31 | } 32 | ) 33 | 34 | // mock request login 35 | interface UserInfo { 36 | username: string; 37 | phone: string | number; 38 | } 39 | export const reqLogin = () => { 40 | return luchRequest.get("/api/login") 41 | } 42 | // mock get userInfo 43 | ; (async () => { 44 | const result = await reqLogin() 45 | // interface UserInfo 46 | result.data 47 | }) 48 | 49 | // mock request download 50 | const url = "xxx/xxx/xxx/xxx" 51 | ; (async () => { 52 | const result = await luchRequest.download(url) 53 | result.tempFilePath 54 | }) -------------------------------------------------------------------------------- /docs/acknowledgement/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | title: 鸣谢 4 | --- 5 | 6 | 前言 7 | ------------ 8 | 感谢每一位贡献者
9 | 对插件**做出贡献**或对此插件进行**打赏**,本人将在此处列出,以表示感谢
10 | 贡献者可以提出一个名称、一个网址显示在此处。
11 | 如果你不想自己的名字显示在这里,可以发邮件或者qq向我说明情况
12 | 侵权删! 13 | 14 | 土豪赞赏 15 | ------------ 16 |
17 | wechat 打赏 18 | wechat 打赏 19 | 20 | 21 | 赞助名单 22 | ------------ 23 | - `lishuda@kxtsoft.com` 24 | - qq:`78****245` 25 | - `346****37@qq.com` 26 | - 名字找不到了 0.0 27 | - 记得 28 | - ... 29 | 30 | 插件贡献 31 | ------------ 32 | - 高卓彦 提出`3.0.0`版本存在所有请求都为GET请求bug,已在3.0.1版本修复 33 | - `353754391@qq.com` 提出多实例共用同一全局配置bug 34 | - `370681295@qq.com` - @zouyaoji 提出 ` params ` 选项参数格式化数组等存在问题。已改为axios 参数格式化方案。 35 | - `TuiMao233` - @TuiMao233 提供index.d.ts 文件支持,十分感谢。 36 | - ... 37 | -------------------------------------------------------------------------------- /src/lib/core/InterceptorManager.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | 4 | function InterceptorManager() { 5 | this.handlers = [] 6 | } 7 | 8 | /** 9 | * Add a new interceptor to the stack 10 | * 11 | * @param {Function} fulfilled The function to handle `then` for a `Promise` 12 | * @param {Function} rejected The function to handle `reject` for a `Promise` 13 | * 14 | * @return {Number} An ID used to remove interceptor later 15 | */ 16 | InterceptorManager.prototype.use = function use(fulfilled, rejected) { 17 | this.handlers.push({ 18 | fulfilled: fulfilled, 19 | rejected: rejected 20 | }) 21 | return this.handlers.length - 1 22 | } 23 | 24 | /** 25 | * Remove an interceptor from the stack 26 | * 27 | * @param {Number} id The ID that was returned by `use` 28 | */ 29 | InterceptorManager.prototype.eject = function eject(id) { 30 | if (this.handlers[id]) { 31 | this.handlers[id] = null 32 | } 33 | } 34 | 35 | /** 36 | * Iterate over all the registered interceptors 37 | * 38 | * This method is particularly useful for skipping over any 39 | * interceptors that may have become `null` calling `eject`. 40 | * 41 | * @param {Function} fn The function to call for each interceptor 42 | */ 43 | InterceptorManager.prototype.forEach = function forEach(fn) { 44 | this.handlers.forEach(h => { 45 | if (h !== null) { 46 | fn(h) 47 | } 48 | }) 49 | } 50 | 51 | export default InterceptorManager 52 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/InterceptorManager.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | 4 | function InterceptorManager() { 5 | this.handlers = [] 6 | } 7 | 8 | /** 9 | * Add a new interceptor to the stack 10 | * 11 | * @param {Function} fulfilled The function to handle `then` for a `Promise` 12 | * @param {Function} rejected The function to handle `reject` for a `Promise` 13 | * 14 | * @return {Number} An ID used to remove interceptor later 15 | */ 16 | InterceptorManager.prototype.use = function use(fulfilled, rejected) { 17 | this.handlers.push({ 18 | fulfilled: fulfilled, 19 | rejected: rejected 20 | }) 21 | return this.handlers.length - 1 22 | } 23 | 24 | /** 25 | * Remove an interceptor from the stack 26 | * 27 | * @param {Number} id The ID that was returned by `use` 28 | */ 29 | InterceptorManager.prototype.eject = function eject(id) { 30 | if (this.handlers[id]) { 31 | this.handlers[id] = null 32 | } 33 | } 34 | 35 | /** 36 | * Iterate over all the registered interceptors 37 | * 38 | * This method is particularly useful for skipping over any 39 | * interceptors that may have become `null` calling `eject`. 40 | * 41 | * @param {Function} fn The function to call for each interceptor 42 | */ 43 | InterceptorManager.prototype.forEach = function forEach(fn) { 44 | this.handlers.forEach(h => { 45 | if (h !== null) { 46 | fn(h) 47 | } 48 | }) 49 | } 50 | 51 | export default InterceptorManager 52 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/InterceptorManager.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | 4 | function InterceptorManager() { 5 | this.handlers = [] 6 | } 7 | 8 | /** 9 | * Add a new interceptor to the stack 10 | * 11 | * @param {Function} fulfilled The function to handle `then` for a `Promise` 12 | * @param {Function} rejected The function to handle `reject` for a `Promise` 13 | * 14 | * @return {Number} An ID used to remove interceptor later 15 | */ 16 | InterceptorManager.prototype.use = function use(fulfilled, rejected) { 17 | this.handlers.push({ 18 | fulfilled: fulfilled, 19 | rejected: rejected 20 | }) 21 | return this.handlers.length - 1 22 | } 23 | 24 | /** 25 | * Remove an interceptor from the stack 26 | * 27 | * @param {Number} id The ID that was returned by `use` 28 | */ 29 | InterceptorManager.prototype.eject = function eject(id) { 30 | if (this.handlers[id]) { 31 | this.handlers[id] = null 32 | } 33 | } 34 | 35 | /** 36 | * Iterate over all the registered interceptors 37 | * 38 | * This method is particularly useful for skipping over any 39 | * interceptors that may have become `null` calling `eject`. 40 | * 41 | * @param {Function} fn The function to call for each interceptor 42 | */ 43 | InterceptorManager.prototype.forEach = function forEach(fn) { 44 | this.handlers.forEach(h => { 45 | if (h !== null) { 46 | fn(h) 47 | } 48 | }) 49 | } 50 | 51 | export default InterceptorManager 52 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/InterceptorManager.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | 4 | function InterceptorManager() { 5 | this.handlers = [] 6 | } 7 | 8 | /** 9 | * Add a new interceptor to the stack 10 | * 11 | * @param {Function} fulfilled The function to handle `then` for a `Promise` 12 | * @param {Function} rejected The function to handle `reject` for a `Promise` 13 | * 14 | * @return {Number} An ID used to remove interceptor later 15 | */ 16 | InterceptorManager.prototype.use = function use(fulfilled, rejected) { 17 | this.handlers.push({ 18 | fulfilled: fulfilled, 19 | rejected: rejected 20 | }) 21 | return this.handlers.length - 1 22 | } 23 | 24 | /** 25 | * Remove an interceptor from the stack 26 | * 27 | * @param {Number} id The ID that was returned by `use` 28 | */ 29 | InterceptorManager.prototype.eject = function eject(id) { 30 | if (this.handlers[id]) { 31 | this.handlers[id] = null 32 | } 33 | } 34 | 35 | /** 36 | * Iterate over all the registered interceptors 37 | * 38 | * This method is particularly useful for skipping over any 39 | * interceptors that may have become `null` calling `eject`. 40 | * 41 | * @param {Function} fn The function to call for each interceptor 42 | */ 43 | InterceptorManager.prototype.forEach = function forEach(fn) { 44 | this.handlers.forEach(h => { 45 | if (h !== null) { 46 | fn(h) 47 | } 48 | }) 49 | } 50 | 51 | export default InterceptorManager 52 | -------------------------------------------------------------------------------- /src/lib/helpers/buildURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import * as utils from './../utils' 4 | 5 | function encode(val) { 6 | return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']') 7 | } 8 | 9 | /** 10 | * Build a URL by appending params to the end 11 | * 12 | * @param {string} url The base of the url (e.g., http://www.google.com) 13 | * @param {object} [params] The params to be appended 14 | * @returns {string} The formatted url 15 | */ 16 | export default function buildURL(url, params, paramsSerializer) { 17 | /*eslint no-param-reassign:0*/ 18 | if (!params) { 19 | return url 20 | } 21 | 22 | var serializedParams 23 | if (paramsSerializer) { 24 | serializedParams = paramsSerializer(params) 25 | } else if (utils.isURLSearchParams(params)) { 26 | serializedParams = params.toString() 27 | } else { 28 | var parts = [] 29 | 30 | utils.forEach(params, function serialize(val, key) { 31 | if (val === null || typeof val === 'undefined') { 32 | return 33 | } 34 | 35 | if (utils.isArray(val)) { 36 | key = key + '[]' 37 | } else { 38 | val = [val] 39 | } 40 | 41 | utils.forEach(val, function parseValue(v) { 42 | if (utils.isDate(v)) { 43 | v = v.toISOString() 44 | } else if (utils.isObject(v)) { 45 | v = JSON.stringify(v) 46 | } 47 | parts.push(encode(key) + '=' + encode(v)) 48 | }) 49 | }) 50 | 51 | serializedParams = parts.join('&') 52 | } 53 | 54 | if (serializedParams) { 55 | var hashmarkIndex = url.indexOf('#') 56 | if (hashmarkIndex !== -1) { 57 | url = url.slice(0, hashmarkIndex) 58 | } 59 | 60 | url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams 61 | } 62 | 63 | return url 64 | } 65 | -------------------------------------------------------------------------------- /DCloud/luch-request/helpers/buildURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import * as utils from './../utils' 4 | 5 | function encode(val) { 6 | return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']') 7 | } 8 | 9 | /** 10 | * Build a URL by appending params to the end 11 | * 12 | * @param {string} url The base of the url (e.g., http://www.google.com) 13 | * @param {object} [params] The params to be appended 14 | * @returns {string} The formatted url 15 | */ 16 | export default function buildURL(url, params, paramsSerializer) { 17 | /*eslint no-param-reassign:0*/ 18 | if (!params) { 19 | return url 20 | } 21 | 22 | var serializedParams 23 | if (paramsSerializer) { 24 | serializedParams = paramsSerializer(params) 25 | } else if (utils.isURLSearchParams(params)) { 26 | serializedParams = params.toString() 27 | } else { 28 | var parts = [] 29 | 30 | utils.forEach(params, function serialize(val, key) { 31 | if (val === null || typeof val === 'undefined') { 32 | return 33 | } 34 | 35 | if (utils.isArray(val)) { 36 | key = key + '[]' 37 | } else { 38 | val = [val] 39 | } 40 | 41 | utils.forEach(val, function parseValue(v) { 42 | if (utils.isDate(v)) { 43 | v = v.toISOString() 44 | } else if (utils.isObject(v)) { 45 | v = JSON.stringify(v) 46 | } 47 | parts.push(encode(key) + '=' + encode(v)) 48 | }) 49 | }) 50 | 51 | serializedParams = parts.join('&') 52 | } 53 | 54 | if (serializedParams) { 55 | var hashmarkIndex = url.indexOf('#') 56 | if (hashmarkIndex !== -1) { 57 | url = url.slice(0, hashmarkIndex) 58 | } 59 | 60 | url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams 61 | } 62 | 63 | return url 64 | } 65 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/helpers/buildURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import * as utils from './../utils' 4 | 5 | function encode(val) { 6 | return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']') 7 | } 8 | 9 | /** 10 | * Build a URL by appending params to the end 11 | * 12 | * @param {string} url The base of the url (e.g., http://www.google.com) 13 | * @param {object} [params] The params to be appended 14 | * @returns {string} The formatted url 15 | */ 16 | export default function buildURL(url, params, paramsSerializer) { 17 | /*eslint no-param-reassign:0*/ 18 | if (!params) { 19 | return url 20 | } 21 | 22 | var serializedParams 23 | if (paramsSerializer) { 24 | serializedParams = paramsSerializer(params) 25 | } else if (utils.isURLSearchParams(params)) { 26 | serializedParams = params.toString() 27 | } else { 28 | var parts = [] 29 | 30 | utils.forEach(params, function serialize(val, key) { 31 | if (val === null || typeof val === 'undefined') { 32 | return 33 | } 34 | 35 | if (utils.isArray(val)) { 36 | key = key + '[]' 37 | } else { 38 | val = [val] 39 | } 40 | 41 | utils.forEach(val, function parseValue(v) { 42 | if (utils.isDate(v)) { 43 | v = v.toISOString() 44 | } else if (utils.isObject(v)) { 45 | v = JSON.stringify(v) 46 | } 47 | parts.push(encode(key) + '=' + encode(v)) 48 | }) 49 | }) 50 | 51 | serializedParams = parts.join('&') 52 | } 53 | 54 | if (serializedParams) { 55 | var hashmarkIndex = url.indexOf('#') 56 | if (hashmarkIndex !== -1) { 57 | url = url.slice(0, hashmarkIndex) 58 | } 59 | 60 | url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams 61 | } 62 | 63 | return url 64 | } 65 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/helpers/buildURL.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import * as utils from './../utils' 4 | 5 | function encode(val) { 6 | return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']') 7 | } 8 | 9 | /** 10 | * Build a URL by appending params to the end 11 | * 12 | * @param {string} url The base of the url (e.g., http://www.google.com) 13 | * @param {object} [params] The params to be appended 14 | * @returns {string} The formatted url 15 | */ 16 | export default function buildURL(url, params, paramsSerializer) { 17 | /*eslint no-param-reassign:0*/ 18 | if (!params) { 19 | return url 20 | } 21 | 22 | var serializedParams 23 | if (paramsSerializer) { 24 | serializedParams = paramsSerializer(params) 25 | } else if (utils.isURLSearchParams(params)) { 26 | serializedParams = params.toString() 27 | } else { 28 | var parts = [] 29 | 30 | utils.forEach(params, function serialize(val, key) { 31 | if (val === null || typeof val === 'undefined') { 32 | return 33 | } 34 | 35 | if (utils.isArray(val)) { 36 | key = key + '[]' 37 | } else { 38 | val = [val] 39 | } 40 | 41 | utils.forEach(val, function parseValue(v) { 42 | if (utils.isDate(v)) { 43 | v = v.toISOString() 44 | } else if (utils.isObject(v)) { 45 | v = JSON.stringify(v) 46 | } 47 | parts.push(encode(key) + '=' + encode(v)) 48 | }) 49 | }) 50 | 51 | serializedParams = parts.join('&') 52 | } 53 | 54 | if (serializedParams) { 55 | var hashmarkIndex = url.indexOf('#') 56 | if (hashmarkIndex !== -1) { 57 | url = url.slice(0, hashmarkIndex) 58 | } 59 | 60 | url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams 61 | } 62 | 63 | return url 64 | } 65 | -------------------------------------------------------------------------------- /test/dev-test/uni.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里是uni-app内置的常用样式变量 3 | * 4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App 6 | * 7 | */ 8 | 9 | /** 10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 11 | * 12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 13 | */ 14 | 15 | /* 颜色变量 */ 16 | 17 | /* 行为相关颜色 */ 18 | $uni-color-primary: #007aff; 19 | $uni-color-success: #4cd964; 20 | $uni-color-warning: #f0ad4e; 21 | $uni-color-error: #dd524d; 22 | 23 | /* 文字基本颜色 */ 24 | $uni-text-color:#333;//基本色 25 | $uni-text-color-inverse:#fff;//反色 26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 27 | $uni-text-color-placeholder: #808080; 28 | $uni-text-color-disable:#c0c0c0; 29 | 30 | /* 背景颜色 */ 31 | $uni-bg-color:#ffffff; 32 | $uni-bg-color-grey:#f8f8f8; 33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色 34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 35 | 36 | /* 边框颜色 */ 37 | $uni-border-color:#c8c7cc; 38 | 39 | /* 尺寸变量 */ 40 | 41 | /* 文字尺寸 */ 42 | $uni-font-size-sm:24rpx; 43 | $uni-font-size-base:28rpx; 44 | $uni-font-size-lg:32rpx; 45 | 46 | /* 图片尺寸 */ 47 | $uni-img-size-sm:40rpx; 48 | $uni-img-size-base:52rpx; 49 | $uni-img-size-lg:80rpx; 50 | 51 | /* Border Radius */ 52 | $uni-border-radius-sm: 4rpx; 53 | $uni-border-radius-base: 6rpx; 54 | $uni-border-radius-lg: 12rpx; 55 | $uni-border-radius-circle: 50%; 56 | 57 | /* 水平间距 */ 58 | $uni-spacing-row-sm: 10px; 59 | $uni-spacing-row-base: 20rpx; 60 | $uni-spacing-row-lg: 30rpx; 61 | 62 | /* 垂直间距 */ 63 | $uni-spacing-col-sm: 8rpx; 64 | $uni-spacing-col-base: 16rpx; 65 | $uni-spacing-col-lg: 24rpx; 66 | 67 | /* 透明度 */ 68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 69 | 70 | /* 文章场景相关 */ 71 | $uni-color-title: #2C405A; // 文章标题颜色 72 | $uni-font-size-title:40rpx; 73 | $uni-color-subtitle: #555555; // 二级标题颜色 74 | $uni-font-size-subtitle:36rpx; 75 | $uni-color-paragraph: #3F536E; // 文章段落颜色 76 | $uni-font-size-paragraph:30rpx; -------------------------------------------------------------------------------- /example/request-demo/uni.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里是uni-app内置的常用样式变量 3 | * 4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App 6 | * 7 | */ 8 | 9 | /** 10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 11 | * 12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 13 | */ 14 | 15 | /* 颜色变量 */ 16 | 17 | /* 行为相关颜色 */ 18 | $uni-color-primary: #007aff; 19 | $uni-color-success: #4cd964; 20 | $uni-color-warning: #f0ad4e; 21 | $uni-color-error: #dd524d; 22 | 23 | /* 文字基本颜色 */ 24 | $uni-text-color:#333;//基本色 25 | $uni-text-color-inverse:#fff;//反色 26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 27 | $uni-text-color-placeholder: #808080; 28 | $uni-text-color-disable:#c0c0c0; 29 | 30 | /* 背景颜色 */ 31 | $uni-bg-color:#ffffff; 32 | $uni-bg-color-grey:#f8f8f8; 33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色 34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 35 | 36 | /* 边框颜色 */ 37 | $uni-border-color:#c8c7cc; 38 | 39 | /* 尺寸变量 */ 40 | 41 | /* 文字尺寸 */ 42 | $uni-font-size-sm:24upx; 43 | $uni-font-size-base:28upx; 44 | $uni-font-size-lg:32upx; 45 | 46 | /* 图片尺寸 */ 47 | $uni-img-size-sm:40upx; 48 | $uni-img-size-base:52upx; 49 | $uni-img-size-lg:80upx; 50 | 51 | /* Border Radius */ 52 | $uni-border-radius-sm: 4upx; 53 | $uni-border-radius-base: 6upx; 54 | $uni-border-radius-lg: 12upx; 55 | $uni-border-radius-circle: 50%; 56 | 57 | /* 水平间距 */ 58 | $uni-spacing-row-sm: 10px; 59 | $uni-spacing-row-base: 20upx; 60 | $uni-spacing-row-lg: 30upx; 61 | 62 | /* 垂直间距 */ 63 | $uni-spacing-col-sm: 8upx; 64 | $uni-spacing-col-base: 16upx; 65 | $uni-spacing-col-lg: 24upx; 66 | 67 | /* 透明度 */ 68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 69 | 70 | /* 文章场景相关 */ 71 | $uni-color-title: #2C405A; // 文章标题颜色 72 | $uni-font-size-title:40upx; 73 | $uni-color-subtitle: #555555; // 二级标题颜色 74 | $uni-font-size-subtitle:36upx; 75 | $uni-color-paragraph: #3F536E; // 文章段落颜色 76 | $uni-font-size-paragraph:30upx; -------------------------------------------------------------------------------- /example/request-demo/pages/goods-list/goods-list.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 65 | 66 | 92 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /assets/img/logo.jpg 4 | heroText: luch-request 5 | tagline: 基于Promise开发的uni-app跨平台请求库 6 | actionText: 快速上手 → 7 | actionLink: /handbook/ 8 | features: 9 | - title: 项目级别 10 | details: 更小的体积,易用的api,方便的自定义能力。 11 | - title: 稳定维护 12 | details: luch-request 至今已至少有17个版本的迭代。下载次数超1W。 13 | - title: 代码简洁 14 | details: 插件使用es6,es7 开发,使代码的可读性很高,源码清晰明了。 15 | - title: 条件编译 16 | details: 插件开发使用了`条件编译`避免了不同终端可能产生的冗余代码。 17 | - title: 规范 18 | details: eslint、rollup等构建工具辅助开发。 19 | - title: 方便简单的自定义能力 20 | details: 有` custom ` 自定义参数的支持,满足你所有的自定义要求。 21 | footer: MIT Licensed | Copyright © 2020-2023 quanzhan.co 22 | --- 23 | 24 |

25 | 友情链接 26 |

27 | 34 | 37 | 38 | 78 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | // import resolve from 'rollup-plugin-node-resolve' 2 | // import babel from 'rollup-plugin-babel' 3 | // import json from 'rollup-plugin-json' 4 | // import commonjs from 'rollup-plugin-commonjs' 5 | // import replace from 'rollup-plugin-replace' 6 | import {eslint} from 'rollup-plugin-eslint' 7 | // import {uglify} from 'rollup-plugin-uglify' 8 | // 配置服务 9 | // import liveServer from 'rollup-plugin-live-server' 10 | import copy from 'rollup-plugin-copy' 11 | // var path = require('path'); 12 | 13 | // const mode = process.env.NODE_ENV 14 | // const isWatch = process.env.ROLLUP_WATCH 15 | // const zip = require('rollup-plugin-zip') 16 | 17 | // console.log('执行环境:', mode) 18 | 19 | // const isProd = mode === 'production' 20 | 21 | export default { 22 | input: 'src/lib/luch-request.js', 23 | output: { 24 | file: 'dist/index.js', 25 | format: 'umd', 26 | name: 'LuChRequest', 27 | globals: {}, 28 | sourcemap: true 29 | }, 30 | external: [], 31 | plugins: [ 32 | // json(), 33 | eslint(), 34 | // replace({ 35 | // 'process.env.NODE_ENV': JSON.stringify(mode) 36 | // }), 37 | // resolve(), 38 | // babel({ 39 | // runtimeHelpers: true, 40 | // exclude : ['node_modules/**'] 41 | // }), 42 | // commonjs(), 43 | // isWatch && liveServer({ 44 | // port: 3000, 45 | // root: 'test', 46 | // file: 'index.html', 47 | // open: false, 48 | // wait: 500 49 | // }), 50 | // isProd && uglify({ 51 | // // comments: ['all'], 52 | // output: { 53 | // // 最紧凑的输出 54 | // // beautify: false, 55 | // // 删除所有的注释 56 | // // comments: ['all'], 57 | // }, 58 | // warnings: false, 59 | // compress: { 60 | // // comments: ['all'], 61 | // pure_getters: true, 62 | // unsafe: true, 63 | // unsafe_comps: true, 64 | // } 65 | // }) 66 | copy({ 67 | targets: [ 68 | {src: ['src/lib/utils.js', 'src/lib/core', 'src/lib/helpers', 'src/lib/utils', 'src/lib/adapters'], dest: 'DCloud/luch-request'}, 69 | {src: 'src/lib/luch-request.js', dest: 'DCloud/luch-request', rename: 'index.js'}, 70 | {src: 'src/lib/luch-request.d.ts', dest: 'DCloud/luch-request', rename: 'index.d.ts'}, 71 | {src: ['example/request-demo'], dest: 'DCloud/'}, 72 | ] 73 | }), 74 | // zip({ 75 | // file: 'DCloud/luch-request.zip', 76 | // dir: './DCloud/luch-request' 77 | // }) 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | ## [3.1.1](https://github.com/lei-mu/luch-request/compare/3.1.0-alpha.0...3.1.1) (2023-08-02) 2 | 3 | 4 | 5 | 6 | ## [3.1.0](https://github.com/lei-mu/luch-request/compare/3.0.8...3.1.0) (2023-05-25) 7 | 8 | 9 | ### Features 10 | 11 | * 更新请求新配置项。新增‘是否尝试将响应数据json化’配置项。 ([68344a1](https://github.com/lei-mu/luch-request/commit/68344a1d9dcbf586d4a0aff37d02aa0bb27ff45c)), closes [#113](https://github.com/lei-mu/luch-request/issues/113) 12 | * 增加`version` 属性,获取插件版本号 ([40403d2](https://github.com/lei-mu/luch-request/commit/40403d2ef57dead0f577a384ac686cc7dcc772da)) 13 | 14 | 15 | 16 | 17 | ## [3.0.8](https://github.com/lei-mu/luch-request/compare/3.0.7...3.0.8) (2022-08-23) 18 | 19 | 20 | ### Features 21 | 22 | * `put` 方法增加快手小程序和京东小程序的支持 ([7e15dff](https://github.com/lei-mu/luch-request/commit/7e15dff0ac343ccbd6a298c7c9ae8ef0e2148eb9)) 23 | * 参考axio源代码 添加支持paramsSerializer。 ([cae1043](https://github.com/lei-mu/luch-request/commit/cae10430dc7222d85e0cadb13512898d66998547)) 24 | * 返回数据增加`rawData`,保留返回的原始数据 ([3924b7c](https://github.com/lei-mu/luch-request/commit/3924b7c3ea444526be436a31f9e7d5623749580b)) 25 | * 局部请求配置支持baseURL ([df2d98f](https://github.com/lei-mu/luch-request/commit/df2d98fc063f356ffd525158e9cd47d7eb24f68f)) 26 | 27 | 28 | 29 | 30 | ## 3.0.7 (2021-09-04) 31 | 32 | 1. Bug Fix: 修复通过 `Request.config` 设置全局参数,多个实例`config`存在共同引用bug 33 | 34 | 35 | ## 3.0.6 (2021-05-10) 36 | 37 | 1. New Feature: APP端 增加`responseType`配置项 38 | 39 | ## 3.0.5 (2021-01-10) 40 | ### Features 41 | 42 | * [重要] APP不再支持`CONNECT`、`HEAD`、`TRACE`请求方式。[uni.request](https://uniapp.dcloud.io/api/request/request) 43 | * [重要]全局默认`timeout`由`30000`ms,改为`60000`ms 44 | * [重要]增加`index.d.ts`文件支持。感谢`Mr_Mao`的支持。github:`https://github.com/TuiMao233` 45 | * [重要]网络请求相关接口 uni.request、uni.uploadFile、uni.downloadFile 支持 timeout 参数。 46 | * [重要]返回结果response 增加`fullPath`参数。 47 | 48 | ## 3.0.4 (2020-07-05) 49 | 50 | 1. New Feature: request 方法增加 ` firstIpv4 `配置项 51 | 1. New Feature: 增加 ` middleware `通用请求方法 52 | 53 | ## 3.0.3 (2020-06-16) 54 | 55 | 1. Bug Fix: 修复` params ` 选项对数组格式化错误bug 56 | 57 | ## 3.0.2 (2020-06-04) 58 | 59 | 1. Bug Fix: 修复文件上传和request 配置缺少字段bug 60 | 61 | ## 3.0.1 (2020-06-02) 62 | 63 | 1. Bug Fix: 请求方式都为` GET `的bug 64 | 65 | ## 3.0.0 (2020-06-01) 66 | 67 | 1. New Feature: 支持多拦截器 68 | 1. New Feature: 支持局部配置自定义验证器 69 | 70 | ## 2.0.1 (2020-05-01) 71 | 72 | 1. Bug Fix: 修复多实例全局配置共用问题 73 | 74 | ## 2.0.0 (2020-04-24) 75 | 76 | 1. New Feature: 增加 request ` withCredentials `选项(仅h5端支持) 77 | 1. New Feature: h5端 upload 增加 ` files ` ` file `选项。[uni.uploadFile](https://uniapp.dcloud.io/api/request/network-file?id=uploadfile "uni.uploadFile") 78 | 1. Enhancement: ` params ` 选项参数格式化方法使用axios 格式化方法 79 | 1. Bug Fix: 对upload 返回data 为空字符串的情况容错 80 | 1. Change: 修改header与全局合并方式。当前:header = Object.assign(全局,局部) 81 | 82 | ## 0.0.0 (2019-05) 83 | 84 | 1. luch-request created 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/issue/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | title: 常见问题 4 | --- 5 | 6 | # 常见问题 7 | 8 | ## 如果cli 用户npm 引入报错? 9 | 10 | 插件使用es6,es7 开发,好处就是结构清晰,语义化,开发代码少,并且对于目前的我来说,完全没有必要使用es5开发。 11 |
12 | 为什么不用babel解决:babel 编译后的代码对uni的条件编译注释不友好。如果不用条件编译则不能发挥最大优势。 13 |
14 | 这样存在的问题:对于HBuilderX 创建的项目完全没有影响,idea 会对node_modules 里的插件条件编译,并且babel。主要是cli 用户,cli 不会对node_modules 里的代码babel。 15 |
16 | 可尝试如下配置 17 | ``` javascript 18 | // vue.config.js 19 | module.exports = { 20 | transpileDependencies: ['luch-request'] 21 | } 22 | ``` 23 | 24 | 25 | ## 为什么会请求两次? 26 | 27 | 如果其中有`options` 请求:`本地访问接口时跨域请求,所以浏览器会先发一个option 去预测能否成功,然后再发一个真正的请求`。(自己观察请求头,Request Method,百度`简单请求`) 28 | 29 | ## 如何跨域? 30 | 31 | 问的人不少,可以先百度了解一下。如何跨域 32 | 33 | ## `TypeError: undefined is not an object (evaluating 'this.$http.get')` 34 | 35 | 不知道为啥问的人这么多?太基础了,百度学习一下 export default 和export,头大。
36 | `import { http } from '@/utils/luch-request/index.js'` 37 | 38 | ## 什么参数需要在` setConfig ` 设置?什么参数需要在` request ` 拦截器设置? 39 | 40 | - ` setConfig ` 适用于设置一些静态的/默认的参数;比如header 里的一些默认值、默认全局参数(全局请求配置)。` token ` 并不适合在这里设置。 41 | - ` interceptors.request ` 拦截器适用范围较广,但我仍然建议把一些静态的东西放在 ` setConfig ` 里。拦截器会在每次请求调用,而 ` setConfig ` 仅在调用时修改一遍。 42 | 43 | ## 如何jwt无痛刷新? 44 | 45 | [jwt无痛刷新](/resources/article.html#jwt-%E6%97%A0%E7%97%9B%E5%88%B7%E6%96%B0) 46 | 47 | ## 如何配置超时时间? 48 | 49 | **全局** 50 | 51 | 网络请求的 超时时间 可以统一在 manifest.json 中配置 [networkTimeout](https://uniapp.dcloud.io/collocation/manifest?id=networktimeout) 52 | 53 | 插件的全局配置超时时间:[插件-全局请求配置-timeout](/guide/3.x/#%E5%8F%AF%E9%85%8D%E7%BD%AE%E9%A1%B9)。必须请求方法和终端支持`timeout`,支持度参照[timeout 支持度](/guide/3.x/#middleware) 54 | 55 | **局部** 56 | 57 | 局部配置项`timeout`:[timeout](/guide/3.x/#request)。必须请求方法和终端支持`timeout`,支持度参照[timeout 支持度](/guide/3.x/#middleware) 58 | 59 | 如果终端和请求方式不支持`timeout`,可参考如下实现 60 | ```` javascript 61 | http.request({ 62 | method: 'POST', // 请求方法必须大写 [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] 63 | url: '/user/12345', 64 | data: { 65 | firstName: 'Fred', 66 | lastName: 'Flintstone' 67 | }, 68 | params: { // 会拼接到url上 69 | token: '1111' 70 | }, 71 | // 返回当前请求的task, options。请勿在此处修改options。非必填 72 | getTask: (task, options) => { 73 | // 500ms 后终止请求 74 | setTimeout(() => { 75 | task.abort() 76 | }, 500) 77 | } 78 | }) 79 | ```` 80 | 81 | ## 发送FormData? 82 | 83 | uni 不支持发送`FormData`对象 84 | 85 | 对于 POST 方法且 header['content-type'] 为 application/json 的数据,会进行 JSON 序列化。 86 | 87 | 对于 POST 方法且 header['content-type'] 为 application/x-www-form-urlencoded 的数据,会将数据转换为 query string。 88 | 89 | 所以,如果你想发送formData 类型数据,请将`header['content-type']` 设置为 `application/x-www-form-urlencoded`。 90 | 91 | 如果你的formData 里有`file` 怎么办?请使用插件的[upload](/guide/3.x/#upload)方法。 92 | 93 | 94 | 95 | ## 后台返回bigInt类型处理? 96 | `3.0.8`版本给`response` 新增 `rawData` 字段,保存原始数据。请在拦截器自定义处理该字段。或者局部处理。 -------------------------------------------------------------------------------- /example/request-demo/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "request-demo", 3 | "appid" : "", 4 | "description": "", 5 | "versionName": "1.0.0", 6 | "versionCode": "100", 7 | "transformPx": false, 8 | /* 5+App特有相关 */ 9 | "app-plus": { 10 | "usingComponents": true, 11 | "splashscreen": { 12 | "alwaysShowBeforeRender": true, 13 | "waiting": true, 14 | "autoclose": true, 15 | "delay": 0 16 | }, 17 | /* 模块配置 */ 18 | "modules": { 19 | 20 | }, 21 | /* 应用发布信息 */ 22 | "distribute": { 23 | /* android打包配置 */ 24 | "android": { 25 | "permissions": ["", 26 | "", 27 | "", 28 | "", 29 | "", 30 | "", 31 | "", 32 | "", 33 | "", 34 | "", 35 | "", 36 | "", 37 | "", 38 | "", 39 | "", 40 | "", 41 | "", 42 | "", 43 | "", 44 | "", 45 | "", 46 | "" 47 | ] 48 | }, 49 | /* ios打包配置 */ 50 | "ios": { 51 | 52 | }, 53 | /* SDK配置 */ 54 | "sdkConfigs": { 55 | 56 | } 57 | } 58 | }, 59 | /* 快应用特有相关 */ 60 | "quickapp": { 61 | 62 | }, 63 | /* 小程序特有相关 */ 64 | "mp-weixin": { 65 | "appid": "", 66 | "setting": { 67 | "urlCheck": false 68 | }, 69 | "usingComponents": true 70 | }, 71 | "mp-alipay" : { 72 | "usingComponents" : true 73 | }, 74 | "mp-baidu" : { 75 | "usingComponents" : true 76 | }, 77 | "mp-toutiao" : { 78 | "usingComponents" : true 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/dev-test/api/service.js: -------------------------------------------------------------------------------- 1 | 2 | import Request from '@/utils/luch-request/index.js' 3 | 4 | 5 | const getTokenStorage = () => { 6 | let token = '' 7 | try { 8 | token = uni.getStorageSync('token') 9 | } catch (e) { 10 | //TODO handle the exception 11 | } 12 | return token 13 | } 14 | 15 | const test = new Request() 16 | /** 17 | * 修改全局配置示例 18 | const test = new Request({ 19 | header: {a:1}, // 举例 20 | baseURL: 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest', 21 | validateStatus: (statusCode) => { // statusCode 必存在。此处示例为全局默认配置 22 | return statusCode >= 200 && statusCode < 300 23 | } 24 | }) 25 | test.config.baseURL = 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest' 26 | **/ 27 | 28 | test.setConfig((config) => { /* 设置全局配置 */ 29 | config.baseURL = 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest' 30 | config.header = { 31 | ...config.header, 32 | a: 1, // 演示 33 | b: 2 // 演示 34 | } 35 | return config 36 | }) 37 | 38 | test.interceptors.request.use((config) => { /* 请求之前拦截器。可以使用async await 做异步操作 */ 39 | config.header = { 40 | ...config.header, 41 | a: 3 // 演示 42 | } 43 | /* 44 | if (!token) { // 如果token不存在,return Promise.reject(config) 会取消本次请求 45 | return Promise.reject(config) 46 | } 47 | */ 48 | return config 49 | }, (config) => { 50 | return Promise.reject(config) 51 | }) 52 | 53 | 54 | test.interceptors.response.use((response) => { /* 请求之后拦截器。可以使用async await 做异步操作 */ 55 | if (response.data.code !== 200) { // 服务端返回的状态码不等于200,则reject() 56 | return Promise.reject(response) 57 | } 58 | return response 59 | }, (response) => { // 请求错误做点什么。可以使用async await 做异步操作 60 | return Promise.reject(response) 61 | }) 62 | 63 | 64 | const http = new Request() 65 | http.setConfig((config) => { /* 设置全局配置 */ 66 | config.baseURL = 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest' /* 根域名不同 */ 67 | config.header = { 68 | ...config.header, 69 | a: 1, // 演示 70 | b: 2 // 演示 71 | } 72 | console.log('全局默认config'); 73 | console.log(config); 74 | return config 75 | }) 76 | 77 | 78 | http.interceptors.request.use((config) => { /* 请求之前拦截器。可以使用async await 做异步操作 */ 79 | config.header = { 80 | ...config.header, 81 | token: getTokenStorage() 82 | } 83 | /* 84 | if (!token) { // 如果token不存在,return Promise.reject(config) 会取消本次请求 85 | return Promise.reject(config) 86 | } 87 | */ 88 | return config 89 | }, (config) => { 90 | return Promise.reject(config) 91 | }) 92 | 93 | // 必须使用异步函数,注意 94 | http.interceptors.response.use(async (response) => { /* 请求之后拦截器。可以使用async await 做异步操作 */ 95 | // if (response.data.code !== 200) { // 服务端返回的状态码不等于200,则reject() 96 | // return Promise.reject(response) 97 | // } 98 | return response 99 | }, (response) => { // 请求错误做点什么。可以使用async await 做异步操作 100 | console.log(response) 101 | return Promise.reject(response) 102 | }) 103 | 104 | export { 105 | http, 106 | test 107 | } 108 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | locales: { 3 | '/': { 4 | lang: 'zh-CN', 5 | title: 'luch-request', 6 | description: 'luch-request 是一个基于Promise开发的uni-app跨平台、项目级别的请求库,它有更小的体积,易用的api,方便简单的自定义能力。luch-request官网,luch的博客,uni-app,request插件,uni request封装,uni request插件' 7 | } 8 | }, 9 | base: '/luch-request/', 10 | title: 'luch-request', 11 | description: 'luch-request 是一个基于Promise开发的uni-app跨平台、项目级别的请求库,它有更小的体积,易用的api,方便简单的自定义能力。luch-request官网,luch的博客,uni-app,request插件,uni request封装,uni request插件', 12 | head: [ 13 | ['meta', {'http-equiv': 'X-UA-Compatible', content: 'IE=Edge'}], 14 | ['meta', {'name': 'renderer', content: 'webkit'}], 15 | ['meta', {'name': 'author', content: 'luch'}], 16 | ['meta', {'name': 'keywords', content: 'luch,luch-requst,luch-request官网,luch的个人博客,uni-app,request插件,uni request封装,uni request插件'}], 17 | ['script', {}, ` 18 | var _hmt = _hmt || []; 19 | (function() { 20 | var hm = document.createElement("script"); 21 | hm.src = "https://hm.baidu.com/hm.js?d64f5f90a8b778dcc6ae876318d0b091"; 22 | var s = document.getElementsByTagName("script")[0]; 23 | s.parentNode.insertBefore(hm, s); 24 | })(); 25 | `] 26 | ], 27 | themeConfig: { 28 | // 假定是 GitHub. 同时也可以是一个完整的 GitLab URL 29 | repo: 'https://github.com/lei-mu/luch-request', 30 | // 自定义仓库链接文字。默认从 `themeConfig.repo` 中自动推断为 31 | // "GitHub"/"GitLab"/"Bitbucket" 其中之一,或是 "Source"。 32 | // repoLabel: '查看源码', 33 | 34 | // 以下为可选的编辑链接选项 35 | // 假如文档不是放在仓库的根目录下: 36 | docsDir: 'docs', 37 | // 假如文档放在一个特定的分支下: 38 | docsBranch: 'docs', 39 | // 默认是 false, 设置为 true 来启用 40 | editLinks: true, 41 | // 默认为 "Edit this page" 42 | editLinkText: '帮助我改善此页面!', 43 | nav: [ 44 | {text: '首页', link: '/'}, 45 | { 46 | text: '文档', 47 | ariaLabel: '文档', 48 | items: [ 49 | {text: '3.x文档', link: '/guide/3.x/'}, 50 | {text: '2.x文档', link: '/guide/2.x/'}, 51 | ] 52 | }, 53 | {text: '指南', link: '/handbook/'}, 54 | {text: '常见问题', link: '/issue/'}, 55 | {text: '更新记录', link: 'https://github.com/lei-mu/luch-request/releases', target: '_blank', rel: 'nofollow noopener noreferrer'}, 56 | { 57 | text: '相关资源', 58 | ariaLabel: '相关资源', 59 | items: [ 60 | {text: '相关文章', link: '/resources/article'} 61 | ] 62 | }, 63 | {text: '鸣谢', link: '/acknowledgement/'}, 64 | {text: '博客', link: 'https://www.quanzhan.co/', target: '_blank'}, 65 | { 66 | text: 'DCloud', 67 | ariaLabel: 'DCloud', 68 | items: [ 69 | {text: '插件市场', link: 'https://ext.dcloud.net.cn/plugin?id=392', target: '_blank', rel: 'nofollow noopener noreferrer'}, 70 | {text: '社区', link: 'https://ask.dcloud.net.cn/question/74922', target: '_blank', rel: 'nofollow noopener noreferrer'} 71 | ] 72 | } 73 | ], 74 | lastUpdated: 'Last Updated', 75 | }, 76 | plugins: [ 77 | ['@vuepress/pwa',{ 78 | serviceWorker: true, 79 | updatePopup: { 80 | message: '此文档有新的内容', // defaults to 'New content is available.' 81 | buttonText: '更新' // defaults to 'Refresh' 82 | } 83 | }], 84 | '@vuepress/active-header-links' 85 | ], 86 | smoothScroll: true 87 | } 88 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "luch-request", 3 | "version": "3.1.1", 4 | "description": "基于Promise实现uni-app request 请求插件", 5 | "keywords": [ 6 | "uni-app", 7 | "request", 8 | "Promise", 9 | "luch", 10 | "luch-request" 11 | ], 12 | "main": "src/lib/luch-request.js", 13 | "scripts": { 14 | "dev": "rollup -c", 15 | "watch": "rollup -c -w", 16 | "build": "rimraf DCloud && rollup -c --environment NODE_ENV:production", 17 | "zipD": "node node/zipDCloudPlugin.js && node node/zipDCloudDemo.js", 18 | "docs": "vuepress dev docs", 19 | "docs:build": "vuepress build docs", 20 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0", 21 | "pub": "npm publish && cnpm sync luch-request", 22 | "pub:alpha": "npm publish --tag=alpha && cnpm sync luch-request", 23 | "test": "echo \"Error: no test specified\" && exit 1" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/lei-mu/luch-request.git" 28 | }, 29 | "author": "luch", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/lei-mu/luch-request/issues" 33 | }, 34 | "homepage": "https://www.quanzhan.co/luch-request/", 35 | "devDependencies": { 36 | "@babel/core": "^7.9.0", 37 | "@babel/plugin-proposal-class-properties": "^7.8.3", 38 | "@babel/plugin-transform-arrow-functions": "^7.8.3", 39 | "@babel/preset-env": "^7.9.5", 40 | "@vuepress/plugin-active-header-links": "^1.5.0", 41 | "@vuepress/plugin-pwa": "^1.5.2", 42 | "archiver": "^4.0.1", 43 | "babel-eslint": "^10.1.0", 44 | "babel-preset-es2015": "^6.24.1", 45 | "commitizen": "^4.2.4", 46 | "conventional-changelog-cli": "^2.1.1", 47 | "cz-conventional-changelog": "^3.2.0", 48 | "eslint": "^6.8.0", 49 | "grunt": "^1.1.0", 50 | "grunt-babel": "^8.0.0", 51 | "load-grunt-tasks": "^5.1.0", 52 | "node-zip": "^1.1.1", 53 | "rollup": "^2.66.1", 54 | "rollup-plugin-babel": "^4.4.0", 55 | "rollup-plugin-commonjs": "^10.1.0", 56 | "rollup-plugin-copy": "^3.3.0", 57 | "rollup-plugin-eslint": "^7.0.0", 58 | "rollup-plugin-json": "^4.0.0", 59 | "rollup-plugin-live-server": "^1.0.3", 60 | "rollup-plugin-node-resolve": "^5.2.0", 61 | "rollup-plugin-replace": "^2.2.0", 62 | "rollup-plugin-uglify": "^6.0.4", 63 | "rollup-plugin-zip": "^1.0.0", 64 | "validate-commit-msg": "^2.14.0", 65 | "vuepress": "^1.4.1" 66 | }, 67 | "engines": { 68 | }, 69 | "config": { 70 | "commitizen": { 71 | "path": "./node_modules/cz-conventional-changelog" 72 | }, 73 | "ghooks": { 74 | "commit-msg": "validate-commit-msg" 75 | }, 76 | "validate-commit-msg": { 77 | "types": [ 78 | "feat", 79 | "fix", 80 | "docs", 81 | "style", 82 | "refactor", 83 | "perf", 84 | "test", 85 | "build", 86 | "ci", 87 | "chore", 88 | "revert" 89 | ], 90 | "scope": { 91 | "required": false, 92 | "allowed": [ 93 | "*" 94 | ], 95 | "validate": false, 96 | "multiple": false 97 | }, 98 | "warnOnFail": false, 99 | "maxSubjectLength": 100, 100 | "subjectPattern": ".+", 101 | "subjectPatternErrorMsg": "subject does not match subject pattern!", 102 | "helpMessage": "", 103 | "autoFix": false 104 | } 105 | }, 106 | "dependencies": { 107 | "@dcloudio/types": "^2.0.16" 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/dev-test/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "dev-test", 3 | "appid" : "__UNI__7E67B0A", 4 | "description" : "", 5 | "versionName" : "1.0.0", 6 | "versionCode" : "100", 7 | "transformPx" : false, 8 | /* 5+App特有相关 */ 9 | "app-plus" : { 10 | "usingComponents" : true, 11 | "nvueCompiler" : "uni-app", 12 | "compilerVersion" : 3, 13 | "splashscreen" : { 14 | "alwaysShowBeforeRender" : true, 15 | "waiting" : true, 16 | "autoclose" : true, 17 | "delay" : 0 18 | }, 19 | /* 模块配置 */ 20 | "modules" : {}, 21 | /* 应用发布信息 */ 22 | "distribute" : { 23 | /* android打包配置 */ 24 | "android" : { 25 | "permissions" : [ 26 | "", 27 | "", 28 | "", 29 | "", 30 | "", 31 | "", 32 | "", 33 | "", 34 | "", 35 | "", 36 | "", 37 | "", 38 | "", 39 | "", 40 | "", 41 | "", 42 | "", 43 | "", 44 | "", 45 | "", 46 | "", 47 | "" 48 | ] 49 | }, 50 | /* ios打包配置 */ 51 | "ios" : {}, 52 | /* SDK配置 */ 53 | "sdkConfigs" : {} 54 | } 55 | }, 56 | /* 快应用特有相关 */ 57 | "quickapp" : {}, 58 | /* 小程序特有相关 */ 59 | "mp-weixin" : { 60 | "appid" : "", 61 | "setting" : { 62 | "urlCheck" : false 63 | }, 64 | "usingComponents" : true 65 | }, 66 | "mp-alipay" : { 67 | "usingComponents" : true 68 | }, 69 | "mp-baidu" : { 70 | "usingComponents" : true 71 | }, 72 | "mp-toutiao" : { 73 | "usingComponents" : true 74 | }, 75 | "uniStatistics": { 76 | "enable": false 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /example/request-demo/api/service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @version 3.0.5 3 | * @Author lu-ch 4 | * @Email webwork.s@qq.com 5 | * 文档: https://www.quanzhan.co/luch-request/ 6 | * github: https://github.com/lei-mu/luch-request 7 | * DCloud: http://ext.dcloud.net.cn/plugin?id=392 8 | * HBuilderX: beat-3.0.4 alpha-3.0.4 9 | */ 10 | 11 | import Request from '@/utils/luch-request/index.js' 12 | 13 | 14 | const getTokenStorage = () => { 15 | let token = '' 16 | try { 17 | token = uni.getStorageSync('token') 18 | } catch (e) { 19 | } 20 | return token 21 | } 22 | 23 | const test = new Request() 24 | /** 25 | * 修改全局配置示例 26 | const test = new Request({ 27 | header: {a:1}, // 举例 28 | baseURL: 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest', 29 | validateStatus: (statusCode) => { // statusCode 必存在。此处示例为全局默认配置 30 | return statusCode >= 200 && statusCode < 300 31 | } 32 | }) 33 | test.config.baseURL = 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest' 34 | **/ 35 | console.log(`test 请求实例的插件版本为:${test.version}`) 36 | test.setConfig((config) => { /* 设置全局配置 */ 37 | config.baseURL = 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest' 38 | config.header = { 39 | ...config.header, 40 | a: 1, // 演示 41 | b: 2 // 演示 42 | } 43 | config.custom = { 44 | // auth: false, // 是否传token 45 | // loading: false // 是否使用loading 46 | } 47 | return config 48 | }) 49 | 50 | test.interceptors.request.use((config) => { /* 请求之前拦截器。可以使用async await 做异步操作 */ 51 | config.header = { 52 | ...config.header, 53 | a: 3 // 演示 54 | } 55 | /** 56 | * custom {Object} - 自定义参数 57 | */ 58 | // if (config.custom.auth) { 59 | // config.header.token = '123456' 60 | // } 61 | // if (config.custom.loading) { 62 | // uni.showLoading() 63 | // } 64 | /* 65 | if (!token) { // 如果token不存在,return Promise.reject(config) 会取消本次请求 66 | return Promise.reject(config) 67 | } 68 | */ 69 | return config 70 | }, (config) => { 71 | return Promise.reject(config) 72 | }) 73 | 74 | 75 | test.interceptors.response.use((response) => { /* 请求之后拦截器。可以使用async await 做异步操作 */ 76 | // if (response.config.custom.loading) { 77 | // uni.hideLoading() 78 | // } 79 | if (response.data.code !== 200) { // 服务端返回的状态码不等于200,则reject() 80 | return Promise.reject(response) 81 | } 82 | return response 83 | }, (response) => { // 请求错误做点什么。可以使用async await 做异步操作 84 | // if (response.config.custom.loading) { 85 | // uni.hideLoading() 86 | // } 87 | return Promise.reject(response) 88 | }) 89 | 90 | 91 | const http = new Request() 92 | http.setConfig((config) => { /* 设置全局配置 */ 93 | config.baseURL = 'https://www.fastmock.site/mock/26243bdf9062eeae2848fc67603bda2d/luchrequest' /* 根域名不同 */ 94 | config.header = { 95 | ...config.header, 96 | a: 1, // 演示 97 | b: 2 // 演示 98 | } 99 | return config 100 | }) 101 | 102 | 103 | http.interceptors.request.use((config) => { /* 请求之前拦截器。可以使用async await 做异步操作 */ 104 | config.header = { 105 | ...config.header, 106 | token: getTokenStorage() 107 | } 108 | /* 109 | if (!token) { // 如果token不存在,return Promise.reject(config) 会取消本次请求 110 | return Promise.reject(config) 111 | } 112 | */ 113 | return config 114 | }, (config) => { 115 | return Promise.reject(config) 116 | }) 117 | 118 | 119 | http.interceptors.response.use(async (response) => { /* 请求之后拦截器。可以使用async await 做异步操作 */ 120 | // if (response.data.code !== 200) { // 服务端返回的状态码不等于200,则reject() 121 | // return Promise.reject(response) 122 | // } 123 | return response 124 | }, (response) => { // 请求错误做点什么。可以使用async await 做异步操作 125 | console.log(response) 126 | return Promise.reject(response) 127 | }) 128 | 129 | export { 130 | http, 131 | test 132 | } 133 | -------------------------------------------------------------------------------- /src/lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // utils is a library of generic helper functions non-specific to axios 4 | 5 | var toString = Object.prototype.toString 6 | 7 | /** 8 | * Determine if a value is an Array 9 | * 10 | * @param {Object} val The value to test 11 | * @returns {boolean} True if value is an Array, otherwise false 12 | */ 13 | export function isArray (val) { 14 | return toString.call(val) === '[object Array]' 15 | } 16 | 17 | 18 | /** 19 | * Determine if a value is an Object 20 | * 21 | * @param {Object} val The value to test 22 | * @returns {boolean} True if value is an Object, otherwise false 23 | */ 24 | export function isObject (val) { 25 | return val !== null && typeof val === 'object' 26 | } 27 | 28 | /** 29 | * Determine if a value is a Date 30 | * 31 | * @param {Object} val The value to test 32 | * @returns {boolean} True if value is a Date, otherwise false 33 | */ 34 | export function isDate (val) { 35 | return toString.call(val) === '[object Date]' 36 | } 37 | 38 | /** 39 | * Determine if a value is a URLSearchParams object 40 | * 41 | * @param {Object} val The value to test 42 | * @returns {boolean} True if value is a URLSearchParams object, otherwise false 43 | */ 44 | export function isURLSearchParams (val) { 45 | return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams 46 | } 47 | 48 | 49 | /** 50 | * Iterate over an Array or an Object invoking a function for each item. 51 | * 52 | * If `obj` is an Array callback will be called passing 53 | * the value, index, and complete array for each item. 54 | * 55 | * If 'obj' is an Object callback will be called passing 56 | * the value, key, and complete object for each property. 57 | * 58 | * @param {Object|Array} obj The object to iterate 59 | * @param {Function} fn The callback to invoke for each item 60 | */ 61 | export function forEach (obj, fn) { 62 | // Don't bother if no value provided 63 | if (obj === null || typeof obj === 'undefined') { 64 | return 65 | } 66 | 67 | // Force an array if not already something iterable 68 | if (typeof obj !== 'object') { 69 | /*eslint no-param-reassign:0*/ 70 | obj = [obj] 71 | } 72 | 73 | if (isArray(obj)) { 74 | // Iterate over array values 75 | for (var i = 0, l = obj.length; i < l; i++) { 76 | fn.call(null, obj[i], i, obj) 77 | } 78 | } else { 79 | // Iterate over object keys 80 | for (var key in obj) { 81 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 82 | fn.call(null, obj[key], key, obj) 83 | } 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * 是否为boolean 值 90 | * @param val 91 | * @returns {boolean} 92 | */ 93 | export function isBoolean(val) { 94 | return typeof val === 'boolean' 95 | } 96 | 97 | /** 98 | * 是否为真正的对象{} new Object 99 | * @param {any} obj - 检测的对象 100 | * @returns {boolean} 101 | */ 102 | export function isPlainObject(obj) { 103 | return Object.prototype.toString.call(obj) === '[object Object]' 104 | } 105 | 106 | 107 | 108 | /** 109 | * Function equal to merge with the difference being that no reference 110 | * to original objects is kept. 111 | * 112 | * @see merge 113 | * @param {Object} obj1 Object to merge 114 | * @returns {Object} Result of all merge properties 115 | */ 116 | export function deepMerge(/* obj1, obj2, obj3, ... */) { 117 | let result = {} 118 | function assignValue(val, key) { 119 | if (typeof result[key] === 'object' && typeof val === 'object') { 120 | result[key] = deepMerge(result[key], val) 121 | } else if (typeof val === 'object') { 122 | result[key] = deepMerge({}, val) 123 | } else { 124 | result[key] = val 125 | } 126 | } 127 | for (let i = 0, l = arguments.length; i < l; i++) { 128 | forEach(arguments[i], assignValue) 129 | } 130 | return result 131 | } 132 | 133 | export function isUndefined (val) { 134 | return typeof val === 'undefined' 135 | } 136 | -------------------------------------------------------------------------------- /DCloud/luch-request/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // utils is a library of generic helper functions non-specific to axios 4 | 5 | var toString = Object.prototype.toString 6 | 7 | /** 8 | * Determine if a value is an Array 9 | * 10 | * @param {Object} val The value to test 11 | * @returns {boolean} True if value is an Array, otherwise false 12 | */ 13 | export function isArray (val) { 14 | return toString.call(val) === '[object Array]' 15 | } 16 | 17 | 18 | /** 19 | * Determine if a value is an Object 20 | * 21 | * @param {Object} val The value to test 22 | * @returns {boolean} True if value is an Object, otherwise false 23 | */ 24 | export function isObject (val) { 25 | return val !== null && typeof val === 'object' 26 | } 27 | 28 | /** 29 | * Determine if a value is a Date 30 | * 31 | * @param {Object} val The value to test 32 | * @returns {boolean} True if value is a Date, otherwise false 33 | */ 34 | export function isDate (val) { 35 | return toString.call(val) === '[object Date]' 36 | } 37 | 38 | /** 39 | * Determine if a value is a URLSearchParams object 40 | * 41 | * @param {Object} val The value to test 42 | * @returns {boolean} True if value is a URLSearchParams object, otherwise false 43 | */ 44 | export function isURLSearchParams (val) { 45 | return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams 46 | } 47 | 48 | 49 | /** 50 | * Iterate over an Array or an Object invoking a function for each item. 51 | * 52 | * If `obj` is an Array callback will be called passing 53 | * the value, index, and complete array for each item. 54 | * 55 | * If 'obj' is an Object callback will be called passing 56 | * the value, key, and complete object for each property. 57 | * 58 | * @param {Object|Array} obj The object to iterate 59 | * @param {Function} fn The callback to invoke for each item 60 | */ 61 | export function forEach (obj, fn) { 62 | // Don't bother if no value provided 63 | if (obj === null || typeof obj === 'undefined') { 64 | return 65 | } 66 | 67 | // Force an array if not already something iterable 68 | if (typeof obj !== 'object') { 69 | /*eslint no-param-reassign:0*/ 70 | obj = [obj] 71 | } 72 | 73 | if (isArray(obj)) { 74 | // Iterate over array values 75 | for (var i = 0, l = obj.length; i < l; i++) { 76 | fn.call(null, obj[i], i, obj) 77 | } 78 | } else { 79 | // Iterate over object keys 80 | for (var key in obj) { 81 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 82 | fn.call(null, obj[key], key, obj) 83 | } 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * 是否为boolean 值 90 | * @param val 91 | * @returns {boolean} 92 | */ 93 | export function isBoolean(val) { 94 | return typeof val === 'boolean' 95 | } 96 | 97 | /** 98 | * 是否为真正的对象{} new Object 99 | * @param {any} obj - 检测的对象 100 | * @returns {boolean} 101 | */ 102 | export function isPlainObject(obj) { 103 | return Object.prototype.toString.call(obj) === '[object Object]' 104 | } 105 | 106 | 107 | 108 | /** 109 | * Function equal to merge with the difference being that no reference 110 | * to original objects is kept. 111 | * 112 | * @see merge 113 | * @param {Object} obj1 Object to merge 114 | * @returns {Object} Result of all merge properties 115 | */ 116 | export function deepMerge(/* obj1, obj2, obj3, ... */) { 117 | let result = {} 118 | function assignValue(val, key) { 119 | if (typeof result[key] === 'object' && typeof val === 'object') { 120 | result[key] = deepMerge(result[key], val) 121 | } else if (typeof val === 'object') { 122 | result[key] = deepMerge({}, val) 123 | } else { 124 | result[key] = val 125 | } 126 | } 127 | for (let i = 0, l = arguments.length; i < l; i++) { 128 | forEach(arguments[i], assignValue) 129 | } 130 | return result 131 | } 132 | 133 | export function isUndefined (val) { 134 | return typeof val === 'undefined' 135 | } 136 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // utils is a library of generic helper functions non-specific to axios 4 | 5 | var toString = Object.prototype.toString 6 | 7 | /** 8 | * Determine if a value is an Array 9 | * 10 | * @param {Object} val The value to test 11 | * @returns {boolean} True if value is an Array, otherwise false 12 | */ 13 | export function isArray (val) { 14 | return toString.call(val) === '[object Array]' 15 | } 16 | 17 | 18 | /** 19 | * Determine if a value is an Object 20 | * 21 | * @param {Object} val The value to test 22 | * @returns {boolean} True if value is an Object, otherwise false 23 | */ 24 | export function isObject (val) { 25 | return val !== null && typeof val === 'object' 26 | } 27 | 28 | /** 29 | * Determine if a value is a Date 30 | * 31 | * @param {Object} val The value to test 32 | * @returns {boolean} True if value is a Date, otherwise false 33 | */ 34 | export function isDate (val) { 35 | return toString.call(val) === '[object Date]' 36 | } 37 | 38 | /** 39 | * Determine if a value is a URLSearchParams object 40 | * 41 | * @param {Object} val The value to test 42 | * @returns {boolean} True if value is a URLSearchParams object, otherwise false 43 | */ 44 | export function isURLSearchParams (val) { 45 | return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams 46 | } 47 | 48 | 49 | /** 50 | * Iterate over an Array or an Object invoking a function for each item. 51 | * 52 | * If `obj` is an Array callback will be called passing 53 | * the value, index, and complete array for each item. 54 | * 55 | * If 'obj' is an Object callback will be called passing 56 | * the value, key, and complete object for each property. 57 | * 58 | * @param {Object|Array} obj The object to iterate 59 | * @param {Function} fn The callback to invoke for each item 60 | */ 61 | export function forEach (obj, fn) { 62 | // Don't bother if no value provided 63 | if (obj === null || typeof obj === 'undefined') { 64 | return 65 | } 66 | 67 | // Force an array if not already something iterable 68 | if (typeof obj !== 'object') { 69 | /*eslint no-param-reassign:0*/ 70 | obj = [obj] 71 | } 72 | 73 | if (isArray(obj)) { 74 | // Iterate over array values 75 | for (var i = 0, l = obj.length; i < l; i++) { 76 | fn.call(null, obj[i], i, obj) 77 | } 78 | } else { 79 | // Iterate over object keys 80 | for (var key in obj) { 81 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 82 | fn.call(null, obj[key], key, obj) 83 | } 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * 是否为boolean 值 90 | * @param val 91 | * @returns {boolean} 92 | */ 93 | export function isBoolean(val) { 94 | return typeof val === 'boolean' 95 | } 96 | 97 | /** 98 | * 是否为真正的对象{} new Object 99 | * @param {any} obj - 检测的对象 100 | * @returns {boolean} 101 | */ 102 | export function isPlainObject(obj) { 103 | return Object.prototype.toString.call(obj) === '[object Object]' 104 | } 105 | 106 | 107 | 108 | /** 109 | * Function equal to merge with the difference being that no reference 110 | * to original objects is kept. 111 | * 112 | * @see merge 113 | * @param {Object} obj1 Object to merge 114 | * @returns {Object} Result of all merge properties 115 | */ 116 | export function deepMerge(/* obj1, obj2, obj3, ... */) { 117 | let result = {} 118 | function assignValue(val, key) { 119 | if (typeof result[key] === 'object' && typeof val === 'object') { 120 | result[key] = deepMerge(result[key], val) 121 | } else if (typeof val === 'object') { 122 | result[key] = deepMerge({}, val) 123 | } else { 124 | result[key] = val 125 | } 126 | } 127 | for (let i = 0, l = arguments.length; i < l; i++) { 128 | forEach(arguments[i], assignValue) 129 | } 130 | return result 131 | } 132 | 133 | export function isUndefined (val) { 134 | return typeof val === 'undefined' 135 | } 136 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // utils is a library of generic helper functions non-specific to axios 4 | 5 | var toString = Object.prototype.toString 6 | 7 | /** 8 | * Determine if a value is an Array 9 | * 10 | * @param {Object} val The value to test 11 | * @returns {boolean} True if value is an Array, otherwise false 12 | */ 13 | export function isArray (val) { 14 | return toString.call(val) === '[object Array]' 15 | } 16 | 17 | 18 | /** 19 | * Determine if a value is an Object 20 | * 21 | * @param {Object} val The value to test 22 | * @returns {boolean} True if value is an Object, otherwise false 23 | */ 24 | export function isObject (val) { 25 | return val !== null && typeof val === 'object' 26 | } 27 | 28 | /** 29 | * Determine if a value is a Date 30 | * 31 | * @param {Object} val The value to test 32 | * @returns {boolean} True if value is a Date, otherwise false 33 | */ 34 | export function isDate (val) { 35 | return toString.call(val) === '[object Date]' 36 | } 37 | 38 | /** 39 | * Determine if a value is a URLSearchParams object 40 | * 41 | * @param {Object} val The value to test 42 | * @returns {boolean} True if value is a URLSearchParams object, otherwise false 43 | */ 44 | export function isURLSearchParams (val) { 45 | return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams 46 | } 47 | 48 | 49 | /** 50 | * Iterate over an Array or an Object invoking a function for each item. 51 | * 52 | * If `obj` is an Array callback will be called passing 53 | * the value, index, and complete array for each item. 54 | * 55 | * If 'obj' is an Object callback will be called passing 56 | * the value, key, and complete object for each property. 57 | * 58 | * @param {Object|Array} obj The object to iterate 59 | * @param {Function} fn The callback to invoke for each item 60 | */ 61 | export function forEach (obj, fn) { 62 | // Don't bother if no value provided 63 | if (obj === null || typeof obj === 'undefined') { 64 | return 65 | } 66 | 67 | // Force an array if not already something iterable 68 | if (typeof obj !== 'object') { 69 | /*eslint no-param-reassign:0*/ 70 | obj = [obj] 71 | } 72 | 73 | if (isArray(obj)) { 74 | // Iterate over array values 75 | for (var i = 0, l = obj.length; i < l; i++) { 76 | fn.call(null, obj[i], i, obj) 77 | } 78 | } else { 79 | // Iterate over object keys 80 | for (var key in obj) { 81 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 82 | fn.call(null, obj[key], key, obj) 83 | } 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * 是否为boolean 值 90 | * @param val 91 | * @returns {boolean} 92 | */ 93 | export function isBoolean(val) { 94 | return typeof val === 'boolean' 95 | } 96 | 97 | /** 98 | * 是否为真正的对象{} new Object 99 | * @param {any} obj - 检测的对象 100 | * @returns {boolean} 101 | */ 102 | export function isPlainObject(obj) { 103 | return Object.prototype.toString.call(obj) === '[object Object]' 104 | } 105 | 106 | 107 | 108 | /** 109 | * Function equal to merge with the difference being that no reference 110 | * to original objects is kept. 111 | * 112 | * @see merge 113 | * @param {Object} obj1 Object to merge 114 | * @returns {Object} Result of all merge properties 115 | */ 116 | export function deepMerge(/* obj1, obj2, obj3, ... */) { 117 | let result = {} 118 | function assignValue(val, key) { 119 | if (typeof result[key] === 'object' && typeof val === 'object') { 120 | result[key] = deepMerge(result[key], val) 121 | } else if (typeof val === 'object') { 122 | result[key] = deepMerge({}, val) 123 | } else { 124 | result[key] = val 125 | } 126 | } 127 | for (let i = 0, l = arguments.length; i < l; i++) { 128 | forEach(arguments[i], assignValue) 129 | } 130 | return result 131 | } 132 | 133 | export function isUndefined (val) { 134 | return typeof val === 'undefined' 135 | } 136 | -------------------------------------------------------------------------------- /src/lib/core/mergeConfig.js: -------------------------------------------------------------------------------- 1 | import {deepMerge, isUndefined} from '../utils' 2 | 3 | /** 4 | * 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局 5 | * @param {Array} keys - 配置项 6 | * @param {Object} globalsConfig - 当前的全局配置 7 | * @param {Object} config2 - 局部配置 8 | * @return {{}} 9 | */ 10 | const mergeKeys = (keys, globalsConfig, config2) => { 11 | let config = {} 12 | keys.forEach(prop => { 13 | if (!isUndefined(config2[prop])) { 14 | config[prop] = config2[prop] 15 | } else if (!isUndefined(globalsConfig[prop])) { 16 | config[prop] = globalsConfig[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | /** 22 | * 23 | * @param globalsConfig - 当前实例的全局配置 24 | * @param config2 - 当前的局部配置 25 | * @return - 合并后的配置 26 | */ 27 | export default (globalsConfig, config2 = {}) => { 28 | const method = config2.method || globalsConfig.method || 'GET' 29 | let config = { 30 | baseURL: config2.baseURL || globalsConfig.baseURL || '', 31 | method: method, 32 | url: config2.url || '', 33 | params: config2.params || {}, 34 | custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})}, 35 | header: deepMerge(globalsConfig.header || {}, config2.header || {}) 36 | } 37 | const defaultToConfig2Keys = ['getTask', 'validateStatus', 'paramsSerializer', 'forcedJSONParsing'] 38 | config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)} 39 | 40 | // eslint-disable-next-line no-empty 41 | if (method === 'DOWNLOAD') { 42 | const downloadKeys = [ 43 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 44 | 'timeout', 45 | // #endif 46 | // #ifdef MP 47 | 'filePath', 48 | // #endif 49 | ] 50 | config = {...config, ...mergeKeys(downloadKeys, globalsConfig, config2)} 51 | } else if (method === 'UPLOAD') { 52 | delete config.header['content-type'] 53 | delete config.header['Content-Type'] 54 | const uploadKeys = [ 55 | // #ifdef APP-PLUS || H5 56 | 'files', 57 | // #endif 58 | // #ifdef MP-ALIPAY 59 | 'fileType', 60 | // #endif 61 | // #ifdef H5 62 | 'file', 63 | // #endif 64 | 'filePath', 65 | 'name', 66 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 67 | 'timeout', 68 | // #endif 69 | 'formData', 70 | ] 71 | uploadKeys.forEach(prop => { 72 | if (!isUndefined(config2[prop])) { 73 | config[prop] = config2[prop] 74 | } 75 | }) 76 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 77 | if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) { 78 | config['timeout'] = globalsConfig['timeout'] 79 | } 80 | // #endif 81 | } else { 82 | const defaultsKeys = [ 83 | 'data', 84 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 85 | 'timeout', 86 | // #endif 87 | 'dataType', 88 | // #ifndef MP-ALIPAY 89 | 'responseType', 90 | // #endif 91 | // #ifdef APP-PLUS 92 | 'sslVerify', 93 | // #endif 94 | // #ifdef H5 95 | 'withCredentials', 96 | // #endif 97 | // #ifdef APP-PLUS 98 | 'firstIpv4', 99 | // #endif 100 | // #ifdef MP-WEIXIN 101 | 'enableHttp2', 102 | 'enableQuic', 103 | // #endif 104 | // #ifdef MP-TOUTIAO || MP-WEIXIN 105 | 'enableCache', 106 | // #endif 107 | // #ifdef MP-WEIXIN 108 | 'enableHttpDNS', 109 | 'httpDNSServiceId', 110 | 'enableChunked', 111 | 'forceCellularNetwork', 112 | // #endif 113 | // #ifdef MP-ALIPAY 114 | 'enableCookie', 115 | // #endif 116 | // #ifdef MP-BAIDU 117 | 'cloudCache', 118 | 'defer' 119 | // #endif 120 | 121 | ] 122 | config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)} 123 | } 124 | 125 | return config 126 | } 127 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/mergeConfig.js: -------------------------------------------------------------------------------- 1 | import {deepMerge, isUndefined} from '../utils' 2 | 3 | /** 4 | * 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局 5 | * @param {Array} keys - 配置项 6 | * @param {Object} globalsConfig - 当前的全局配置 7 | * @param {Object} config2 - 局部配置 8 | * @return {{}} 9 | */ 10 | const mergeKeys = (keys, globalsConfig, config2) => { 11 | let config = {} 12 | keys.forEach(prop => { 13 | if (!isUndefined(config2[prop])) { 14 | config[prop] = config2[prop] 15 | } else if (!isUndefined(globalsConfig[prop])) { 16 | config[prop] = globalsConfig[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | /** 22 | * 23 | * @param globalsConfig - 当前实例的全局配置 24 | * @param config2 - 当前的局部配置 25 | * @return - 合并后的配置 26 | */ 27 | export default (globalsConfig, config2 = {}) => { 28 | const method = config2.method || globalsConfig.method || 'GET' 29 | let config = { 30 | baseURL: config2.baseURL || globalsConfig.baseURL || '', 31 | method: method, 32 | url: config2.url || '', 33 | params: config2.params || {}, 34 | custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})}, 35 | header: deepMerge(globalsConfig.header || {}, config2.header || {}) 36 | } 37 | const defaultToConfig2Keys = ['getTask', 'validateStatus', 'paramsSerializer', 'forcedJSONParsing'] 38 | config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)} 39 | 40 | // eslint-disable-next-line no-empty 41 | if (method === 'DOWNLOAD') { 42 | const downloadKeys = [ 43 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 44 | 'timeout', 45 | // #endif 46 | // #ifdef MP 47 | 'filePath', 48 | // #endif 49 | ] 50 | config = {...config, ...mergeKeys(downloadKeys, globalsConfig, config2)} 51 | } else if (method === 'UPLOAD') { 52 | delete config.header['content-type'] 53 | delete config.header['Content-Type'] 54 | const uploadKeys = [ 55 | // #ifdef APP-PLUS || H5 56 | 'files', 57 | // #endif 58 | // #ifdef MP-ALIPAY 59 | 'fileType', 60 | // #endif 61 | // #ifdef H5 62 | 'file', 63 | // #endif 64 | 'filePath', 65 | 'name', 66 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 67 | 'timeout', 68 | // #endif 69 | 'formData', 70 | ] 71 | uploadKeys.forEach(prop => { 72 | if (!isUndefined(config2[prop])) { 73 | config[prop] = config2[prop] 74 | } 75 | }) 76 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 77 | if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) { 78 | config['timeout'] = globalsConfig['timeout'] 79 | } 80 | // #endif 81 | } else { 82 | const defaultsKeys = [ 83 | 'data', 84 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 85 | 'timeout', 86 | // #endif 87 | 'dataType', 88 | // #ifndef MP-ALIPAY 89 | 'responseType', 90 | // #endif 91 | // #ifdef APP-PLUS 92 | 'sslVerify', 93 | // #endif 94 | // #ifdef H5 95 | 'withCredentials', 96 | // #endif 97 | // #ifdef APP-PLUS 98 | 'firstIpv4', 99 | // #endif 100 | // #ifdef MP-WEIXIN 101 | 'enableHttp2', 102 | 'enableQuic', 103 | // #endif 104 | // #ifdef MP-TOUTIAO || MP-WEIXIN 105 | 'enableCache', 106 | // #endif 107 | // #ifdef MP-WEIXIN 108 | 'enableHttpDNS', 109 | 'httpDNSServiceId', 110 | 'enableChunked', 111 | 'forceCellularNetwork', 112 | // #endif 113 | // #ifdef MP-ALIPAY 114 | 'enableCookie', 115 | // #endif 116 | // #ifdef MP-BAIDU 117 | 'cloudCache', 118 | 'defer' 119 | // #endif 120 | 121 | ] 122 | config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)} 123 | } 124 | 125 | return config 126 | } 127 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/mergeConfig.js: -------------------------------------------------------------------------------- 1 | import {deepMerge, isUndefined} from '../utils' 2 | 3 | /** 4 | * 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局 5 | * @param {Array} keys - 配置项 6 | * @param {Object} globalsConfig - 当前的全局配置 7 | * @param {Object} config2 - 局部配置 8 | * @return {{}} 9 | */ 10 | const mergeKeys = (keys, globalsConfig, config2) => { 11 | let config = {} 12 | keys.forEach(prop => { 13 | if (!isUndefined(config2[prop])) { 14 | config[prop] = config2[prop] 15 | } else if (!isUndefined(globalsConfig[prop])) { 16 | config[prop] = globalsConfig[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | /** 22 | * 23 | * @param globalsConfig - 当前实例的全局配置 24 | * @param config2 - 当前的局部配置 25 | * @return - 合并后的配置 26 | */ 27 | export default (globalsConfig, config2 = {}) => { 28 | const method = config2.method || globalsConfig.method || 'GET' 29 | let config = { 30 | baseURL: config2.baseURL || globalsConfig.baseURL || '', 31 | method: method, 32 | url: config2.url || '', 33 | params: config2.params || {}, 34 | custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})}, 35 | header: deepMerge(globalsConfig.header || {}, config2.header || {}) 36 | } 37 | const defaultToConfig2Keys = ['getTask', 'validateStatus', 'paramsSerializer', 'forcedJSONParsing'] 38 | config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)} 39 | 40 | // eslint-disable-next-line no-empty 41 | if (method === 'DOWNLOAD') { 42 | const downloadKeys = [ 43 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 44 | 'timeout', 45 | // #endif 46 | // #ifdef MP 47 | 'filePath', 48 | // #endif 49 | ] 50 | config = {...config, ...mergeKeys(downloadKeys, globalsConfig, config2)} 51 | } else if (method === 'UPLOAD') { 52 | delete config.header['content-type'] 53 | delete config.header['Content-Type'] 54 | const uploadKeys = [ 55 | // #ifdef APP-PLUS || H5 56 | 'files', 57 | // #endif 58 | // #ifdef MP-ALIPAY 59 | 'fileType', 60 | // #endif 61 | // #ifdef H5 62 | 'file', 63 | // #endif 64 | 'filePath', 65 | 'name', 66 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 67 | 'timeout', 68 | // #endif 69 | 'formData', 70 | ] 71 | uploadKeys.forEach(prop => { 72 | if (!isUndefined(config2[prop])) { 73 | config[prop] = config2[prop] 74 | } 75 | }) 76 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 77 | if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) { 78 | config['timeout'] = globalsConfig['timeout'] 79 | } 80 | // #endif 81 | } else { 82 | const defaultsKeys = [ 83 | 'data', 84 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 85 | 'timeout', 86 | // #endif 87 | 'dataType', 88 | // #ifndef MP-ALIPAY 89 | 'responseType', 90 | // #endif 91 | // #ifdef APP-PLUS 92 | 'sslVerify', 93 | // #endif 94 | // #ifdef H5 95 | 'withCredentials', 96 | // #endif 97 | // #ifdef APP-PLUS 98 | 'firstIpv4', 99 | // #endif 100 | // #ifdef MP-WEIXIN 101 | 'enableHttp2', 102 | 'enableQuic', 103 | // #endif 104 | // #ifdef MP-TOUTIAO || MP-WEIXIN 105 | 'enableCache', 106 | // #endif 107 | // #ifdef MP-WEIXIN 108 | 'enableHttpDNS', 109 | 'httpDNSServiceId', 110 | 'enableChunked', 111 | 'forceCellularNetwork', 112 | // #endif 113 | // #ifdef MP-ALIPAY 114 | 'enableCookie', 115 | // #endif 116 | // #ifdef MP-BAIDU 117 | 'cloudCache', 118 | 'defer' 119 | // #endif 120 | 121 | ] 122 | config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)} 123 | } 124 | 125 | return config 126 | } 127 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/mergeConfig.js: -------------------------------------------------------------------------------- 1 | import {deepMerge, isUndefined} from '../utils' 2 | 3 | /** 4 | * 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局 5 | * @param {Array} keys - 配置项 6 | * @param {Object} globalsConfig - 当前的全局配置 7 | * @param {Object} config2 - 局部配置 8 | * @return {{}} 9 | */ 10 | const mergeKeys = (keys, globalsConfig, config2) => { 11 | let config = {} 12 | keys.forEach(prop => { 13 | if (!isUndefined(config2[prop])) { 14 | config[prop] = config2[prop] 15 | } else if (!isUndefined(globalsConfig[prop])) { 16 | config[prop] = globalsConfig[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | /** 22 | * 23 | * @param globalsConfig - 当前实例的全局配置 24 | * @param config2 - 当前的局部配置 25 | * @return - 合并后的配置 26 | */ 27 | export default (globalsConfig, config2 = {}) => { 28 | const method = config2.method || globalsConfig.method || 'GET' 29 | let config = { 30 | baseURL: config2.baseURL || globalsConfig.baseURL || '', 31 | method: method, 32 | url: config2.url || '', 33 | params: config2.params || {}, 34 | custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})}, 35 | header: deepMerge(globalsConfig.header || {}, config2.header || {}) 36 | } 37 | const defaultToConfig2Keys = ['getTask', 'validateStatus', 'paramsSerializer', 'forcedJSONParsing'] 38 | config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)} 39 | 40 | // eslint-disable-next-line no-empty 41 | if (method === 'DOWNLOAD') { 42 | const downloadKeys = [ 43 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 44 | 'timeout', 45 | // #endif 46 | // #ifdef MP 47 | 'filePath', 48 | // #endif 49 | ] 50 | config = {...config, ...mergeKeys(downloadKeys, globalsConfig, config2)} 51 | } else if (method === 'UPLOAD') { 52 | delete config.header['content-type'] 53 | delete config.header['Content-Type'] 54 | const uploadKeys = [ 55 | // #ifdef APP-PLUS || H5 56 | 'files', 57 | // #endif 58 | // #ifdef MP-ALIPAY 59 | 'fileType', 60 | // #endif 61 | // #ifdef H5 62 | 'file', 63 | // #endif 64 | 'filePath', 65 | 'name', 66 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 67 | 'timeout', 68 | // #endif 69 | 'formData', 70 | ] 71 | uploadKeys.forEach(prop => { 72 | if (!isUndefined(config2[prop])) { 73 | config[prop] = config2[prop] 74 | } 75 | }) 76 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 77 | if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) { 78 | config['timeout'] = globalsConfig['timeout'] 79 | } 80 | // #endif 81 | } else { 82 | const defaultsKeys = [ 83 | 'data', 84 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 85 | 'timeout', 86 | // #endif 87 | 'dataType', 88 | // #ifndef MP-ALIPAY 89 | 'responseType', 90 | // #endif 91 | // #ifdef APP-PLUS 92 | 'sslVerify', 93 | // #endif 94 | // #ifdef H5 95 | 'withCredentials', 96 | // #endif 97 | // #ifdef APP-PLUS 98 | 'firstIpv4', 99 | // #endif 100 | // #ifdef MP-WEIXIN 101 | 'enableHttp2', 102 | 'enableQuic', 103 | // #endif 104 | // #ifdef MP-TOUTIAO || MP-WEIXIN 105 | 'enableCache', 106 | // #endif 107 | // #ifdef MP-WEIXIN 108 | 'enableHttpDNS', 109 | 'httpDNSServiceId', 110 | 'enableChunked', 111 | 'forceCellularNetwork', 112 | // #endif 113 | // #ifdef MP-ALIPAY 114 | 'enableCookie', 115 | // #endif 116 | // #ifdef MP-BAIDU 117 | 'cloudCache', 118 | 'defer' 119 | // #endif 120 | 121 | ] 122 | config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)} 123 | } 124 | 125 | return config 126 | } 127 | -------------------------------------------------------------------------------- /test/dev-test/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 127 | 128 | 154 | -------------------------------------------------------------------------------- /example/request-demo/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 131 | 132 | 158 | -------------------------------------------------------------------------------- /src/lib/adapters/index.js: -------------------------------------------------------------------------------- 1 | import buildURL from '../helpers/buildURL' 2 | import buildFullPath from '../core/buildFullPath' 3 | import settle from '../core/settle' 4 | import {isUndefined} from "../utils" 5 | 6 | /** 7 | * 返回可选值存在的配置 8 | * @param {Array} keys - 可选值数组 9 | * @param {Object} config2 - 配置 10 | * @return {{}} - 存在的配置项 11 | */ 12 | const mergeKeys = (keys, config2) => { 13 | let config = {} 14 | keys.forEach(prop => { 15 | if (!isUndefined(config2[prop])) { 16 | config[prop] = config2[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | export default (config) => { 22 | return new Promise((resolve, reject) => { 23 | let fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer) 24 | const _config = { 25 | url: fullPath, 26 | header: config.header, 27 | complete: (response) => { 28 | config.fullPath = fullPath 29 | response.config = config 30 | response.rawData = response.data 31 | try { 32 | let jsonParseHandle = false 33 | const forcedJSONParsingType = typeof config.forcedJSONParsing 34 | if (forcedJSONParsingType === 'boolean') { 35 | jsonParseHandle = config.forcedJSONParsing 36 | } else if (forcedJSONParsingType === 'object') { 37 | const includesMethod = config.forcedJSONParsing.include || [] 38 | jsonParseHandle = includesMethod.includes(config.method) 39 | } 40 | 41 | // 对可能字符串不是json 的情况容错 42 | if (jsonParseHandle && typeof response.data === 'string') { 43 | response.data = JSON.parse(response.data) 44 | } 45 | // eslint-disable-next-line no-empty 46 | } catch (e) { 47 | } 48 | settle(resolve, reject, response) 49 | } 50 | } 51 | let requestTask 52 | if (config.method === 'UPLOAD') { 53 | delete _config.header['content-type'] 54 | delete _config.header['Content-Type'] 55 | let otherConfig = { 56 | // #ifdef MP-ALIPAY 57 | fileType: config.fileType, 58 | // #endif 59 | filePath: config.filePath, 60 | name: config.name 61 | } 62 | const optionalKeys = [ 63 | // #ifdef APP-PLUS || H5 64 | 'files', 65 | // #endif 66 | // #ifdef H5 67 | 'file', 68 | // #endif 69 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 70 | 'timeout', 71 | // #endif 72 | 'formData' 73 | ] 74 | requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)}) 75 | } else if (config.method === 'DOWNLOAD') { 76 | const optionalKeys = [ 77 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 78 | 'timeout', 79 | // #endif 80 | // #ifdef MP 81 | 'filePath', 82 | // #endif 83 | ] 84 | requestTask = uni.downloadFile({..._config, ...mergeKeys(optionalKeys, config)}) 85 | } else { 86 | const optionalKeys = [ 87 | 'data', 88 | 'method', 89 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 90 | 'timeout', 91 | // #endif 92 | 'dataType', 93 | // #ifndef MP-ALIPAY 94 | 'responseType', 95 | // #endif 96 | // #ifdef APP-PLUS 97 | 'sslVerify', 98 | // #endif 99 | // #ifdef H5 100 | 'withCredentials', 101 | // #endif 102 | // #ifdef APP-PLUS 103 | 'firstIpv4', 104 | // #endif 105 | // #ifdef MP-WEIXIN 106 | 'enableHttp2', 107 | 'enableQuic', 108 | // #endif 109 | // #ifdef MP-TOUTIAO || MP-WEIXIN 110 | 'enableCache', 111 | // #endif 112 | // #ifdef MP-WEIXIN 113 | 'enableHttpDNS', 114 | 'httpDNSServiceId', 115 | 'enableChunked', 116 | 'forceCellularNetwork', 117 | // #endif 118 | // #ifdef MP-ALIPAY 119 | 'enableCookie', 120 | // #endif 121 | // #ifdef MP-BAIDU 122 | 'cloudCache', 123 | 'defer' 124 | // #endif 125 | ] 126 | requestTask = uni.request({..._config, ...mergeKeys(optionalKeys, config)}) 127 | } 128 | if (config.getTask) { 129 | config.getTask(requestTask, config) 130 | } 131 | }) 132 | } 133 | -------------------------------------------------------------------------------- /DCloud/luch-request/adapters/index.js: -------------------------------------------------------------------------------- 1 | import buildURL from '../helpers/buildURL' 2 | import buildFullPath from '../core/buildFullPath' 3 | import settle from '../core/settle' 4 | import {isUndefined} from "../utils" 5 | 6 | /** 7 | * 返回可选值存在的配置 8 | * @param {Array} keys - 可选值数组 9 | * @param {Object} config2 - 配置 10 | * @return {{}} - 存在的配置项 11 | */ 12 | const mergeKeys = (keys, config2) => { 13 | let config = {} 14 | keys.forEach(prop => { 15 | if (!isUndefined(config2[prop])) { 16 | config[prop] = config2[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | export default (config) => { 22 | return new Promise((resolve, reject) => { 23 | let fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer) 24 | const _config = { 25 | url: fullPath, 26 | header: config.header, 27 | complete: (response) => { 28 | config.fullPath = fullPath 29 | response.config = config 30 | response.rawData = response.data 31 | try { 32 | let jsonParseHandle = false 33 | const forcedJSONParsingType = typeof config.forcedJSONParsing 34 | if (forcedJSONParsingType === 'boolean') { 35 | jsonParseHandle = config.forcedJSONParsing 36 | } else if (forcedJSONParsingType === 'object') { 37 | const includesMethod = config.forcedJSONParsing.include || [] 38 | jsonParseHandle = includesMethod.includes(config.method) 39 | } 40 | 41 | // 对可能字符串不是json 的情况容错 42 | if (jsonParseHandle && typeof response.data === 'string') { 43 | response.data = JSON.parse(response.data) 44 | } 45 | // eslint-disable-next-line no-empty 46 | } catch (e) { 47 | } 48 | settle(resolve, reject, response) 49 | } 50 | } 51 | let requestTask 52 | if (config.method === 'UPLOAD') { 53 | delete _config.header['content-type'] 54 | delete _config.header['Content-Type'] 55 | let otherConfig = { 56 | // #ifdef MP-ALIPAY 57 | fileType: config.fileType, 58 | // #endif 59 | filePath: config.filePath, 60 | name: config.name 61 | } 62 | const optionalKeys = [ 63 | // #ifdef APP-PLUS || H5 64 | 'files', 65 | // #endif 66 | // #ifdef H5 67 | 'file', 68 | // #endif 69 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 70 | 'timeout', 71 | // #endif 72 | 'formData' 73 | ] 74 | requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)}) 75 | } else if (config.method === 'DOWNLOAD') { 76 | const optionalKeys = [ 77 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 78 | 'timeout', 79 | // #endif 80 | // #ifdef MP 81 | 'filePath', 82 | // #endif 83 | ] 84 | requestTask = uni.downloadFile({..._config, ...mergeKeys(optionalKeys, config)}) 85 | } else { 86 | const optionalKeys = [ 87 | 'data', 88 | 'method', 89 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 90 | 'timeout', 91 | // #endif 92 | 'dataType', 93 | // #ifndef MP-ALIPAY 94 | 'responseType', 95 | // #endif 96 | // #ifdef APP-PLUS 97 | 'sslVerify', 98 | // #endif 99 | // #ifdef H5 100 | 'withCredentials', 101 | // #endif 102 | // #ifdef APP-PLUS 103 | 'firstIpv4', 104 | // #endif 105 | // #ifdef MP-WEIXIN 106 | 'enableHttp2', 107 | 'enableQuic', 108 | // #endif 109 | // #ifdef MP-TOUTIAO || MP-WEIXIN 110 | 'enableCache', 111 | // #endif 112 | // #ifdef MP-WEIXIN 113 | 'enableHttpDNS', 114 | 'httpDNSServiceId', 115 | 'enableChunked', 116 | 'forceCellularNetwork', 117 | // #endif 118 | // #ifdef MP-ALIPAY 119 | 'enableCookie', 120 | // #endif 121 | // #ifdef MP-BAIDU 122 | 'cloudCache', 123 | 'defer' 124 | // #endif 125 | ] 126 | requestTask = uni.request({..._config, ...mergeKeys(optionalKeys, config)}) 127 | } 128 | if (config.getTask) { 129 | config.getTask(requestTask, config) 130 | } 131 | }) 132 | } 133 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/adapters/index.js: -------------------------------------------------------------------------------- 1 | import buildURL from '../helpers/buildURL' 2 | import buildFullPath from '../core/buildFullPath' 3 | import settle from '../core/settle' 4 | import {isUndefined} from "../utils" 5 | 6 | /** 7 | * 返回可选值存在的配置 8 | * @param {Array} keys - 可选值数组 9 | * @param {Object} config2 - 配置 10 | * @return {{}} - 存在的配置项 11 | */ 12 | const mergeKeys = (keys, config2) => { 13 | let config = {} 14 | keys.forEach(prop => { 15 | if (!isUndefined(config2[prop])) { 16 | config[prop] = config2[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | export default (config) => { 22 | return new Promise((resolve, reject) => { 23 | let fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer) 24 | const _config = { 25 | url: fullPath, 26 | header: config.header, 27 | complete: (response) => { 28 | config.fullPath = fullPath 29 | response.config = config 30 | response.rawData = response.data 31 | try { 32 | let jsonParseHandle = false 33 | const forcedJSONParsingType = typeof config.forcedJSONParsing 34 | if (forcedJSONParsingType === 'boolean') { 35 | jsonParseHandle = config.forcedJSONParsing 36 | } else if (forcedJSONParsingType === 'object') { 37 | const includesMethod = config.forcedJSONParsing.include || [] 38 | jsonParseHandle = includesMethod.includes(config.method) 39 | } 40 | 41 | // 对可能字符串不是json 的情况容错 42 | if (jsonParseHandle && typeof response.data === 'string') { 43 | response.data = JSON.parse(response.data) 44 | } 45 | // eslint-disable-next-line no-empty 46 | } catch (e) { 47 | } 48 | settle(resolve, reject, response) 49 | } 50 | } 51 | let requestTask 52 | if (config.method === 'UPLOAD') { 53 | delete _config.header['content-type'] 54 | delete _config.header['Content-Type'] 55 | let otherConfig = { 56 | // #ifdef MP-ALIPAY 57 | fileType: config.fileType, 58 | // #endif 59 | filePath: config.filePath, 60 | name: config.name 61 | } 62 | const optionalKeys = [ 63 | // #ifdef APP-PLUS || H5 64 | 'files', 65 | // #endif 66 | // #ifdef H5 67 | 'file', 68 | // #endif 69 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 70 | 'timeout', 71 | // #endif 72 | 'formData' 73 | ] 74 | requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)}) 75 | } else if (config.method === 'DOWNLOAD') { 76 | const optionalKeys = [ 77 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 78 | 'timeout', 79 | // #endif 80 | // #ifdef MP 81 | 'filePath', 82 | // #endif 83 | ] 84 | requestTask = uni.downloadFile({..._config, ...mergeKeys(optionalKeys, config)}) 85 | } else { 86 | const optionalKeys = [ 87 | 'data', 88 | 'method', 89 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 90 | 'timeout', 91 | // #endif 92 | 'dataType', 93 | // #ifndef MP-ALIPAY 94 | 'responseType', 95 | // #endif 96 | // #ifdef APP-PLUS 97 | 'sslVerify', 98 | // #endif 99 | // #ifdef H5 100 | 'withCredentials', 101 | // #endif 102 | // #ifdef APP-PLUS 103 | 'firstIpv4', 104 | // #endif 105 | // #ifdef MP-WEIXIN 106 | 'enableHttp2', 107 | 'enableQuic', 108 | // #endif 109 | // #ifdef MP-TOUTIAO || MP-WEIXIN 110 | 'enableCache', 111 | // #endif 112 | // #ifdef MP-WEIXIN 113 | 'enableHttpDNS', 114 | 'httpDNSServiceId', 115 | 'enableChunked', 116 | 'forceCellularNetwork', 117 | // #endif 118 | // #ifdef MP-ALIPAY 119 | 'enableCookie', 120 | // #endif 121 | // #ifdef MP-BAIDU 122 | 'cloudCache', 123 | 'defer' 124 | // #endif 125 | ] 126 | requestTask = uni.request({..._config, ...mergeKeys(optionalKeys, config)}) 127 | } 128 | if (config.getTask) { 129 | config.getTask(requestTask, config) 130 | } 131 | }) 132 | } 133 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/adapters/index.js: -------------------------------------------------------------------------------- 1 | import buildURL from '../helpers/buildURL' 2 | import buildFullPath from '../core/buildFullPath' 3 | import settle from '../core/settle' 4 | import {isUndefined} from "../utils" 5 | 6 | /** 7 | * 返回可选值存在的配置 8 | * @param {Array} keys - 可选值数组 9 | * @param {Object} config2 - 配置 10 | * @return {{}} - 存在的配置项 11 | */ 12 | const mergeKeys = (keys, config2) => { 13 | let config = {} 14 | keys.forEach(prop => { 15 | if (!isUndefined(config2[prop])) { 16 | config[prop] = config2[prop] 17 | } 18 | }) 19 | return config 20 | } 21 | export default (config) => { 22 | return new Promise((resolve, reject) => { 23 | let fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer) 24 | const _config = { 25 | url: fullPath, 26 | header: config.header, 27 | complete: (response) => { 28 | config.fullPath = fullPath 29 | response.config = config 30 | response.rawData = response.data 31 | try { 32 | let jsonParseHandle = false 33 | const forcedJSONParsingType = typeof config.forcedJSONParsing 34 | if (forcedJSONParsingType === 'boolean') { 35 | jsonParseHandle = config.forcedJSONParsing 36 | } else if (forcedJSONParsingType === 'object') { 37 | const includesMethod = config.forcedJSONParsing.include || [] 38 | jsonParseHandle = includesMethod.includes(config.method) 39 | } 40 | 41 | // 对可能字符串不是json 的情况容错 42 | if (jsonParseHandle && typeof response.data === 'string') { 43 | response.data = JSON.parse(response.data) 44 | } 45 | // eslint-disable-next-line no-empty 46 | } catch (e) { 47 | } 48 | settle(resolve, reject, response) 49 | } 50 | } 51 | let requestTask 52 | if (config.method === 'UPLOAD') { 53 | delete _config.header['content-type'] 54 | delete _config.header['Content-Type'] 55 | let otherConfig = { 56 | // #ifdef MP-ALIPAY 57 | fileType: config.fileType, 58 | // #endif 59 | filePath: config.filePath, 60 | name: config.name 61 | } 62 | const optionalKeys = [ 63 | // #ifdef APP-PLUS || H5 64 | 'files', 65 | // #endif 66 | // #ifdef H5 67 | 'file', 68 | // #endif 69 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 70 | 'timeout', 71 | // #endif 72 | 'formData' 73 | ] 74 | requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)}) 75 | } else if (config.method === 'DOWNLOAD') { 76 | const optionalKeys = [ 77 | // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU 78 | 'timeout', 79 | // #endif 80 | // #ifdef MP 81 | 'filePath', 82 | // #endif 83 | ] 84 | requestTask = uni.downloadFile({..._config, ...mergeKeys(optionalKeys, config)}) 85 | } else { 86 | const optionalKeys = [ 87 | 'data', 88 | 'method', 89 | // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN 90 | 'timeout', 91 | // #endif 92 | 'dataType', 93 | // #ifndef MP-ALIPAY 94 | 'responseType', 95 | // #endif 96 | // #ifdef APP-PLUS 97 | 'sslVerify', 98 | // #endif 99 | // #ifdef H5 100 | 'withCredentials', 101 | // #endif 102 | // #ifdef APP-PLUS 103 | 'firstIpv4', 104 | // #endif 105 | // #ifdef MP-WEIXIN 106 | 'enableHttp2', 107 | 'enableQuic', 108 | // #endif 109 | // #ifdef MP-TOUTIAO || MP-WEIXIN 110 | 'enableCache', 111 | // #endif 112 | // #ifdef MP-WEIXIN 113 | 'enableHttpDNS', 114 | 'httpDNSServiceId', 115 | 'enableChunked', 116 | 'forceCellularNetwork', 117 | // #endif 118 | // #ifdef MP-ALIPAY 119 | 'enableCookie', 120 | // #endif 121 | // #ifdef MP-BAIDU 122 | 'cloudCache', 123 | 'defer' 124 | // #endif 125 | ] 126 | requestTask = uni.request({..._config, ...mergeKeys(optionalKeys, config)}) 127 | } 128 | if (config.getTask) { 129 | config.getTask(requestTask, config) 130 | } 131 | }) 132 | } 133 | -------------------------------------------------------------------------------- /docs/handbook/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | title: 指南 4 | meta: 5 | - name: description 6 | content: luch-request 是一个基于Promise 开发的uni-app跨平台、项目级别的请求库,它有更小的体积,易用的api,方便简单的自定义能力。luch-request 基于Promise,使用条件编译开发,专用于uni-app项目(事实上,我们可以剔除对应的终端以外的代码,直接在对应终端原生语言使用)。为了降低学习成本,一些api参照axios 设计。并扩展一些其它的api。 7 | --- 8 | 9 | 10 | # 指南 11 | 12 | 介绍 13 | ------------ 14 | 15 | luch-request 是一个基于Promise 开发的uni-app跨平台、项目级别的请求库,它有更小的体积,易用的api,方便简单的自定义能力。 16 | 17 | - 支持全局挂载 18 | - 支持多个全局配置实例 19 | - 支持自定义验证器 20 | - 支持文件上传/下载 21 | - 支持task 操作 22 | - 支持自定义参数 23 | - 支持多拦截器 24 | - 对参数的处理比uni.request 更强 25 | 26 | ### 它是如何工作的 27 | luch-request 基于Promise,使用条件编译开发,专用于uni-app项目(事实上,我们可以剔除对应的终端以外的代码,直接在对应终端原生语言使用)。为了降低学习成本,一些api参照axios 设计。并扩展一些其它的api。 28 |
29 | 对于某些终端不支持的option,插件已通过内部实现,过滤不支持的参数。 30 |
31 | 在项目中,我们可以通过`局部引入`和`全局引入`的方式去使用它(参考:[示例项目](https://github.com/lei-mu/luch-request/tree/master/example/request-demo))。 32 | 33 | ### 为什么不是...? 34 | 35 | #### axios 36 | axios 是一个优秀的可用于前端项目和node 的请求库。但是在uni-app 项目中却不能使用它。因为它使用了`xhr` 对象的请求库,但是在除h5终端以外的终端都没有开放xhr对象,所以它无法跨端开发。并且大量的配置在uni-app中不支持,或者没有。无用的代码意味着无用的消耗。它的迭代并不会考虑uni-app。 37 | 38 | #### axios重写`adapter` 39 | 还是那句话,对于uni-app来说它太大太重。大量无用的代码,并不适用于项目。luch-request完全满足项目开发。 40 | 41 | #### 其他的uni request 插件 42 | **非条件编译开发:** 插件市场的部分request没有使用条件编译开发,这对我们项目debug会造成误导影响。并且多余的代码也增大了项目体积。 43 |
44 | **多余的配置项:** 有些插件会把loading、auth等参数加入配置,使其做一些请求之外的操作,这些配置并不是所有人都会使用。**request请求库只需专注于请求即可**。luch-request对额外操作的处理则更为优雅,增加了`custom` 配置,使开发者可以做一些自定义操作。 45 |
46 | **开发构建:** luch-request请求库开发配置了eslint、rollup等等项目级构建打包工具,很大程度上使代码更加标准。 47 |
48 | 其他显而易见的优势就不用说了 49 | 50 | #### uni.request 51 | ... 52 |
53 | 无法满足项目级开发要求,无拦截器,无自定义api. 54 |
55 | 你的使用方式 56 | ```` javascript 57 | uni.request({ 58 | url: this.$baseUrl + 'api/user' 59 | method: 'POST', 60 | data: {a:1}, 61 | header: {Content-Type: '...', token: '....'} 62 | success: (res) => {}, 63 | fail: (err) => {} 64 | }) 65 | ```` 66 | 使用luch-request后 67 | ```` javascript 68 | this.$http.post('/api/user', {a:1}).then(res => { 69 | ... 70 | }).catch(err => { 71 | ... 72 | }) 73 | ```` 74 |
75 | luch-request 对特殊参数的处理方式比uni.request 更强。具体可见get,传递数组。 76 | 77 | #### function 78 | 这是我见得大多数人的使用方法。自己写一个function封装。修改配置都是直接改代码。在一些项目中可能出现多个api的情况,无法多实例。 79 |
80 | ... 81 | 82 | 快速上手 83 | ------------ 84 | 85 | ### npm 86 | 87 | ```` javascript 88 | npm i luch-request -S 89 | ```` 90 | cli 用户使用npm 包需增加以下配置(什么是cli用户) 91 |
92 | 项目根路径下创建`vue.config.js` 文件,增加以下内容 93 | ``` javascript 94 | // vue.config.js 95 | module.exports = { 96 | transpileDependencies: ['luch-request'] 97 | } 98 | ``` 99 | 100 | ::: warning 101 | cli用户使用npm包,为什么要加以上配置[详见](/issue/#_1-%E4%B8%BA%E4%BB%80%E4%B9%88cli%E7%94%A8%E6%88%B7%E4%B8%8D%E8%83%BD%E4%BD%BF%E7%94%A8-npm-%E6%96%B9%E5%BC%8F%E5%BC%95%E5%85%A5) 102 | ::: 103 | 104 | ### github 105 | 106 | GitHub 107 |
108 | 使用DCloud/luch-request 文件夹即可 109 | 110 | 111 | ### DCloud插件市场 112 | 113 | DCloud插件市场 114 | 115 | 116 | tip 117 | ------------ 118 | - nvue 不支持全局挂载 119 | - 当前的hbuilderx 版本号:beat-3.0.4 alpha-3.0.4 120 | - 推荐使用下载插件的方式使用。 121 | - license: MIT 122 | 123 | 124 | issue 125 | ------------ 126 | - DCloud: 有任何问题或者建议可以=> issue提交,先给个五星好评QAQ!! 127 | - github: Issues 128 | 129 | 130 | 作者想说 131 | ------------ 132 | - 写代码很容易,为了让你们看懂写文档真的很lei 0.0 133 | - 最近发现有插件与我雷同,当初接触uni-app 就发现插件市场虽然有封装的不错的request库,但是都没有对多全局配置做处理,都是通过修改源码的方式配置。我首先推出通过class类,并仿照axios的api实现request请求库,并起名‘仿axios封装request网络请求库,支持拦截器全局配置’。他们虽然修改了部分代码,但是功能与性能并没有优化,反而使代码很冗余。希望能推出新的功能,和性能更加强悍的请求库。(2019-05) 134 | - 任何形式的‘参考’、‘借鉴’,请标明作者` luch-request ` 135 | ```javascript 136 | luch-request 137 | ``` 138 | 139 | 140 | 我有疑惑 141 | ------------ 142 | ### 关于问问题 143 | 1. 首先请善于利用搜索引擎,不管百度,还是Google,遇到问题请先自己尝试解决。自己尝试过无法解决,再问。 144 | 2. 不要问类似为什么我的xx无法使用这种问题。请仔细阅读文档,检查代码,或者说明运行环境,把相关代码贴至评论或者发送至我的邮箱,还可以点击DCloud 社区,在里面提问,可能我在里面已经回答了。 145 | 3. 我的代码如果真的出现bug,或者你有好的建议、需求,可以提issue,我看到后会立即解决 146 | 147 | 148 | ### 如何问问题 149 | 1. 问问题之前请换位思考,如果自己要解决这个问题,需要哪些信息 150 | 2. 仔细阅读文档,检查代码 151 | 3. 说明运行环境,比如:app端 ios、android 版本号、手机机型、普遍现象还是个别现象(越详细越好) 152 | 4. 发出代码片段或者截图至邮箱(很重要)`webwork.s@qq.com` 153 | 5. 或者可以在DCloud 社区里发出详细的问题描述 154 | 6. 以上都觉得解决不了你的问题或问题过于复杂难以描述,可以加QQ:`370306150` 155 | 156 | 157 | 其他 158 | ------------ 159 | ### 参与插件贡献 160 | **代码pr**:理论上不允许任何人往`master`分支合并代码,如果你有重大改动,请联系我的邮箱(`webwork.s@qq.com`)或者qq(`370306150`),我会专门为你建立一条分支。 161 | 162 | **其他**:[鸣谢](/acknowledgement/)对插件做出贡献者 163 | ### ts 支持 164 | index.d.ts。目前,该文件由@TuiMao233提供。希望更多的人可以参与进来,pr请提到`request-ts`分支。request-ts 165 | 166 | # 深入 167 | 168 | 169 | 开发理念 170 | ------------ 171 | ... 172 | -------------------------------------------------------------------------------- /src/lib/core/Request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Class Request 3 | * @description luch-request http请求插件 4 | * @Author lu-ch 5 | * @Email webwork.s@qq.com 6 | * 文档: https://www.quanzhan.co/luch-request/ 7 | * github: https://github.com/lei-mu/luch-request 8 | * DCloud: http://ext.dcloud.net.cn/plugin?id=392 9 | */ 10 | 11 | 12 | import dispatchRequest from './dispatchRequest' 13 | import InterceptorManager from './InterceptorManager' 14 | import mergeConfig from './mergeConfig' 15 | import defaults from './defaults' 16 | import { isPlainObject } from '../utils' 17 | import clone from '../utils/clone' 18 | 19 | export default class Request { 20 | /** 21 | * @param {Object} arg - 全局配置 22 | * @param {String} arg.baseURL - 全局根路径 23 | * @param {Object} arg.header - 全局header 24 | * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式 25 | * @param {String} arg.dataType = [json] - 全局默认的dataType 26 | * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持 27 | * @param {Object} arg.custom - 全局默认的自定义参数 28 | * @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序 29 | * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+) 30 | * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+) 31 | * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+) 32 | * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300 33 | */ 34 | constructor(arg = {}) { 35 | if (!isPlainObject(arg)) { 36 | arg = {} 37 | console.warn('设置全局参数必须接收一个Object') 38 | } 39 | this.config = clone({...defaults, ...arg}) 40 | this.interceptors = { 41 | request: new InterceptorManager(), 42 | response: new InterceptorManager() 43 | } 44 | } 45 | 46 | /** 47 | * @Function 48 | * @param {Request~setConfigCallback} f - 设置全局默认配置 49 | */ 50 | setConfig(f) { 51 | this.config = f(this.config) 52 | } 53 | 54 | middleware(config) { 55 | config = mergeConfig(this.config, config) 56 | let chain = [dispatchRequest, undefined] 57 | let promise = Promise.resolve(config) 58 | 59 | this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { 60 | chain.unshift(interceptor.fulfilled, interceptor.rejected) 61 | }) 62 | 63 | this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { 64 | chain.push(interceptor.fulfilled, interceptor.rejected) 65 | }) 66 | 67 | while (chain.length) { 68 | promise = promise.then(chain.shift(), chain.shift()) 69 | } 70 | 71 | return promise 72 | } 73 | 74 | /** 75 | * @Function 76 | * @param {Object} config - 请求配置项 77 | * @prop {String} options.url - 请求路径 78 | * @prop {Object} options.data - 请求参数 79 | * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型 80 | * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse 81 | * @prop {Object} [options.header = config.header] - 请求header 82 | * @prop {Object} [options.method = config.method] - 请求方法 83 | * @returns {Promise} 84 | */ 85 | request(config = {}) { 86 | return this.middleware(config) 87 | } 88 | 89 | get(url, options = {}) { 90 | return this.middleware({ 91 | url, 92 | method: 'GET', 93 | ...options 94 | }) 95 | } 96 | 97 | post(url, data, options = {}) { 98 | return this.middleware({ 99 | url, 100 | data, 101 | method: 'POST', 102 | ...options 103 | }) 104 | } 105 | 106 | // #ifndef MP-ALIPAY || MP-KUAISHOU || MP-JD 107 | put(url, data, options = {}) { 108 | return this.middleware({ 109 | url, 110 | data, 111 | method: 'PUT', 112 | ...options 113 | }) 114 | } 115 | 116 | // #endif 117 | 118 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 119 | delete(url, data, options = {}) { 120 | return this.middleware({ 121 | url, 122 | data, 123 | method: 'DELETE', 124 | ...options 125 | }) 126 | } 127 | 128 | // #endif 129 | 130 | // #ifdef H5 || MP-WEIXIN 131 | connect(url, data, options = {}) { 132 | return this.middleware({ 133 | url, 134 | data, 135 | method: 'CONNECT', 136 | ...options 137 | }) 138 | } 139 | 140 | // #endif 141 | 142 | // #ifdef H5 || MP-WEIXIN || MP-BAIDU 143 | head(url, data, options = {}) { 144 | return this.middleware({ 145 | url, 146 | data, 147 | method: 'HEAD', 148 | ...options 149 | }) 150 | } 151 | 152 | // #endif 153 | 154 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 155 | options(url, data, options = {}) { 156 | return this.middleware({ 157 | url, 158 | data, 159 | method: 'OPTIONS', 160 | ...options 161 | }) 162 | } 163 | 164 | // #endif 165 | 166 | // #ifdef H5 || MP-WEIXIN 167 | trace(url, data, options = {}) { 168 | return this.middleware({ 169 | url, 170 | data, 171 | method: 'TRACE', 172 | ...options 173 | }) 174 | } 175 | 176 | // #endif 177 | 178 | upload(url, config = {}) { 179 | config.url = url 180 | config.method = 'UPLOAD' 181 | return this.middleware(config) 182 | } 183 | 184 | download(url, config = {}) { 185 | config.url = url 186 | config.method = 'DOWNLOAD' 187 | return this.middleware(config) 188 | } 189 | 190 | get version () { 191 | return '3.1.0' 192 | } 193 | } 194 | 195 | 196 | /** 197 | * setConfig回调 198 | * @return {Object} - 返回操作后的config 199 | * @callback Request~setConfigCallback 200 | * @param {Object} config - 全局默认config 201 | */ 202 | -------------------------------------------------------------------------------- /DCloud/luch-request/core/Request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Class Request 3 | * @description luch-request http请求插件 4 | * @Author lu-ch 5 | * @Email webwork.s@qq.com 6 | * 文档: https://www.quanzhan.co/luch-request/ 7 | * github: https://github.com/lei-mu/luch-request 8 | * DCloud: http://ext.dcloud.net.cn/plugin?id=392 9 | */ 10 | 11 | 12 | import dispatchRequest from './dispatchRequest' 13 | import InterceptorManager from './InterceptorManager' 14 | import mergeConfig from './mergeConfig' 15 | import defaults from './defaults' 16 | import { isPlainObject } from '../utils' 17 | import clone from '../utils/clone' 18 | 19 | export default class Request { 20 | /** 21 | * @param {Object} arg - 全局配置 22 | * @param {String} arg.baseURL - 全局根路径 23 | * @param {Object} arg.header - 全局header 24 | * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式 25 | * @param {String} arg.dataType = [json] - 全局默认的dataType 26 | * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持 27 | * @param {Object} arg.custom - 全局默认的自定义参数 28 | * @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序 29 | * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+) 30 | * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+) 31 | * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+) 32 | * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300 33 | */ 34 | constructor(arg = {}) { 35 | if (!isPlainObject(arg)) { 36 | arg = {} 37 | console.warn('设置全局参数必须接收一个Object') 38 | } 39 | this.config = clone({...defaults, ...arg}) 40 | this.interceptors = { 41 | request: new InterceptorManager(), 42 | response: new InterceptorManager() 43 | } 44 | } 45 | 46 | /** 47 | * @Function 48 | * @param {Request~setConfigCallback} f - 设置全局默认配置 49 | */ 50 | setConfig(f) { 51 | this.config = f(this.config) 52 | } 53 | 54 | middleware(config) { 55 | config = mergeConfig(this.config, config) 56 | let chain = [dispatchRequest, undefined] 57 | let promise = Promise.resolve(config) 58 | 59 | this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { 60 | chain.unshift(interceptor.fulfilled, interceptor.rejected) 61 | }) 62 | 63 | this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { 64 | chain.push(interceptor.fulfilled, interceptor.rejected) 65 | }) 66 | 67 | while (chain.length) { 68 | promise = promise.then(chain.shift(), chain.shift()) 69 | } 70 | 71 | return promise 72 | } 73 | 74 | /** 75 | * @Function 76 | * @param {Object} config - 请求配置项 77 | * @prop {String} options.url - 请求路径 78 | * @prop {Object} options.data - 请求参数 79 | * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型 80 | * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse 81 | * @prop {Object} [options.header = config.header] - 请求header 82 | * @prop {Object} [options.method = config.method] - 请求方法 83 | * @returns {Promise} 84 | */ 85 | request(config = {}) { 86 | return this.middleware(config) 87 | } 88 | 89 | get(url, options = {}) { 90 | return this.middleware({ 91 | url, 92 | method: 'GET', 93 | ...options 94 | }) 95 | } 96 | 97 | post(url, data, options = {}) { 98 | return this.middleware({ 99 | url, 100 | data, 101 | method: 'POST', 102 | ...options 103 | }) 104 | } 105 | 106 | // #ifndef MP-ALIPAY || MP-KUAISHOU || MP-JD 107 | put(url, data, options = {}) { 108 | return this.middleware({ 109 | url, 110 | data, 111 | method: 'PUT', 112 | ...options 113 | }) 114 | } 115 | 116 | // #endif 117 | 118 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 119 | delete(url, data, options = {}) { 120 | return this.middleware({ 121 | url, 122 | data, 123 | method: 'DELETE', 124 | ...options 125 | }) 126 | } 127 | 128 | // #endif 129 | 130 | // #ifdef H5 || MP-WEIXIN 131 | connect(url, data, options = {}) { 132 | return this.middleware({ 133 | url, 134 | data, 135 | method: 'CONNECT', 136 | ...options 137 | }) 138 | } 139 | 140 | // #endif 141 | 142 | // #ifdef H5 || MP-WEIXIN || MP-BAIDU 143 | head(url, data, options = {}) { 144 | return this.middleware({ 145 | url, 146 | data, 147 | method: 'HEAD', 148 | ...options 149 | }) 150 | } 151 | 152 | // #endif 153 | 154 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 155 | options(url, data, options = {}) { 156 | return this.middleware({ 157 | url, 158 | data, 159 | method: 'OPTIONS', 160 | ...options 161 | }) 162 | } 163 | 164 | // #endif 165 | 166 | // #ifdef H5 || MP-WEIXIN 167 | trace(url, data, options = {}) { 168 | return this.middleware({ 169 | url, 170 | data, 171 | method: 'TRACE', 172 | ...options 173 | }) 174 | } 175 | 176 | // #endif 177 | 178 | upload(url, config = {}) { 179 | config.url = url 180 | config.method = 'UPLOAD' 181 | return this.middleware(config) 182 | } 183 | 184 | download(url, config = {}) { 185 | config.url = url 186 | config.method = 'DOWNLOAD' 187 | return this.middleware(config) 188 | } 189 | 190 | get version () { 191 | return '3.1.0' 192 | } 193 | } 194 | 195 | 196 | /** 197 | * setConfig回调 198 | * @return {Object} - 返回操作后的config 199 | * @callback Request~setConfigCallback 200 | * @param {Object} config - 全局默认config 201 | */ 202 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/core/Request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Class Request 3 | * @description luch-request http请求插件 4 | * @Author lu-ch 5 | * @Email webwork.s@qq.com 6 | * 文档: https://www.quanzhan.co/luch-request/ 7 | * github: https://github.com/lei-mu/luch-request 8 | * DCloud: http://ext.dcloud.net.cn/plugin?id=392 9 | */ 10 | 11 | 12 | import dispatchRequest from './dispatchRequest' 13 | import InterceptorManager from './InterceptorManager' 14 | import mergeConfig from './mergeConfig' 15 | import defaults from './defaults' 16 | import { isPlainObject } from '../utils' 17 | import clone from '../utils/clone' 18 | 19 | export default class Request { 20 | /** 21 | * @param {Object} arg - 全局配置 22 | * @param {String} arg.baseURL - 全局根路径 23 | * @param {Object} arg.header - 全局header 24 | * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式 25 | * @param {String} arg.dataType = [json] - 全局默认的dataType 26 | * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持 27 | * @param {Object} arg.custom - 全局默认的自定义参数 28 | * @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序 29 | * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+) 30 | * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+) 31 | * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+) 32 | * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300 33 | */ 34 | constructor(arg = {}) { 35 | if (!isPlainObject(arg)) { 36 | arg = {} 37 | console.warn('设置全局参数必须接收一个Object') 38 | } 39 | this.config = clone({...defaults, ...arg}) 40 | this.interceptors = { 41 | request: new InterceptorManager(), 42 | response: new InterceptorManager() 43 | } 44 | } 45 | 46 | /** 47 | * @Function 48 | * @param {Request~setConfigCallback} f - 设置全局默认配置 49 | */ 50 | setConfig(f) { 51 | this.config = f(this.config) 52 | } 53 | 54 | middleware(config) { 55 | config = mergeConfig(this.config, config) 56 | let chain = [dispatchRequest, undefined] 57 | let promise = Promise.resolve(config) 58 | 59 | this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { 60 | chain.unshift(interceptor.fulfilled, interceptor.rejected) 61 | }) 62 | 63 | this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { 64 | chain.push(interceptor.fulfilled, interceptor.rejected) 65 | }) 66 | 67 | while (chain.length) { 68 | promise = promise.then(chain.shift(), chain.shift()) 69 | } 70 | 71 | return promise 72 | } 73 | 74 | /** 75 | * @Function 76 | * @param {Object} config - 请求配置项 77 | * @prop {String} options.url - 请求路径 78 | * @prop {Object} options.data - 请求参数 79 | * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型 80 | * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse 81 | * @prop {Object} [options.header = config.header] - 请求header 82 | * @prop {Object} [options.method = config.method] - 请求方法 83 | * @returns {Promise} 84 | */ 85 | request(config = {}) { 86 | return this.middleware(config) 87 | } 88 | 89 | get(url, options = {}) { 90 | return this.middleware({ 91 | url, 92 | method: 'GET', 93 | ...options 94 | }) 95 | } 96 | 97 | post(url, data, options = {}) { 98 | return this.middleware({ 99 | url, 100 | data, 101 | method: 'POST', 102 | ...options 103 | }) 104 | } 105 | 106 | // #ifndef MP-ALIPAY || MP-KUAISHOU || MP-JD 107 | put(url, data, options = {}) { 108 | return this.middleware({ 109 | url, 110 | data, 111 | method: 'PUT', 112 | ...options 113 | }) 114 | } 115 | 116 | // #endif 117 | 118 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 119 | delete(url, data, options = {}) { 120 | return this.middleware({ 121 | url, 122 | data, 123 | method: 'DELETE', 124 | ...options 125 | }) 126 | } 127 | 128 | // #endif 129 | 130 | // #ifdef H5 || MP-WEIXIN 131 | connect(url, data, options = {}) { 132 | return this.middleware({ 133 | url, 134 | data, 135 | method: 'CONNECT', 136 | ...options 137 | }) 138 | } 139 | 140 | // #endif 141 | 142 | // #ifdef H5 || MP-WEIXIN || MP-BAIDU 143 | head(url, data, options = {}) { 144 | return this.middleware({ 145 | url, 146 | data, 147 | method: 'HEAD', 148 | ...options 149 | }) 150 | } 151 | 152 | // #endif 153 | 154 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 155 | options(url, data, options = {}) { 156 | return this.middleware({ 157 | url, 158 | data, 159 | method: 'OPTIONS', 160 | ...options 161 | }) 162 | } 163 | 164 | // #endif 165 | 166 | // #ifdef H5 || MP-WEIXIN 167 | trace(url, data, options = {}) { 168 | return this.middleware({ 169 | url, 170 | data, 171 | method: 'TRACE', 172 | ...options 173 | }) 174 | } 175 | 176 | // #endif 177 | 178 | upload(url, config = {}) { 179 | config.url = url 180 | config.method = 'UPLOAD' 181 | return this.middleware(config) 182 | } 183 | 184 | download(url, config = {}) { 185 | config.url = url 186 | config.method = 'DOWNLOAD' 187 | return this.middleware(config) 188 | } 189 | 190 | get version () { 191 | return '3.1.0' 192 | } 193 | } 194 | 195 | 196 | /** 197 | * setConfig回调 198 | * @return {Object} - 返回操作后的config 199 | * @callback Request~setConfigCallback 200 | * @param {Object} config - 全局默认config 201 | */ 202 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/core/Request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Class Request 3 | * @description luch-request http请求插件 4 | * @Author lu-ch 5 | * @Email webwork.s@qq.com 6 | * 文档: https://www.quanzhan.co/luch-request/ 7 | * github: https://github.com/lei-mu/luch-request 8 | * DCloud: http://ext.dcloud.net.cn/plugin?id=392 9 | */ 10 | 11 | 12 | import dispatchRequest from './dispatchRequest' 13 | import InterceptorManager from './InterceptorManager' 14 | import mergeConfig from './mergeConfig' 15 | import defaults from './defaults' 16 | import { isPlainObject } from '../utils' 17 | import clone from '../utils/clone' 18 | 19 | export default class Request { 20 | /** 21 | * @param {Object} arg - 全局配置 22 | * @param {String} arg.baseURL - 全局根路径 23 | * @param {Object} arg.header - 全局header 24 | * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式 25 | * @param {String} arg.dataType = [json] - 全局默认的dataType 26 | * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持 27 | * @param {Object} arg.custom - 全局默认的自定义参数 28 | * @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序 29 | * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+) 30 | * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+) 31 | * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+) 32 | * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300 33 | */ 34 | constructor(arg = {}) { 35 | if (!isPlainObject(arg)) { 36 | arg = {} 37 | console.warn('设置全局参数必须接收一个Object') 38 | } 39 | this.config = clone({...defaults, ...arg}) 40 | this.interceptors = { 41 | request: new InterceptorManager(), 42 | response: new InterceptorManager() 43 | } 44 | } 45 | 46 | /** 47 | * @Function 48 | * @param {Request~setConfigCallback} f - 设置全局默认配置 49 | */ 50 | setConfig(f) { 51 | this.config = f(this.config) 52 | } 53 | 54 | middleware(config) { 55 | config = mergeConfig(this.config, config) 56 | let chain = [dispatchRequest, undefined] 57 | let promise = Promise.resolve(config) 58 | 59 | this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { 60 | chain.unshift(interceptor.fulfilled, interceptor.rejected) 61 | }) 62 | 63 | this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { 64 | chain.push(interceptor.fulfilled, interceptor.rejected) 65 | }) 66 | 67 | while (chain.length) { 68 | promise = promise.then(chain.shift(), chain.shift()) 69 | } 70 | 71 | return promise 72 | } 73 | 74 | /** 75 | * @Function 76 | * @param {Object} config - 请求配置项 77 | * @prop {String} options.url - 请求路径 78 | * @prop {Object} options.data - 请求参数 79 | * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型 80 | * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse 81 | * @prop {Object} [options.header = config.header] - 请求header 82 | * @prop {Object} [options.method = config.method] - 请求方法 83 | * @returns {Promise} 84 | */ 85 | request(config = {}) { 86 | return this.middleware(config) 87 | } 88 | 89 | get(url, options = {}) { 90 | return this.middleware({ 91 | url, 92 | method: 'GET', 93 | ...options 94 | }) 95 | } 96 | 97 | post(url, data, options = {}) { 98 | return this.middleware({ 99 | url, 100 | data, 101 | method: 'POST', 102 | ...options 103 | }) 104 | } 105 | 106 | // #ifndef MP-ALIPAY || MP-KUAISHOU || MP-JD 107 | put(url, data, options = {}) { 108 | return this.middleware({ 109 | url, 110 | data, 111 | method: 'PUT', 112 | ...options 113 | }) 114 | } 115 | 116 | // #endif 117 | 118 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 119 | delete(url, data, options = {}) { 120 | return this.middleware({ 121 | url, 122 | data, 123 | method: 'DELETE', 124 | ...options 125 | }) 126 | } 127 | 128 | // #endif 129 | 130 | // #ifdef H5 || MP-WEIXIN 131 | connect(url, data, options = {}) { 132 | return this.middleware({ 133 | url, 134 | data, 135 | method: 'CONNECT', 136 | ...options 137 | }) 138 | } 139 | 140 | // #endif 141 | 142 | // #ifdef H5 || MP-WEIXIN || MP-BAIDU 143 | head(url, data, options = {}) { 144 | return this.middleware({ 145 | url, 146 | data, 147 | method: 'HEAD', 148 | ...options 149 | }) 150 | } 151 | 152 | // #endif 153 | 154 | // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU 155 | options(url, data, options = {}) { 156 | return this.middleware({ 157 | url, 158 | data, 159 | method: 'OPTIONS', 160 | ...options 161 | }) 162 | } 163 | 164 | // #endif 165 | 166 | // #ifdef H5 || MP-WEIXIN 167 | trace(url, data, options = {}) { 168 | return this.middleware({ 169 | url, 170 | data, 171 | method: 'TRACE', 172 | ...options 173 | }) 174 | } 175 | 176 | // #endif 177 | 178 | upload(url, config = {}) { 179 | config.url = url 180 | config.method = 'UPLOAD' 181 | return this.middleware(config) 182 | } 183 | 184 | download(url, config = {}) { 185 | config.url = url 186 | config.method = 'DOWNLOAD' 187 | return this.middleware(config) 188 | } 189 | 190 | get version () { 191 | return '3.1.0' 192 | } 193 | } 194 | 195 | 196 | /** 197 | * setConfig回调 198 | * @return {Object} - 返回操作后的config 199 | * @callback Request~setConfigCallback 200 | * @param {Object} config - 全局默认config 201 | */ 202 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | /* Basic Options */ 5 | // "incremental": true, /* Enable incremental compilation */ 6 | "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 7 | "module": "ES2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 8 | // "lib": [], /* Specify library files to be included in the compilation. */ 9 | // "allowJs": true, /* Allow javascript files to be compiled. */ 10 | // "checkJs": true, /* Report errors in .js files. */ 11 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 12 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 13 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 14 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 15 | // "outFile": "./", /* Concatenate and emit output to single file. */ 16 | // "outDir": "../test-template/node_modules/uni-draw-poster", /* Redirect output structure to the directory. */ 17 | "outDir": "../dist", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | /* Strict Type-Checking Options */ 27 | "strict": true, /* Enable all strict type-checking options. */ 28 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 29 | // "strictNullChecks": true, /* Enable strict null checks. */ 30 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 31 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 32 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 33 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 34 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | /* Module Resolution Options */ 41 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 42 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 43 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 44 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 45 | "types": [ 46 | "@dcloudio/types" 47 | ], /* Type declaration files to be included in compilation. */ 48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | /* Source Map Options */ 53 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 54 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 55 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 56 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 57 | /* Experimental Options */ 58 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 59 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 60 | /* Advanced Options */ 61 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 62 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 63 | } 64 | } -------------------------------------------------------------------------------- /src/lib/luch-request.d.ts: -------------------------------------------------------------------------------- 1 | export type HttpTask = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask; 2 | 3 | export type HttpRequestTask = UniApp.RequestTask; 4 | 5 | export type HttpUploadTask = UniApp.UploadTask; 6 | 7 | export type HttpDownloadTask = UniApp.DownloadTask; 8 | 9 | export type HttpMethod = 10 | "GET" 11 | | "POST" 12 | | "PUT" 13 | | "DELETE" 14 | | "CONNECT" 15 | | "HEAD" 16 | | "OPTIONS" 17 | | "TRACE" 18 | | "UPLOAD" 19 | | "DOWNLOAD"; 20 | 21 | export type HttpRequestHeader = Record; 22 | 23 | export type HttpParams = Record; 24 | 25 | export type HttpData = Record; 26 | 27 | export type HttpResponseType = 'arraybuffer' | 'text'; 28 | 29 | export type HttpCustom = Record; 30 | 31 | export type HttpFileType = 'image' | 'video' | 'audio'; 32 | 33 | export type HttpFormData = Record; 34 | 35 | export type HttpResponseHeader = Record & { 36 | "set-cookie"?: string[] 37 | }; 38 | 39 | export interface HttpRequestConfig { 40 | /** @desc 请求服务器接口地址 */ 41 | url?: string; 42 | /** @desc 请求方式,默认为 GET */ 43 | method?: HttpMethod; 44 | /** @desc 请求基地址 */ 45 | baseURL?: string; 46 | /** @desc 请求头信息,不能设置 Referer,App、H5 端会自动带上 cookie,且 H5 端不可手动修改 */ 47 | header?: HttpRequestHeader; 48 | /** @desc 请求查询参数,自动拼接为查询字符串 */ 49 | params?: HttpParams; 50 | /** @desc 请求体参数 */ 51 | data?: HttpData; 52 | /** @desc 超时时间,单位 ms,默认为 60000,仅 H5 (HBuilderX 2.9.9+)、APP (HBuilderX 2.9.9+)、微信小程序 (2.10.0)、支付宝小程序支持 */ 53 | timeout?: number; 54 | /** @desc 跨域请求时是否携带凭证 (cookies),默认为 false,仅 H5 (HBuilderX 2.6.15+) 支持 */ 55 | withCredentials?: boolean; 56 | /** @desc 设置响应的数据类型,支付宝小程序不支持 */ 57 | responseType?: HttpResponseType; 58 | /** @desc 全局自定义验证器 */ 59 | validateStatus?: ((statusCode: number) => boolean) | null; 60 | 61 | 62 | /** params 参数自定义处理 */ 63 | paramsSerializer?: (params: AnyObject) => string | void; 64 | 65 | /** @desc 默认为 json,如果设为 json,会尝试对返回的数据做一次 JSON.parse */ 66 | dataType?: string; 67 | /** @desc DNS 解析时是否优先使用 ipv4,默认为 false,仅 App-Android (HBuilderX 2.8.0+) 支持 */ 68 | firstIpv4?: boolean; 69 | /** @desc 是否验证 SSL 证书,默认为 true,仅 App-Android (HBuilderX 2.3.3+) 支持 */ 70 | sslVerify?: boolean; 71 | 72 | /** @desc 开启 http2;微信小程序 */ 73 | enableHttp2?: boolean; 74 | 75 | /** @desc 开启 quic;微信小程序 */ 76 | enableQuic?: boolean; 77 | /** @desc 开启 cache;微信小程序、字节跳动小程序 2.31.0+ */ 78 | enableCache?: boolean; 79 | /** @desc 开启 httpDNS;微信小程序 */ 80 | enableHttpDNS?: boolean; 81 | /** @desc httpDNS 服务商;微信小程序 */ 82 | httpDNSServiceId?: string; 83 | /** @desc 开启 transfer-encoding chunked;微信小程序 */ 84 | enableChunked?: boolean; 85 | /** @desc wifi下使用移动网络发送请求;微信小程序 */ 86 | forceCellularNetwork?: boolean; 87 | /** @desc 开启后可在headers中编辑cookie;支付宝小程序 10.2.33+ */ 88 | enableCookie?: boolean; 89 | /** @desc 是否开启云加速;百度小程序 3.310.11+ */ 90 | cloudCache?: boolean | object; 91 | /** @desc 控制当前请求是否延时至首屏内容渲染后发送;百度小程序 3.310.11+ */ 92 | defer?: boolean; 93 | 94 | /** @desc 自定义参数 */ 95 | custom?: HttpCustom; 96 | 97 | /** @desc 返回当前请求的 task 和 options,不要在这里修改 options */ 98 | getTask?: (task: T, options: HttpRequestConfig) => void; 99 | 100 | /** @desc 需要上传的文件列表,使用 files 时,filePath 和 name 不生效,仅支持 App、H5 (2.6.15+) */ 101 | files?: { name?: string; file?: File; uri: string; }[]; 102 | /** @desc 文件类型,仅支付宝小程序支持且为必填项 */ 103 | fileType?: HttpFileType; 104 | /** @desc 要上传的文件对象,仅 H5 (2.6.15+) 支持 */ 105 | file?: File; 106 | /** @desc 要上传文件资源的路径,使用 files 时,filePath 和 name 不生效 */ 107 | filePath?: string; 108 | /** @desc 文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,使用 files 时,filePath 和 name 不生效 */ 109 | name?: string; 110 | /** @desc 请求中其他额外的 form data */ 111 | formData?: HttpFormData; 112 | } 113 | 114 | export interface HttpResponse { 115 | data: T; 116 | statusCode: number; 117 | header: HttpResponseHeader; 118 | config: HttpRequestConfig; 119 | cookies: string[]; 120 | errMsg: string; 121 | rawData: any; 122 | } 123 | 124 | export interface HttpUploadResponse { 125 | data: T; 126 | statusCode: number; 127 | config: HttpRequestConfig; 128 | errMsg: string; 129 | rawData: any; 130 | } 131 | 132 | export interface HttpDownloadResponse extends HttpResponse { 133 | tempFilePath: string; 134 | apFilePath?: string; 135 | filePath?: string; 136 | fileContent?: string; 137 | } 138 | 139 | export interface HttpError { 140 | data?: T; 141 | statusCode?: number; 142 | header?: HttpResponseHeader; 143 | config: HttpRequestConfig; 144 | cookies?: string[]; 145 | errMsg: string; 146 | } 147 | 148 | export interface HttpPromise extends Promise> { 149 | } 150 | 151 | export interface HttpInterceptorManager { 152 | use(onFulfilled?: (value: V) => V | Promise, onRejected?: (error: E) => T | Promise): void; 153 | 154 | eject(id: number): void; 155 | } 156 | 157 | export abstract class HttpRequestAbstract { 158 | constructor(config?: HttpRequestConfig); 159 | 160 | interceptors: { 161 | request: HttpInterceptorManager; 162 | response: HttpInterceptorManager; 163 | } 164 | 165 | request, D = HttpRequestTask>(config: HttpRequestConfig): Promise; 166 | 167 | get, D = HttpRequestTask>(url: string, config?: HttpRequestConfig): Promise; 168 | 169 | delete, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 170 | 171 | head, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 172 | 173 | options, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 174 | 175 | post, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 176 | 177 | put, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 178 | 179 | config: HttpRequestConfig; 180 | 181 | setConfig(onSend: (config: HttpRequestConfig) => HttpRequestConfig): void; 182 | 183 | connect, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 184 | 185 | trace, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 186 | 187 | upload, D = HttpUploadTask>(url: string, config?: HttpRequestConfig): Promise; 188 | 189 | download, D = HttpDownloadTask>(url: string, config?: HttpRequestConfig): Promise; 190 | 191 | middleware, D = HttpTask>(config: HttpRequestConfig): Promise; 192 | } 193 | 194 | declare class HttpRequest extends HttpRequestAbstract { 195 | } 196 | 197 | export default HttpRequest; 198 | -------------------------------------------------------------------------------- /DCloud/luch-request/index.d.ts: -------------------------------------------------------------------------------- 1 | export type HttpTask = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask; 2 | 3 | export type HttpRequestTask = UniApp.RequestTask; 4 | 5 | export type HttpUploadTask = UniApp.UploadTask; 6 | 7 | export type HttpDownloadTask = UniApp.DownloadTask; 8 | 9 | export type HttpMethod = 10 | "GET" 11 | | "POST" 12 | | "PUT" 13 | | "DELETE" 14 | | "CONNECT" 15 | | "HEAD" 16 | | "OPTIONS" 17 | | "TRACE" 18 | | "UPLOAD" 19 | | "DOWNLOAD"; 20 | 21 | export type HttpRequestHeader = Record; 22 | 23 | export type HttpParams = Record; 24 | 25 | export type HttpData = Record; 26 | 27 | export type HttpResponseType = 'arraybuffer' | 'text'; 28 | 29 | export type HttpCustom = Record; 30 | 31 | export type HttpFileType = 'image' | 'video' | 'audio'; 32 | 33 | export type HttpFormData = Record; 34 | 35 | export type HttpResponseHeader = Record & { 36 | "set-cookie"?: string[] 37 | }; 38 | 39 | export interface HttpRequestConfig { 40 | /** @desc 请求服务器接口地址 */ 41 | url?: string; 42 | /** @desc 请求方式,默认为 GET */ 43 | method?: HttpMethod; 44 | /** @desc 请求基地址 */ 45 | baseURL?: string; 46 | /** @desc 请求头信息,不能设置 Referer,App、H5 端会自动带上 cookie,且 H5 端不可手动修改 */ 47 | header?: HttpRequestHeader; 48 | /** @desc 请求查询参数,自动拼接为查询字符串 */ 49 | params?: HttpParams; 50 | /** @desc 请求体参数 */ 51 | data?: HttpData; 52 | /** @desc 超时时间,单位 ms,默认为 60000,仅 H5 (HBuilderX 2.9.9+)、APP (HBuilderX 2.9.9+)、微信小程序 (2.10.0)、支付宝小程序支持 */ 53 | timeout?: number; 54 | /** @desc 跨域请求时是否携带凭证 (cookies),默认为 false,仅 H5 (HBuilderX 2.6.15+) 支持 */ 55 | withCredentials?: boolean; 56 | /** @desc 设置响应的数据类型,支付宝小程序不支持 */ 57 | responseType?: HttpResponseType; 58 | /** @desc 全局自定义验证器 */ 59 | validateStatus?: ((statusCode: number) => boolean) | null; 60 | 61 | 62 | /** params 参数自定义处理 */ 63 | paramsSerializer?: (params: AnyObject) => string | void; 64 | 65 | /** @desc 默认为 json,如果设为 json,会尝试对返回的数据做一次 JSON.parse */ 66 | dataType?: string; 67 | /** @desc DNS 解析时是否优先使用 ipv4,默认为 false,仅 App-Android (HBuilderX 2.8.0+) 支持 */ 68 | firstIpv4?: boolean; 69 | /** @desc 是否验证 SSL 证书,默认为 true,仅 App-Android (HBuilderX 2.3.3+) 支持 */ 70 | sslVerify?: boolean; 71 | 72 | /** @desc 开启 http2;微信小程序 */ 73 | enableHttp2?: boolean; 74 | 75 | /** @desc 开启 quic;微信小程序 */ 76 | enableQuic?: boolean; 77 | /** @desc 开启 cache;微信小程序、字节跳动小程序 2.31.0+ */ 78 | enableCache?: boolean; 79 | /** @desc 开启 httpDNS;微信小程序 */ 80 | enableHttpDNS?: boolean; 81 | /** @desc httpDNS 服务商;微信小程序 */ 82 | httpDNSServiceId?: string; 83 | /** @desc 开启 transfer-encoding chunked;微信小程序 */ 84 | enableChunked?: boolean; 85 | /** @desc wifi下使用移动网络发送请求;微信小程序 */ 86 | forceCellularNetwork?: boolean; 87 | /** @desc 开启后可在headers中编辑cookie;支付宝小程序 10.2.33+ */ 88 | enableCookie?: boolean; 89 | /** @desc 是否开启云加速;百度小程序 3.310.11+ */ 90 | cloudCache?: boolean | object; 91 | /** @desc 控制当前请求是否延时至首屏内容渲染后发送;百度小程序 3.310.11+ */ 92 | defer?: boolean; 93 | 94 | /** @desc 自定义参数 */ 95 | custom?: HttpCustom; 96 | 97 | /** @desc 返回当前请求的 task 和 options,不要在这里修改 options */ 98 | getTask?: (task: T, options: HttpRequestConfig) => void; 99 | 100 | /** @desc 需要上传的文件列表,使用 files 时,filePath 和 name 不生效,仅支持 App、H5 (2.6.15+) */ 101 | files?: { name?: string; file?: File; uri: string; }[]; 102 | /** @desc 文件类型,仅支付宝小程序支持且为必填项 */ 103 | fileType?: HttpFileType; 104 | /** @desc 要上传的文件对象,仅 H5 (2.6.15+) 支持 */ 105 | file?: File; 106 | /** @desc 要上传文件资源的路径,使用 files 时,filePath 和 name 不生效 */ 107 | filePath?: string; 108 | /** @desc 文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,使用 files 时,filePath 和 name 不生效 */ 109 | name?: string; 110 | /** @desc 请求中其他额外的 form data */ 111 | formData?: HttpFormData; 112 | } 113 | 114 | export interface HttpResponse { 115 | data: T; 116 | statusCode: number; 117 | header: HttpResponseHeader; 118 | config: HttpRequestConfig; 119 | cookies: string[]; 120 | errMsg: string; 121 | rawData: any; 122 | } 123 | 124 | export interface HttpUploadResponse { 125 | data: T; 126 | statusCode: number; 127 | config: HttpRequestConfig; 128 | errMsg: string; 129 | rawData: any; 130 | } 131 | 132 | export interface HttpDownloadResponse extends HttpResponse { 133 | tempFilePath: string; 134 | apFilePath?: string; 135 | filePath?: string; 136 | fileContent?: string; 137 | } 138 | 139 | export interface HttpError { 140 | data?: T; 141 | statusCode?: number; 142 | header?: HttpResponseHeader; 143 | config: HttpRequestConfig; 144 | cookies?: string[]; 145 | errMsg: string; 146 | } 147 | 148 | export interface HttpPromise extends Promise> { 149 | } 150 | 151 | export interface HttpInterceptorManager { 152 | use(onFulfilled?: (value: V) => V | Promise, onRejected?: (error: E) => T | Promise): void; 153 | 154 | eject(id: number): void; 155 | } 156 | 157 | export abstract class HttpRequestAbstract { 158 | constructor(config?: HttpRequestConfig); 159 | 160 | interceptors: { 161 | request: HttpInterceptorManager; 162 | response: HttpInterceptorManager; 163 | } 164 | 165 | request, D = HttpRequestTask>(config: HttpRequestConfig): Promise; 166 | 167 | get, D = HttpRequestTask>(url: string, config?: HttpRequestConfig): Promise; 168 | 169 | delete, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 170 | 171 | head, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 172 | 173 | options, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 174 | 175 | post, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 176 | 177 | put, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 178 | 179 | config: HttpRequestConfig; 180 | 181 | setConfig(onSend: (config: HttpRequestConfig) => HttpRequestConfig): void; 182 | 183 | connect, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 184 | 185 | trace, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 186 | 187 | upload, D = HttpUploadTask>(url: string, config?: HttpRequestConfig): Promise; 188 | 189 | download, D = HttpDownloadTask>(url: string, config?: HttpRequestConfig): Promise; 190 | 191 | middleware, D = HttpTask>(config: HttpRequestConfig): Promise; 192 | } 193 | 194 | declare class HttpRequest extends HttpRequestAbstract { 195 | } 196 | 197 | export default HttpRequest; 198 | -------------------------------------------------------------------------------- /test/dev-test/utils/luch-request/index.d.ts: -------------------------------------------------------------------------------- 1 | export type HttpTask = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask; 2 | 3 | export type HttpRequestTask = UniApp.RequestTask; 4 | 5 | export type HttpUploadTask = UniApp.UploadTask; 6 | 7 | export type HttpDownloadTask = UniApp.DownloadTask; 8 | 9 | export type HttpMethod = 10 | "GET" 11 | | "POST" 12 | | "PUT" 13 | | "DELETE" 14 | | "CONNECT" 15 | | "HEAD" 16 | | "OPTIONS" 17 | | "TRACE" 18 | | "UPLOAD" 19 | | "DOWNLOAD"; 20 | 21 | export type HttpRequestHeader = Record; 22 | 23 | export type HttpParams = Record; 24 | 25 | export type HttpData = Record; 26 | 27 | export type HttpResponseType = 'arraybuffer' | 'text'; 28 | 29 | export type HttpCustom = Record; 30 | 31 | export type HttpFileType = 'image' | 'video' | 'audio'; 32 | 33 | export type HttpFormData = Record; 34 | 35 | export type HttpResponseHeader = Record & { 36 | "set-cookie"?: string[] 37 | }; 38 | 39 | export interface HttpRequestConfig { 40 | /** @desc 请求服务器接口地址 */ 41 | url?: string; 42 | /** @desc 请求方式,默认为 GET */ 43 | method?: HttpMethod; 44 | /** @desc 请求基地址 */ 45 | baseURL?: string; 46 | /** @desc 请求头信息,不能设置 Referer,App、H5 端会自动带上 cookie,且 H5 端不可手动修改 */ 47 | header?: HttpRequestHeader; 48 | /** @desc 请求查询参数,自动拼接为查询字符串 */ 49 | params?: HttpParams; 50 | /** @desc 请求体参数 */ 51 | data?: HttpData; 52 | /** @desc 超时时间,单位 ms,默认为 60000,仅 H5 (HBuilderX 2.9.9+)、APP (HBuilderX 2.9.9+)、微信小程序 (2.10.0)、支付宝小程序支持 */ 53 | timeout?: number; 54 | /** @desc 跨域请求时是否携带凭证 (cookies),默认为 false,仅 H5 (HBuilderX 2.6.15+) 支持 */ 55 | withCredentials?: boolean; 56 | /** @desc 设置响应的数据类型,支付宝小程序不支持 */ 57 | responseType?: HttpResponseType; 58 | /** @desc 全局自定义验证器 */ 59 | validateStatus?: ((statusCode: number) => boolean) | null; 60 | 61 | 62 | /** params 参数自定义处理 */ 63 | paramsSerializer?: (params: AnyObject) => string | void; 64 | 65 | /** @desc 默认为 json,如果设为 json,会尝试对返回的数据做一次 JSON.parse */ 66 | dataType?: string; 67 | /** @desc DNS 解析时是否优先使用 ipv4,默认为 false,仅 App-Android (HBuilderX 2.8.0+) 支持 */ 68 | firstIpv4?: boolean; 69 | /** @desc 是否验证 SSL 证书,默认为 true,仅 App-Android (HBuilderX 2.3.3+) 支持 */ 70 | sslVerify?: boolean; 71 | 72 | /** @desc 开启 http2;微信小程序 */ 73 | enableHttp2?: boolean; 74 | 75 | /** @desc 开启 quic;微信小程序 */ 76 | enableQuic?: boolean; 77 | /** @desc 开启 cache;微信小程序、字节跳动小程序 2.31.0+ */ 78 | enableCache?: boolean; 79 | /** @desc 开启 httpDNS;微信小程序 */ 80 | enableHttpDNS?: boolean; 81 | /** @desc httpDNS 服务商;微信小程序 */ 82 | httpDNSServiceId?: string; 83 | /** @desc 开启 transfer-encoding chunked;微信小程序 */ 84 | enableChunked?: boolean; 85 | /** @desc wifi下使用移动网络发送请求;微信小程序 */ 86 | forceCellularNetwork?: boolean; 87 | /** @desc 开启后可在headers中编辑cookie;支付宝小程序 10.2.33+ */ 88 | enableCookie?: boolean; 89 | /** @desc 是否开启云加速;百度小程序 3.310.11+ */ 90 | cloudCache?: boolean | object; 91 | /** @desc 控制当前请求是否延时至首屏内容渲染后发送;百度小程序 3.310.11+ */ 92 | defer?: boolean; 93 | 94 | /** @desc 自定义参数 */ 95 | custom?: HttpCustom; 96 | 97 | /** @desc 返回当前请求的 task 和 options,不要在这里修改 options */ 98 | getTask?: (task: T, options: HttpRequestConfig) => void; 99 | 100 | /** @desc 需要上传的文件列表,使用 files 时,filePath 和 name 不生效,仅支持 App、H5 (2.6.15+) */ 101 | files?: { name?: string; file?: File; uri: string; }[]; 102 | /** @desc 文件类型,仅支付宝小程序支持且为必填项 */ 103 | fileType?: HttpFileType; 104 | /** @desc 要上传的文件对象,仅 H5 (2.6.15+) 支持 */ 105 | file?: File; 106 | /** @desc 要上传文件资源的路径,使用 files 时,filePath 和 name 不生效 */ 107 | filePath?: string; 108 | /** @desc 文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,使用 files 时,filePath 和 name 不生效 */ 109 | name?: string; 110 | /** @desc 请求中其他额外的 form data */ 111 | formData?: HttpFormData; 112 | } 113 | 114 | export interface HttpResponse { 115 | data: T; 116 | statusCode: number; 117 | header: HttpResponseHeader; 118 | config: HttpRequestConfig; 119 | cookies: string[]; 120 | errMsg: string; 121 | rawData: any; 122 | } 123 | 124 | export interface HttpUploadResponse { 125 | data: T; 126 | statusCode: number; 127 | config: HttpRequestConfig; 128 | errMsg: string; 129 | rawData: any; 130 | } 131 | 132 | export interface HttpDownloadResponse extends HttpResponse { 133 | tempFilePath: string; 134 | apFilePath?: string; 135 | filePath?: string; 136 | fileContent?: string; 137 | } 138 | 139 | export interface HttpError { 140 | data?: T; 141 | statusCode?: number; 142 | header?: HttpResponseHeader; 143 | config: HttpRequestConfig; 144 | cookies?: string[]; 145 | errMsg: string; 146 | } 147 | 148 | export interface HttpPromise extends Promise> { 149 | } 150 | 151 | export interface HttpInterceptorManager { 152 | use(onFulfilled?: (value: V) => V | Promise, onRejected?: (error: E) => T | Promise): void; 153 | 154 | eject(id: number): void; 155 | } 156 | 157 | export abstract class HttpRequestAbstract { 158 | constructor(config?: HttpRequestConfig); 159 | 160 | interceptors: { 161 | request: HttpInterceptorManager; 162 | response: HttpInterceptorManager; 163 | } 164 | 165 | request, D = HttpRequestTask>(config: HttpRequestConfig): Promise; 166 | 167 | get, D = HttpRequestTask>(url: string, config?: HttpRequestConfig): Promise; 168 | 169 | delete, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 170 | 171 | head, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 172 | 173 | options, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 174 | 175 | post, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 176 | 177 | put, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 178 | 179 | config: HttpRequestConfig; 180 | 181 | setConfig(onSend: (config: HttpRequestConfig) => HttpRequestConfig): void; 182 | 183 | connect, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 184 | 185 | trace, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 186 | 187 | upload, D = HttpUploadTask>(url: string, config?: HttpRequestConfig): Promise; 188 | 189 | download, D = HttpDownloadTask>(url: string, config?: HttpRequestConfig): Promise; 190 | 191 | middleware, D = HttpTask>(config: HttpRequestConfig): Promise; 192 | } 193 | 194 | declare class HttpRequest extends HttpRequestAbstract { 195 | } 196 | 197 | export default HttpRequest; 198 | -------------------------------------------------------------------------------- /example/request-demo/utils/luch-request/index.d.ts: -------------------------------------------------------------------------------- 1 | export type HttpTask = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask; 2 | 3 | export type HttpRequestTask = UniApp.RequestTask; 4 | 5 | export type HttpUploadTask = UniApp.UploadTask; 6 | 7 | export type HttpDownloadTask = UniApp.DownloadTask; 8 | 9 | export type HttpMethod = 10 | "GET" 11 | | "POST" 12 | | "PUT" 13 | | "DELETE" 14 | | "CONNECT" 15 | | "HEAD" 16 | | "OPTIONS" 17 | | "TRACE" 18 | | "UPLOAD" 19 | | "DOWNLOAD"; 20 | 21 | export type HttpRequestHeader = Record; 22 | 23 | export type HttpParams = Record; 24 | 25 | export type HttpData = Record; 26 | 27 | export type HttpResponseType = 'arraybuffer' | 'text'; 28 | 29 | export type HttpCustom = Record; 30 | 31 | export type HttpFileType = 'image' | 'video' | 'audio'; 32 | 33 | export type HttpFormData = Record; 34 | 35 | export type HttpResponseHeader = Record & { 36 | "set-cookie"?: string[] 37 | }; 38 | 39 | export interface HttpRequestConfig { 40 | /** @desc 请求服务器接口地址 */ 41 | url?: string; 42 | /** @desc 请求方式,默认为 GET */ 43 | method?: HttpMethod; 44 | /** @desc 请求基地址 */ 45 | baseURL?: string; 46 | /** @desc 请求头信息,不能设置 Referer,App、H5 端会自动带上 cookie,且 H5 端不可手动修改 */ 47 | header?: HttpRequestHeader; 48 | /** @desc 请求查询参数,自动拼接为查询字符串 */ 49 | params?: HttpParams; 50 | /** @desc 请求体参数 */ 51 | data?: HttpData; 52 | /** @desc 超时时间,单位 ms,默认为 60000,仅 H5 (HBuilderX 2.9.9+)、APP (HBuilderX 2.9.9+)、微信小程序 (2.10.0)、支付宝小程序支持 */ 53 | timeout?: number; 54 | /** @desc 跨域请求时是否携带凭证 (cookies),默认为 false,仅 H5 (HBuilderX 2.6.15+) 支持 */ 55 | withCredentials?: boolean; 56 | /** @desc 设置响应的数据类型,支付宝小程序不支持 */ 57 | responseType?: HttpResponseType; 58 | /** @desc 全局自定义验证器 */ 59 | validateStatus?: ((statusCode: number) => boolean) | null; 60 | 61 | 62 | /** params 参数自定义处理 */ 63 | paramsSerializer?: (params: AnyObject) => string | void; 64 | 65 | /** @desc 默认为 json,如果设为 json,会尝试对返回的数据做一次 JSON.parse */ 66 | dataType?: string; 67 | /** @desc DNS 解析时是否优先使用 ipv4,默认为 false,仅 App-Android (HBuilderX 2.8.0+) 支持 */ 68 | firstIpv4?: boolean; 69 | /** @desc 是否验证 SSL 证书,默认为 true,仅 App-Android (HBuilderX 2.3.3+) 支持 */ 70 | sslVerify?: boolean; 71 | 72 | /** @desc 开启 http2;微信小程序 */ 73 | enableHttp2?: boolean; 74 | 75 | /** @desc 开启 quic;微信小程序 */ 76 | enableQuic?: boolean; 77 | /** @desc 开启 cache;微信小程序、字节跳动小程序 2.31.0+ */ 78 | enableCache?: boolean; 79 | /** @desc 开启 httpDNS;微信小程序 */ 80 | enableHttpDNS?: boolean; 81 | /** @desc httpDNS 服务商;微信小程序 */ 82 | httpDNSServiceId?: string; 83 | /** @desc 开启 transfer-encoding chunked;微信小程序 */ 84 | enableChunked?: boolean; 85 | /** @desc wifi下使用移动网络发送请求;微信小程序 */ 86 | forceCellularNetwork?: boolean; 87 | /** @desc 开启后可在headers中编辑cookie;支付宝小程序 10.2.33+ */ 88 | enableCookie?: boolean; 89 | /** @desc 是否开启云加速;百度小程序 3.310.11+ */ 90 | cloudCache?: boolean | object; 91 | /** @desc 控制当前请求是否延时至首屏内容渲染后发送;百度小程序 3.310.11+ */ 92 | defer?: boolean; 93 | 94 | /** @desc 自定义参数 */ 95 | custom?: HttpCustom; 96 | 97 | /** @desc 返回当前请求的 task 和 options,不要在这里修改 options */ 98 | getTask?: (task: T, options: HttpRequestConfig) => void; 99 | 100 | /** @desc 需要上传的文件列表,使用 files 时,filePath 和 name 不生效,仅支持 App、H5 (2.6.15+) */ 101 | files?: { name?: string; file?: File; uri: string; }[]; 102 | /** @desc 文件类型,仅支付宝小程序支持且为必填项 */ 103 | fileType?: HttpFileType; 104 | /** @desc 要上传的文件对象,仅 H5 (2.6.15+) 支持 */ 105 | file?: File; 106 | /** @desc 要上传文件资源的路径,使用 files 时,filePath 和 name 不生效 */ 107 | filePath?: string; 108 | /** @desc 文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,使用 files 时,filePath 和 name 不生效 */ 109 | name?: string; 110 | /** @desc 请求中其他额外的 form data */ 111 | formData?: HttpFormData; 112 | } 113 | 114 | export interface HttpResponse { 115 | data: T; 116 | statusCode: number; 117 | header: HttpResponseHeader; 118 | config: HttpRequestConfig; 119 | cookies: string[]; 120 | errMsg: string; 121 | rawData: any; 122 | } 123 | 124 | export interface HttpUploadResponse { 125 | data: T; 126 | statusCode: number; 127 | config: HttpRequestConfig; 128 | errMsg: string; 129 | rawData: any; 130 | } 131 | 132 | export interface HttpDownloadResponse extends HttpResponse { 133 | tempFilePath: string; 134 | apFilePath?: string; 135 | filePath?: string; 136 | fileContent?: string; 137 | } 138 | 139 | export interface HttpError { 140 | data?: T; 141 | statusCode?: number; 142 | header?: HttpResponseHeader; 143 | config: HttpRequestConfig; 144 | cookies?: string[]; 145 | errMsg: string; 146 | } 147 | 148 | export interface HttpPromise extends Promise> { 149 | } 150 | 151 | export interface HttpInterceptorManager { 152 | use(onFulfilled?: (value: V) => V | Promise, onRejected?: (error: E) => T | Promise): void; 153 | 154 | eject(id: number): void; 155 | } 156 | 157 | export abstract class HttpRequestAbstract { 158 | constructor(config?: HttpRequestConfig); 159 | 160 | interceptors: { 161 | request: HttpInterceptorManager; 162 | response: HttpInterceptorManager; 163 | } 164 | 165 | request, D = HttpRequestTask>(config: HttpRequestConfig): Promise; 166 | 167 | get, D = HttpRequestTask>(url: string, config?: HttpRequestConfig): Promise; 168 | 169 | delete, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 170 | 171 | head, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 172 | 173 | options, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 174 | 175 | post, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 176 | 177 | put, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 178 | 179 | config: HttpRequestConfig; 180 | 181 | setConfig(onSend: (config: HttpRequestConfig) => HttpRequestConfig): void; 182 | 183 | connect, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 184 | 185 | trace, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig): Promise; 186 | 187 | upload, D = HttpUploadTask>(url: string, config?: HttpRequestConfig): Promise; 188 | 189 | download, D = HttpDownloadTask>(url: string, config?: HttpRequestConfig): Promise; 190 | 191 | middleware, D = HttpTask>(config: HttpRequestConfig): Promise; 192 | } 193 | 194 | declare class HttpRequest extends HttpRequestAbstract { 195 | } 196 | 197 | export default HttpRequest; 198 | -------------------------------------------------------------------------------- /src/lib/utils/clone.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var clone = (function() { 3 | 'use strict'; 4 | 5 | function _instanceof(obj, type) { 6 | return type != null && obj instanceof type; 7 | } 8 | 9 | var nativeMap; 10 | try { 11 | nativeMap = Map; 12 | } catch(_) { 13 | // maybe a reference error because no `Map`. Give it a dummy value that no 14 | // value will ever be an instanceof. 15 | nativeMap = function() {}; 16 | } 17 | 18 | var nativeSet; 19 | try { 20 | nativeSet = Set; 21 | } catch(_) { 22 | nativeSet = function() {}; 23 | } 24 | 25 | var nativePromise; 26 | try { 27 | nativePromise = Promise; 28 | } catch(_) { 29 | nativePromise = function() {}; 30 | } 31 | 32 | /** 33 | * Clones (copies) an Object using deep copying. 34 | * 35 | * This function supports circular references by default, but if you are certain 36 | * there are no circular references in your object, you can save some CPU time 37 | * by calling clone(obj, false). 38 | * 39 | * Caution: if `circular` is false and `parent` contains circular references, 40 | * your program may enter an infinite loop and crash. 41 | * 42 | * @param `parent` - the object to be cloned 43 | * @param `circular` - set to true if the object to be cloned may contain 44 | * circular references. (optional - true by default) 45 | * @param `depth` - set to a number if the object is only to be cloned to 46 | * a particular depth. (optional - defaults to Infinity) 47 | * @param `prototype` - sets the prototype to be used when cloning an object. 48 | * (optional - defaults to parent prototype). 49 | * @param `includeNonEnumerable` - set to true if the non-enumerable properties 50 | * should be cloned as well. Non-enumerable properties on the prototype 51 | * chain will be ignored. (optional - false by default) 52 | */ 53 | function clone(parent, circular, depth, prototype, includeNonEnumerable) { 54 | if (typeof circular === 'object') { 55 | depth = circular.depth; 56 | prototype = circular.prototype; 57 | includeNonEnumerable = circular.includeNonEnumerable; 58 | circular = circular.circular; 59 | } 60 | // maintain two arrays for circular references, where corresponding parents 61 | // and children have the same index 62 | var allParents = []; 63 | var allChildren = []; 64 | 65 | var useBuffer = typeof Buffer != 'undefined'; 66 | 67 | if (typeof circular == 'undefined') 68 | circular = true; 69 | 70 | if (typeof depth == 'undefined') 71 | depth = Infinity; 72 | 73 | // recurse this function so we don't reset allParents and allChildren 74 | function _clone(parent, depth) { 75 | // cloning null always returns null 76 | if (parent === null) 77 | return null; 78 | 79 | if (depth === 0) 80 | return parent; 81 | 82 | var child; 83 | var proto; 84 | if (typeof parent != 'object') { 85 | return parent; 86 | } 87 | 88 | if (_instanceof(parent, nativeMap)) { 89 | child = new nativeMap(); 90 | } else if (_instanceof(parent, nativeSet)) { 91 | child = new nativeSet(); 92 | } else if (_instanceof(parent, nativePromise)) { 93 | child = new nativePromise(function (resolve, reject) { 94 | parent.then(function(value) { 95 | resolve(_clone(value, depth - 1)); 96 | }, function(err) { 97 | reject(_clone(err, depth - 1)); 98 | }); 99 | }); 100 | } else if (clone.__isArray(parent)) { 101 | child = []; 102 | } else if (clone.__isRegExp(parent)) { 103 | child = new RegExp(parent.source, __getRegExpFlags(parent)); 104 | if (parent.lastIndex) child.lastIndex = parent.lastIndex; 105 | } else if (clone.__isDate(parent)) { 106 | child = new Date(parent.getTime()); 107 | } else if (useBuffer && Buffer.isBuffer(parent)) { 108 | if (Buffer.from) { 109 | // Node.js >= 5.10.0 110 | child = Buffer.from(parent); 111 | } else { 112 | // Older Node.js versions 113 | child = new Buffer(parent.length); 114 | parent.copy(child); 115 | } 116 | return child; 117 | } else if (_instanceof(parent, Error)) { 118 | child = Object.create(parent); 119 | } else { 120 | if (typeof prototype == 'undefined') { 121 | proto = Object.getPrototypeOf(parent); 122 | child = Object.create(proto); 123 | } 124 | else { 125 | child = Object.create(prototype); 126 | proto = prototype; 127 | } 128 | } 129 | 130 | if (circular) { 131 | var index = allParents.indexOf(parent); 132 | 133 | if (index != -1) { 134 | return allChildren[index]; 135 | } 136 | allParents.push(parent); 137 | allChildren.push(child); 138 | } 139 | 140 | if (_instanceof(parent, nativeMap)) { 141 | parent.forEach(function(value, key) { 142 | var keyChild = _clone(key, depth - 1); 143 | var valueChild = _clone(value, depth - 1); 144 | child.set(keyChild, valueChild); 145 | }); 146 | } 147 | if (_instanceof(parent, nativeSet)) { 148 | parent.forEach(function(value) { 149 | var entryChild = _clone(value, depth - 1); 150 | child.add(entryChild); 151 | }); 152 | } 153 | 154 | for (var i in parent) { 155 | var attrs = Object.getOwnPropertyDescriptor(parent, i); 156 | if (attrs) { 157 | child[i] = _clone(parent[i], depth - 1); 158 | } 159 | 160 | try { 161 | var objProperty = Object.getOwnPropertyDescriptor(parent, i); 162 | if (objProperty.set === 'undefined') { 163 | // no setter defined. Skip cloning this property 164 | continue; 165 | } 166 | child[i] = _clone(parent[i], depth - 1); 167 | } catch(e){ 168 | if (e instanceof TypeError) { 169 | // when in strict mode, TypeError will be thrown if child[i] property only has a getter 170 | // we can't do anything about this, other than inform the user that this property cannot be set. 171 | continue 172 | } else if (e instanceof ReferenceError) { 173 | //this may happen in non strict mode 174 | continue 175 | } 176 | } 177 | 178 | } 179 | 180 | if (Object.getOwnPropertySymbols) { 181 | var symbols = Object.getOwnPropertySymbols(parent); 182 | for (var i = 0; i < symbols.length; i++) { 183 | // Don't need to worry about cloning a symbol because it is a primitive, 184 | // like a number or string. 185 | var symbol = symbols[i]; 186 | var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); 187 | if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { 188 | continue; 189 | } 190 | child[symbol] = _clone(parent[symbol], depth - 1); 191 | Object.defineProperty(child, symbol, descriptor); 192 | } 193 | } 194 | 195 | if (includeNonEnumerable) { 196 | var allPropertyNames = Object.getOwnPropertyNames(parent); 197 | for (var i = 0; i < allPropertyNames.length; i++) { 198 | var propertyName = allPropertyNames[i]; 199 | var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); 200 | if (descriptor && descriptor.enumerable) { 201 | continue; 202 | } 203 | child[propertyName] = _clone(parent[propertyName], depth - 1); 204 | Object.defineProperty(child, propertyName, descriptor); 205 | } 206 | } 207 | 208 | return child; 209 | } 210 | 211 | return _clone(parent, depth); 212 | } 213 | 214 | /** 215 | * Simple flat clone using prototype, accepts only objects, usefull for property 216 | * override on FLAT configuration object (no nested props). 217 | * 218 | * USE WITH CAUTION! This may not behave as you wish if you do not know how this 219 | * works. 220 | */ 221 | clone.clonePrototype = function clonePrototype(parent) { 222 | if (parent === null) 223 | return null; 224 | 225 | var c = function () {}; 226 | c.prototype = parent; 227 | return new c(); 228 | }; 229 | 230 | // private utility functions 231 | 232 | function __objToStr(o) { 233 | return Object.prototype.toString.call(o); 234 | } 235 | clone.__objToStr = __objToStr; 236 | 237 | function __isDate(o) { 238 | return typeof o === 'object' && __objToStr(o) === '[object Date]'; 239 | } 240 | clone.__isDate = __isDate; 241 | 242 | function __isArray(o) { 243 | return typeof o === 'object' && __objToStr(o) === '[object Array]'; 244 | } 245 | clone.__isArray = __isArray; 246 | 247 | function __isRegExp(o) { 248 | return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; 249 | } 250 | clone.__isRegExp = __isRegExp; 251 | 252 | function __getRegExpFlags(re) { 253 | var flags = ''; 254 | if (re.global) flags += 'g'; 255 | if (re.ignoreCase) flags += 'i'; 256 | if (re.multiline) flags += 'm'; 257 | return flags; 258 | } 259 | clone.__getRegExpFlags = __getRegExpFlags; 260 | 261 | return clone; 262 | })(); 263 | 264 | export default clone 265 | -------------------------------------------------------------------------------- /DCloud/luch-request/utils/clone.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var clone = (function() { 3 | 'use strict'; 4 | 5 | function _instanceof(obj, type) { 6 | return type != null && obj instanceof type; 7 | } 8 | 9 | var nativeMap; 10 | try { 11 | nativeMap = Map; 12 | } catch(_) { 13 | // maybe a reference error because no `Map`. Give it a dummy value that no 14 | // value will ever be an instanceof. 15 | nativeMap = function() {}; 16 | } 17 | 18 | var nativeSet; 19 | try { 20 | nativeSet = Set; 21 | } catch(_) { 22 | nativeSet = function() {}; 23 | } 24 | 25 | var nativePromise; 26 | try { 27 | nativePromise = Promise; 28 | } catch(_) { 29 | nativePromise = function() {}; 30 | } 31 | 32 | /** 33 | * Clones (copies) an Object using deep copying. 34 | * 35 | * This function supports circular references by default, but if you are certain 36 | * there are no circular references in your object, you can save some CPU time 37 | * by calling clone(obj, false). 38 | * 39 | * Caution: if `circular` is false and `parent` contains circular references, 40 | * your program may enter an infinite loop and crash. 41 | * 42 | * @param `parent` - the object to be cloned 43 | * @param `circular` - set to true if the object to be cloned may contain 44 | * circular references. (optional - true by default) 45 | * @param `depth` - set to a number if the object is only to be cloned to 46 | * a particular depth. (optional - defaults to Infinity) 47 | * @param `prototype` - sets the prototype to be used when cloning an object. 48 | * (optional - defaults to parent prototype). 49 | * @param `includeNonEnumerable` - set to true if the non-enumerable properties 50 | * should be cloned as well. Non-enumerable properties on the prototype 51 | * chain will be ignored. (optional - false by default) 52 | */ 53 | function clone(parent, circular, depth, prototype, includeNonEnumerable) { 54 | if (typeof circular === 'object') { 55 | depth = circular.depth; 56 | prototype = circular.prototype; 57 | includeNonEnumerable = circular.includeNonEnumerable; 58 | circular = circular.circular; 59 | } 60 | // maintain two arrays for circular references, where corresponding parents 61 | // and children have the same index 62 | var allParents = []; 63 | var allChildren = []; 64 | 65 | var useBuffer = typeof Buffer != 'undefined'; 66 | 67 | if (typeof circular == 'undefined') 68 | circular = true; 69 | 70 | if (typeof depth == 'undefined') 71 | depth = Infinity; 72 | 73 | // recurse this function so we don't reset allParents and allChildren 74 | function _clone(parent, depth) { 75 | // cloning null always returns null 76 | if (parent === null) 77 | return null; 78 | 79 | if (depth === 0) 80 | return parent; 81 | 82 | var child; 83 | var proto; 84 | if (typeof parent != 'object') { 85 | return parent; 86 | } 87 | 88 | if (_instanceof(parent, nativeMap)) { 89 | child = new nativeMap(); 90 | } else if (_instanceof(parent, nativeSet)) { 91 | child = new nativeSet(); 92 | } else if (_instanceof(parent, nativePromise)) { 93 | child = new nativePromise(function (resolve, reject) { 94 | parent.then(function(value) { 95 | resolve(_clone(value, depth - 1)); 96 | }, function(err) { 97 | reject(_clone(err, depth - 1)); 98 | }); 99 | }); 100 | } else if (clone.__isArray(parent)) { 101 | child = []; 102 | } else if (clone.__isRegExp(parent)) { 103 | child = new RegExp(parent.source, __getRegExpFlags(parent)); 104 | if (parent.lastIndex) child.lastIndex = parent.lastIndex; 105 | } else if (clone.__isDate(parent)) { 106 | child = new Date(parent.getTime()); 107 | } else if (useBuffer && Buffer.isBuffer(parent)) { 108 | if (Buffer.from) { 109 | // Node.js >= 5.10.0 110 | child = Buffer.from(parent); 111 | } else { 112 | // Older Node.js versions 113 | child = new Buffer(parent.length); 114 | parent.copy(child); 115 | } 116 | return child; 117 | } else if (_instanceof(parent, Error)) { 118 | child = Object.create(parent); 119 | } else { 120 | if (typeof prototype == 'undefined') { 121 | proto = Object.getPrototypeOf(parent); 122 | child = Object.create(proto); 123 | } 124 | else { 125 | child = Object.create(prototype); 126 | proto = prototype; 127 | } 128 | } 129 | 130 | if (circular) { 131 | var index = allParents.indexOf(parent); 132 | 133 | if (index != -1) { 134 | return allChildren[index]; 135 | } 136 | allParents.push(parent); 137 | allChildren.push(child); 138 | } 139 | 140 | if (_instanceof(parent, nativeMap)) { 141 | parent.forEach(function(value, key) { 142 | var keyChild = _clone(key, depth - 1); 143 | var valueChild = _clone(value, depth - 1); 144 | child.set(keyChild, valueChild); 145 | }); 146 | } 147 | if (_instanceof(parent, nativeSet)) { 148 | parent.forEach(function(value) { 149 | var entryChild = _clone(value, depth - 1); 150 | child.add(entryChild); 151 | }); 152 | } 153 | 154 | for (var i in parent) { 155 | var attrs = Object.getOwnPropertyDescriptor(parent, i); 156 | if (attrs) { 157 | child[i] = _clone(parent[i], depth - 1); 158 | } 159 | 160 | try { 161 | var objProperty = Object.getOwnPropertyDescriptor(parent, i); 162 | if (objProperty.set === 'undefined') { 163 | // no setter defined. Skip cloning this property 164 | continue; 165 | } 166 | child[i] = _clone(parent[i], depth - 1); 167 | } catch(e){ 168 | if (e instanceof TypeError) { 169 | // when in strict mode, TypeError will be thrown if child[i] property only has a getter 170 | // we can't do anything about this, other than inform the user that this property cannot be set. 171 | continue 172 | } else if (e instanceof ReferenceError) { 173 | //this may happen in non strict mode 174 | continue 175 | } 176 | } 177 | 178 | } 179 | 180 | if (Object.getOwnPropertySymbols) { 181 | var symbols = Object.getOwnPropertySymbols(parent); 182 | for (var i = 0; i < symbols.length; i++) { 183 | // Don't need to worry about cloning a symbol because it is a primitive, 184 | // like a number or string. 185 | var symbol = symbols[i]; 186 | var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); 187 | if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { 188 | continue; 189 | } 190 | child[symbol] = _clone(parent[symbol], depth - 1); 191 | Object.defineProperty(child, symbol, descriptor); 192 | } 193 | } 194 | 195 | if (includeNonEnumerable) { 196 | var allPropertyNames = Object.getOwnPropertyNames(parent); 197 | for (var i = 0; i < allPropertyNames.length; i++) { 198 | var propertyName = allPropertyNames[i]; 199 | var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); 200 | if (descriptor && descriptor.enumerable) { 201 | continue; 202 | } 203 | child[propertyName] = _clone(parent[propertyName], depth - 1); 204 | Object.defineProperty(child, propertyName, descriptor); 205 | } 206 | } 207 | 208 | return child; 209 | } 210 | 211 | return _clone(parent, depth); 212 | } 213 | 214 | /** 215 | * Simple flat clone using prototype, accepts only objects, usefull for property 216 | * override on FLAT configuration object (no nested props). 217 | * 218 | * USE WITH CAUTION! This may not behave as you wish if you do not know how this 219 | * works. 220 | */ 221 | clone.clonePrototype = function clonePrototype(parent) { 222 | if (parent === null) 223 | return null; 224 | 225 | var c = function () {}; 226 | c.prototype = parent; 227 | return new c(); 228 | }; 229 | 230 | // private utility functions 231 | 232 | function __objToStr(o) { 233 | return Object.prototype.toString.call(o); 234 | } 235 | clone.__objToStr = __objToStr; 236 | 237 | function __isDate(o) { 238 | return typeof o === 'object' && __objToStr(o) === '[object Date]'; 239 | } 240 | clone.__isDate = __isDate; 241 | 242 | function __isArray(o) { 243 | return typeof o === 'object' && __objToStr(o) === '[object Array]'; 244 | } 245 | clone.__isArray = __isArray; 246 | 247 | function __isRegExp(o) { 248 | return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; 249 | } 250 | clone.__isRegExp = __isRegExp; 251 | 252 | function __getRegExpFlags(re) { 253 | var flags = ''; 254 | if (re.global) flags += 'g'; 255 | if (re.ignoreCase) flags += 'i'; 256 | if (re.multiline) flags += 'm'; 257 | return flags; 258 | } 259 | clone.__getRegExpFlags = __getRegExpFlags; 260 | 261 | return clone; 262 | })(); 263 | 264 | export default clone 265 | --------------------------------------------------------------------------------