mirror of
https://github.com/WeBankFinTech/fes.js.git
synced 2025-05-20 21:19:52 +08:00
fix: request plugin
This commit is contained in:
parent
2ee1b659a0
commit
297b48503d
@ -6,7 +6,7 @@ import { join } from "path";
|
||||
|
||||
const headPkgs = [
|
||||
"fes-runtime",
|
||||
"fes-core",
|
||||
"fes-compiler",
|
||||
"fes",
|
||||
"fes-preset-built-in",
|
||||
"fes-plugin-request",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@webank/fes-core",
|
||||
"name": "@webank/fes-compiler",
|
||||
"version": "2.0.0",
|
||||
"description": "@webank/fes-core",
|
||||
"description": "@webank/fes-compiler",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
@ -61,7 +61,7 @@ export default class Logger {
|
||||
delete this.profilers[id];
|
||||
process.stderr.write(`${this.PROFILE} `);
|
||||
msg = `${this.PROFILE} ${chalk.cyan(
|
||||
`└ ${namespace}`,
|
||||
`└ ${namespace}`
|
||||
)} Completed in ${this.formatTiming(time - timeEnd)}`;
|
||||
console.log(msg);
|
||||
} else {
|
@ -14,7 +14,9 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"axios": "0.21.1",
|
||||
"@webank/fes": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.21.1"
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ export default (api) => {
|
||||
api.addRuntimePluginKey(() => 'request');
|
||||
// 配置
|
||||
api.describe({
|
||||
key: 'request',
|
||||
config: {
|
||||
schema(joi) {
|
||||
return joi.object({
|
||||
@ -15,7 +16,7 @@ export default (api) => {
|
||||
});
|
||||
},
|
||||
default: {
|
||||
dataField: 'result'
|
||||
dataField: ''
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -29,7 +30,7 @@ export default (api) => {
|
||||
api.writeTmpFile({
|
||||
path: absoluteFilePath,
|
||||
content: requestTemplate
|
||||
.replace('REPLACE_DATA_FIELD', dataField)
|
||||
.replace('REPLACE_DATA_FIELD', JSON.stringify(dataField))
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -44,7 +44,7 @@ const CACHE_TYPE = {
|
||||
local: 'localStorage'
|
||||
};
|
||||
|
||||
const CACHE_DATA = new Map();
|
||||
const CACHE_DATA_MAP = new Map();
|
||||
|
||||
function genInnerKey(key, cacheType) {
|
||||
if (cacheType !== CACHE_TYPE.ram) {
|
||||
@ -53,17 +53,18 @@ function genInnerKey(key, cacheType) {
|
||||
return key;
|
||||
}
|
||||
|
||||
function canCache(requestData) {
|
||||
return isObject(requestData) || isString(requestData) || isURLSearchParams(requestData);
|
||||
function canCache(data) {
|
||||
return !data || isObject(data) || isString(data) || Array.isArray(data) || isURLSearchParams(data);
|
||||
}
|
||||
|
||||
function setCacheData({
|
||||
key,
|
||||
cacheType,
|
||||
cacheType = 'ram',
|
||||
data,
|
||||
cacheTime = 1000 * 60 * 3
|
||||
}) {
|
||||
const _key = genInnerKey(key, cacheType);
|
||||
|
||||
const currentCacheData = {
|
||||
cacheType,
|
||||
data,
|
||||
@ -83,7 +84,7 @@ function setCacheData({
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CACHE_DATA.set(_key, currentCacheData);
|
||||
CACHE_DATA_MAP.set(_key, currentCacheData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,33 +112,36 @@ function getCacheData({ key, cacheType = 'ram' }) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
const currentCacheData = CACHE_DATA.get(_key);
|
||||
const currentCacheData = CACHE_DATA_MAP.get(_key);
|
||||
if (currentCacheData && !isExpire(currentCacheData)) {
|
||||
return currentCacheData.data;
|
||||
}
|
||||
CACHE_DATA.delete(_key);
|
||||
CACHE_DATA_MAP.delete(_key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default (ctx, next) => {
|
||||
export default async (ctx, next) => {
|
||||
const { config } = ctx;
|
||||
if (config.cache) {
|
||||
const data = checkHttpRequestHasBody(config.method) ? config.data : config.params;
|
||||
if (canCache(data)) {
|
||||
const cacheData = getCacheData({ key: ctx.key, cacheType: config.cache.cacheType });
|
||||
if (cacheData) {
|
||||
ctx.response = {
|
||||
data: getCacheData({ key: ctx.key, cacheType: config.cache.cacheType })
|
||||
data: cacheData
|
||||
};
|
||||
return;
|
||||
}
|
||||
}
|
||||
next();
|
||||
await next();
|
||||
|
||||
if (config.cache) {
|
||||
setCacheData({
|
||||
key: ctx.key,
|
||||
data: ctx.response.data,
|
||||
...config.cache
|
||||
});
|
||||
const requestdata = checkHttpRequestHasBody(config.method) ? config.data : config.params;
|
||||
if (ctx.response && canCache(requestdata) && canCache(ctx.response.data)) {
|
||||
setCacheData({
|
||||
key: ctx.key,
|
||||
data: ctx.response.data,
|
||||
...config.cache
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -5,11 +5,11 @@ import { isURLSearchParams } from './helpers';
|
||||
* 一个请求同时包含 data | params 参数的设计本身不合理
|
||||
* 不对这种情况进行兼容
|
||||
*/
|
||||
export default function genRequestKey(ctx, next) {
|
||||
export default async function genRequestKey(ctx, next) {
|
||||
const { url, data, method } = ctx.config;
|
||||
if (isURLSearchParams(data)) {
|
||||
ctx.key = `${url}${data.toString()}${method}`;
|
||||
}
|
||||
ctx.key = `${url}${JSON.stringify(data)}${method}`;
|
||||
next();
|
||||
await next();
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { checkHttpRequestHasBody, trimObj } from 'helpers';
|
||||
import { checkHttpRequestHasBody, trimObj } from './helpers';
|
||||
|
||||
export default (ctx, next) => {
|
||||
export default async (ctx, next) => {
|
||||
const config = ctx.config;
|
||||
if (checkHttpRequestHasBody(config.method)) {
|
||||
config.data = trimObj(config.data);
|
||||
} else {
|
||||
config.params = trimObj(config.params);
|
||||
}
|
||||
next();
|
||||
await next();
|
||||
};
|
||||
|
@ -1,17 +1,17 @@
|
||||
const requestQueue = new Map();
|
||||
const requestMap = new Map();
|
||||
|
||||
export default (ctx, next) => {
|
||||
export default async (ctx, next) => {
|
||||
const key = ctx.key;
|
||||
if (requestQueue.get(key)) {
|
||||
if (requestMap.get(key)) {
|
||||
ctx.error = {
|
||||
type: 'REPEAT',
|
||||
msg: '重复请求'
|
||||
};
|
||||
return;
|
||||
}
|
||||
requestQueue.set(key, true);
|
||||
requestMap.set(key, true);
|
||||
|
||||
next();
|
||||
await next();
|
||||
|
||||
requestQueue.delete(key);
|
||||
requestMap.delete(key);
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import axios from 'axios';
|
||||
import { ApplyPluginsType, plugin } from '@webank/fes';
|
||||
import scheduler from 'scheduler';
|
||||
import scheduler from './scheduler';
|
||||
import {
|
||||
checkHttpRequestHasBody,
|
||||
isFunction
|
||||
@ -10,6 +10,7 @@ import setDataField from './setDataField';
|
||||
import paramsProcess from './paramsProcess';
|
||||
import genRequestKey from './genRequestKey';
|
||||
import preventRepeatReq from './preventRepeatReq';
|
||||
import throttle from './throttle';
|
||||
import cacheControl from './cacheControl';
|
||||
import resDataAdaptor from './resDataAdaptor';
|
||||
import resErrorProcess from './resErrorProcess';
|
||||
@ -32,22 +33,21 @@ function addResponseInterceptors(instance, interceptors) {
|
||||
addInterceptors(instance, interceptors, 'response');
|
||||
}
|
||||
|
||||
function axiosMiddleware(context, next) {
|
||||
context.instance.request(context.config).then((response) => {
|
||||
context.response = response;
|
||||
}).catch((error) => {
|
||||
async function axiosMiddleware(context, next) {
|
||||
try {
|
||||
context.response = await context.instance.request(context.config);
|
||||
} catch (error) {
|
||||
context.error = error;
|
||||
}).finally(() => {
|
||||
next();
|
||||
});
|
||||
}
|
||||
await next();
|
||||
}
|
||||
|
||||
function getRequestInstance() {
|
||||
const {
|
||||
responseDataAdaptor,
|
||||
errorConfig,
|
||||
requestInterceptors,
|
||||
responseInterceptors,
|
||||
requestInterceptors = [],
|
||||
responseInterceptors = [],
|
||||
errorHandler,
|
||||
...otherConfigs
|
||||
} = plugin.applyPlugins({
|
||||
@ -65,14 +65,15 @@ function getRequestInstance() {
|
||||
addRequestInterceptors(instance, requestInterceptors);
|
||||
addResponseInterceptors(instance, responseInterceptors);
|
||||
|
||||
scheduler.use(paramsProcess);
|
||||
scheduler.use(genRequestKey);
|
||||
scheduler.use(preventRepeatReq);
|
||||
scheduler.use(cacheControl);
|
||||
scheduler.use(axiosMiddleware);
|
||||
scheduler.use(resDataAdaptor);
|
||||
scheduler.use(resErrorProcess);
|
||||
scheduler.use(setDataField);
|
||||
scheduler.use(paramsProcess)
|
||||
.use(genRequestKey)
|
||||
.use(preventRepeatReq)
|
||||
.use(throttle)
|
||||
.use(cacheControl)
|
||||
.use(axiosMiddleware)
|
||||
.use(resDataAdaptor)
|
||||
.use(resErrorProcess)
|
||||
.use(setDataField);
|
||||
|
||||
return {
|
||||
context: {
|
||||
@ -96,6 +97,7 @@ function userConfigHandler(url, data, options = {}) {
|
||||
} else {
|
||||
options.params = data;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
let currentRequestInstance = null;
|
||||
@ -117,10 +119,10 @@ export const request = (url, data, options = {}) => {
|
||||
const userConfig = userConfigHandler(url, data, options);
|
||||
const context = createContext(userConfig);
|
||||
|
||||
return currentRequestInstance.request(context).then((ctx) => {
|
||||
if (!ctx.error) {
|
||||
return ctx.config.useResonse ? ctx.response : ctx.response.data;
|
||||
return currentRequestInstance.request(context).then(() => {
|
||||
if (!context.error) {
|
||||
return context.config.useResonse ? context.response : context.response.data;
|
||||
}
|
||||
return Promise.reject(ctx.error);
|
||||
return Promise.reject(context.error);
|
||||
});
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { isFunction, isObject, isString } from './helpers';
|
||||
|
||||
export default ({ response, responseDataAdaptor }, next) => {
|
||||
export default async ({ response, responseDataAdaptor }, next) => {
|
||||
if (isFunction(responseDataAdaptor) && (isObject(response.data) || isString(response.data))) {
|
||||
response.data = responseDataAdaptor(response.data);
|
||||
}
|
||||
next();
|
||||
await next();
|
||||
};
|
||||
|
@ -1,29 +1,19 @@
|
||||
import { isObject, isFunction } from 'helpers';
|
||||
import { isObject } from './helpers';
|
||||
|
||||
function resErrorProcess(error, customerErrorHandler) {
|
||||
if (isFunction(error)) {
|
||||
error();
|
||||
} else {
|
||||
customerErrorHandler && customerErrorHandler(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default ({
|
||||
export default async ({
|
||||
error,
|
||||
errorConfig,
|
||||
errorHandler,
|
||||
errorHandler = {},
|
||||
response
|
||||
}, next) => {
|
||||
const _errorConfig = Object.assign({
|
||||
403: '用户得到授权,但访问是禁止的'
|
||||
}, errorConfig);
|
||||
|
||||
if (isObject(response.data) && response.data.code !== '0') {
|
||||
resErrorProcess(_errorConfig[response.data.code] || response.data.msg || response.data.errorMessage || response.data.errorMsg || '服务异常', errorHandler);
|
||||
} else if (error && error.response && _errorConfig[error.response.status]) {
|
||||
resErrorProcess(_errorConfig[error.response.status], errorHandler);
|
||||
if (response && isObject(response.data) && response.data.code !== '0') {
|
||||
errorHandler[response.data.code] && errorHandler[response.data.code](response);
|
||||
} else if (error) {
|
||||
if (error.type) {
|
||||
errorHandler[error.type] && errorHandler[error.type](error);
|
||||
} else if (error.response) {
|
||||
errorHandler[error.response.status] && errorHandler[error.response.status](error);
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
await next();
|
||||
};
|
||||
|
@ -30,4 +30,4 @@ class Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
export default Scheduler();
|
||||
export default new Scheduler();
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { isObject } from './helpers';
|
||||
|
||||
export default (ctx, next) => {
|
||||
export default async (ctx, next) => {
|
||||
const { dataField, response } = ctx;
|
||||
if (isObject(response.data) && dataField) {
|
||||
if (response && isObject(response.data) && dataField) {
|
||||
ctx.response._rawData = response.data;
|
||||
ctx.response.data = response.data[dataField];
|
||||
}
|
||||
next();
|
||||
await next();
|
||||
};
|
||||
|
16
packages/fes-plugin-request/src/template/throttle.js
Normal file
16
packages/fes-plugin-request/src/template/throttle.js
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
const throttleMap = new Map();
|
||||
|
||||
export default async (ctx, next) => {
|
||||
if (ctx.config.throttle) {
|
||||
if (throttleMap.get(ctx.key) >= Date.now()) {
|
||||
ctx.error = {
|
||||
type: 'FREQUENTLY',
|
||||
msg: '请求过于频繁'
|
||||
};
|
||||
return;
|
||||
}
|
||||
}
|
||||
await next();
|
||||
throttleMap.set(ctx.key, Date.now() + ctx.config.throttle);
|
||||
};
|
@ -30,7 +30,7 @@
|
||||
"@vue/babel-plugin-jsx": "^1.0.0-rc.5",
|
||||
"@vue/compiler-sfc": "^3.0.4",
|
||||
"@vue/preload-webpack-plugin": "1.1.2",
|
||||
"@webank/fes-core": "^2.0.0",
|
||||
"@webank/fes-compiler": "^2.0.0",
|
||||
"cliui": "6.0.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"html-webpack-tags-plugin": "2.0.17",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { relative } from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import { Logger } from '@webank/fes-core';
|
||||
import { Logger } from '@webank/fes-compiler';
|
||||
import {
|
||||
cleanTmpPathExceptCache,
|
||||
getBundleAndConfigs,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { join } from 'path';
|
||||
import { chokidar, winPath, lodash } from '@umijs/utils';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { isPluginOrPreset, PluginType } from '@webank/fes-core';
|
||||
import { isPluginOrPreset, PluginType } from '@webank/fes-compiler';
|
||||
|
||||
function getPlugins(opts) {
|
||||
return Object.keys({
|
||||
|
@ -7,6 +7,9 @@ export default {
|
||||
// __VUE_OPTIONS_API__: true,
|
||||
// __VUE_PROD_DEVTOOLS__: false
|
||||
},
|
||||
request: {
|
||||
dataField: 'fileTemplateList'
|
||||
},
|
||||
html: {
|
||||
options: {
|
||||
title: '海贼王'
|
||||
|
@ -35,6 +35,7 @@
|
||||
"dependencies": {
|
||||
"vue": "^3.0.4",
|
||||
"@webank/fes": "^2.0.0",
|
||||
"@webank/fes-plugin-icon": "^1.0.0"
|
||||
"@webank/fes-plugin-icon": "^1.0.0",
|
||||
"@webank/fes-plugin-request": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
export const request = {
|
||||
errorConfig: {
|
||||
404() {
|
||||
console.log('to 404 page');
|
||||
}
|
||||
}
|
||||
};
|
@ -12,8 +12,7 @@
|
||||
</config>
|
||||
<script>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRouter } from '@webank/fes';
|
||||
// import Icon from '@/components/Icon';
|
||||
import { useRouter, request } from '@webank/fes';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
@ -23,14 +22,44 @@ export default {
|
||||
onMounted(() => {
|
||||
console.log(router);
|
||||
console.log('mounted1!!');
|
||||
// router.push('/onepiece');
|
||||
});
|
||||
onMounted(() => {
|
||||
console.log('mounted2!!');
|
||||
});
|
||||
const clickIcon = () => {
|
||||
console.log('click Icon');
|
||||
};
|
||||
request('api', {}, {
|
||||
cache: {
|
||||
cacheType: 'ram',
|
||||
cacheTime: 5 * 1000
|
||||
}
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
setTimeout(() => {
|
||||
request('api', {}, {
|
||||
cache: {
|
||||
cacheType: 'ram',
|
||||
cacheTime: 5 * 1000
|
||||
}
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 200);
|
||||
setTimeout(() => {
|
||||
request('api', {}, {
|
||||
cache: {
|
||||
cacheType: 'ram',
|
||||
cacheTime: 5 * 1000
|
||||
}
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 6000);
|
||||
return {
|
||||
fes,
|
||||
rotate,
|
||||
|
@ -31,7 +31,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@webank/fes-preset-built-in": "^2.0.0",
|
||||
"@webank/fes-core": "^2.0.0",
|
||||
"@webank/fes-compiler": "^2.0.0",
|
||||
"@webank/fes-runtime": "^2.0.0",
|
||||
"@umijs/utils": "3.3.3",
|
||||
"resolve-cwd": "^3.0.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { dirname } from 'path';
|
||||
import { Service as CoreService } from '@webank/fes-core';
|
||||
import { Service as CoreService } from '@webank/fes-compiler';
|
||||
|
||||
class Service extends CoreService {
|
||||
constructor(opts) {
|
||||
|
20
yarn.lock
20
yarn.lock
@ -4215,10 +4215,10 @@ aws4@^1.8.0:
|
||||
resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
axios@^0.20.0:
|
||||
version "0.20.0"
|
||||
resolved "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
|
||||
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
|
||||
axios@0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
@ -7300,11 +7300,16 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^2.3.6"
|
||||
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.10.0:
|
||||
follow-redirects@^1.0.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
||||
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
for-in@^0.1.3:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
|
||||
@ -13937,11 +13942,6 @@ thenify-all@^1.0.0:
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
throttle-debounce@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2"
|
||||
integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==
|
||||
|
||||
through2-filter@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
|
||||
|
Loading…
x
Reference in New Issue
Block a user