From 74c14736b1b255951581790b6091e839982a03fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Fri, 29 Mar 2024 22:36:47 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=E6=8B=A6=E6=88=AA=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=85=81=E8=AE=B8=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E5=88=B0=E5=A4=9A=E4=B8=AA=20=E2=80=98=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E7=AC=A6=E2=80=99=20=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E6=8B=A6=E6=88=AA=E9=85=8D=E7=BD=AE=E4=BA=86=EF=BC=8C=E5=8F=AA?= =?UTF-8?q?=E8=A6=81=E5=9F=9F=E5=90=8D=E7=AC=A6=E5=90=88=20=E2=80=98?= =?UTF-8?q?=E5=9F=9F=E5=90=8D=E5=8C=B9=E9=85=8D=E7=AC=A6=E2=80=99=E3=80=82?= =?UTF-8?q?=20(#286)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/merge.js | 2 +- packages/gui/src/view/components/settings.vue | 2 +- packages/gui/src/view/pages/server.vue | 2 - .../src/lib/interceptor/impl/req/OPTIONS.js | 4 +- .../src/lib/interceptor/impl/req/abort.js | 22 +++++-- .../src/lib/interceptor/impl/req/cacheReq.js | 10 ++- .../src/lib/interceptor/impl/req/proxy.js | 38 +++++++---- .../src/lib/interceptor/impl/req/redirect.js | 29 +++++++-- .../src/lib/interceptor/impl/req/sni.js | 18 ++++-- .../src/lib/interceptor/impl/req/success.js | 22 +++++-- .../src/lib/interceptor/impl/res/cacheRes.js | 8 ++- .../src/lib/interceptor/impl/res/script.js | 11 +++- .../src/lib/proxy/middleware/overwall.js | 2 +- packages/mitmproxy/src/options.js | 49 +++++++++++--- packages/mitmproxy/src/utils/util.match.js | 64 +++++++++++-------- 15 files changed, 197 insertions(+), 86 deletions(-) diff --git a/packages/core/src/merge.js b/packages/core/src/merge.js index 64b760b20e..3c7888d7b8 100644 --- a/packages/core/src/merge.js +++ b/packages/core/src/merge.js @@ -65,7 +65,7 @@ function doDiff (oldObj, newObj) { function deleteNullItems (target) { lodash.forEach(target, (item, key) => { - if (item == null) { + if (item == null || item === '[delete]') { delete target[key] } if (lodash.isObject(item)) { diff --git a/packages/gui/src/view/components/settings.vue b/packages/gui/src/view/components/settings.vue index f4ac91aadd..54a47b6727 100644 --- a/packages/gui/src/view/components/settings.vue +++ b/packages/gui/src/view/components/settings.vue @@ -17,7 +17,7 @@ :style="{ height: '100%' }" > - +
diff --git a/packages/gui/src/view/pages/server.vue b/packages/gui/src/view/pages/server.vue index 229e56e7de..480a7274a3 100644 --- a/packages/gui/src/view/pages/server.vue +++ b/packages/gui/src/view/pages/server.vue @@ -138,7 +138,6 @@ -
@@ -201,7 +200,6 @@ -
diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/OPTIONS.js b/packages/mitmproxy/src/lib/interceptor/impl/req/OPTIONS.js index 09e4a83338..977532fe97 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/OPTIONS.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/OPTIONS.js @@ -13,6 +13,8 @@ function readConfig (config, defaultConfig) { } module.exports = { + name: 'options', + priority: 1, requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log } = context @@ -27,7 +29,7 @@ module.exports = { const headers = { // 允许跨域 - 'Dev-Sidecar-Interceptor': 'options', + 'DS-Interceptor': 'options', 'Access-Control-Allow-Origin': rOptions.headers.origin, 'Access-Control-Allow-Headers': allowHeaders, 'Access-Control-Allow-Methods': allowMethods, diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/abort.js b/packages/mitmproxy/src/lib/interceptor/impl/req/abort.js index e15bac34e8..269e73a095 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/abort.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/abort.js @@ -1,11 +1,23 @@ module.exports = { - requestIntercept (context, interceptOpts, req, res, ssl, next) { + name: 'abort', + priority: 103, + requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log } = context - log.info('abort:', rOptions.hostname, req.url) - res.writeHead(403) - res.write('DevSidecar 403: \n\n request abort, this request is matched by abort intercept.\n\n 因配置abort拦截器,本请求将取消') + + res.writeHead(403, { + 'Content-Type': 'text/plain; charset=utf-8', + 'DS-Interceptor': 'abort' + }) + res.write( + 'DevSidecar 403: Request abort.\r\n\r\n' + + ' This request is matched by abort intercept.\r\n' + + ' 因配置abort拦截器,本请求直接返回403禁止访问。' + ) res.end() - return true// 是否结束 + + const url = `${rOptions.method} ➜ ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` + log.info('abort intercept:', url) + return true // true代表请求结束 }, is (interceptOpt) { return !!interceptOpt.abort diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/cacheReq.js b/packages/mitmproxy/src/lib/interceptor/impl/req/cacheReq.js index afc7db9de6..b906f33f88 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/cacheReq.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/cacheReq.js @@ -55,6 +55,8 @@ function getLastModifiedTimeFromIfModifiedSince (rOptions, log) { } module.exports = { + name: 'cacheReq', + priority: 111, requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log } = context @@ -65,12 +67,12 @@ module.exports = { // 获取 Cache-Control 用于判断是否禁用缓存 const cacheControl = rOptions.headers['cache-control'] if (cacheControl && (cacheControl.indexOf('no-cache') >= 0 || cacheControl.indexOf('no-store') >= 0)) { - return // 禁用缓存,跳过当前拦截器 + return // 当前请求指定要禁用缓存,跳过当前拦截器 } // 获取 Pragma 用于判断是否禁用缓存 const pragma = rOptions.headers.pragma if (pragma && (pragma.indexOf('no-cache') >= 0 || pragma.indexOf('no-store') >= 0)) { - return // 禁用缓存,跳过当前拦截 + return // 当前请求指定要禁用缓存,跳过当前拦截器 } // 最近编辑时间 @@ -89,10 +91,12 @@ module.exports = { // 缓存未过期,直接拦截请求并响应304 res.writeHead(304, { - 'Dev-Sidecar-Interceptor': 'cacheReq' + 'DS-Interceptor': 'cache: ' + maxAge }) res.end() + const url = `${rOptions.method} ➜ ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` + log.info('cache intercept:', url) return true }, is (interceptOpt) { diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/proxy.js b/packages/mitmproxy/src/lib/interceptor/impl/req/proxy.js index 6a3f21380b..9af56b14cc 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/proxy.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/proxy.js @@ -1,5 +1,8 @@ const url = require('url') +const lodash = require('lodash') module.exports = { + name: 'proxy', + priority: 121, requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log, RequestCounter } = context @@ -8,17 +11,17 @@ module.exports = { let proxyConf = interceptOpt.proxy if (RequestCounter && interceptOpt.backup && interceptOpt.backup.length > 0) { // 优选逻辑 - const backup = [proxyConf] + const backupList = [proxyConf] for (const bk of interceptOpt.backup) { - backup.push(bk) + backupList.push(bk) } const key = rOptions.hostname + '/' + interceptOpt.key - const count = RequestCounter.getOrCreate(key, backup) + const count = RequestCounter.getOrCreate(key, backupList) if (count.value == null) { count.doRank() } if (count.value == null) { - log.error('count value is null', count) + log.error('`count.value` is null, the count:', count) } else { count.doCount(count.value) proxyConf = count.value @@ -30,27 +33,34 @@ module.exports = { } } - let uri = req.url - if (uri.indexOf('http') === 0) { - // eslint-disable-next-line node/no-deprecated-api - const URL = url.parse(uri) - uri = URL.path - } - let proxyTarget = proxyConf + uri + // 获取代理目标地址 + let proxyTarget if (interceptOpt.replace) { const regexp = new RegExp(interceptOpt.replace) proxyTarget = req.url.replace(regexp, proxyConf) + } else if (proxyConf.indexOf('http:') === 0 || proxyConf.indexOf('https:') === 0) { + proxyTarget = proxyConf + } else { + let uri = req.url + if (uri.indexOf('http') === 0) { + // eslint-disable-next-line node/no-deprecated-api + const URL = url.parse(uri) + uri = URL.path + } + proxyTarget = proxyConf + uri } + // eslint-disable-next-line // no-template-curly-in-string // eslint-disable-next-line no-template-curly-in-string proxyTarget = proxyTarget.replace('${host}', rOptions.hostname) - log.info('拦截【proxy】: original:', rOptions.hostname, ',target:', proxyTarget) - // const backup = interceptOpt.backup const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : rOptions.protocol + '//' + proxyTarget // eslint-disable-next-line node/no-deprecated-api const URL = url.parse(proxy) + rOptions.origional = lodash.cloneDeep(rOptions) // 备份原始请求参数 + delete rOptions.origional.agent + delete rOptions.origional.headers rOptions.protocol = URL.protocol rOptions.hostname = URL.host rOptions.host = URL.host @@ -69,8 +79,10 @@ module.exports = { if (rOptions.agent && rOptions.agent.options) { rOptions.agent.options.rejectUnauthorized = false } + res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}`) log.info('proxy intercept: hostname:', originHostname, ', target:', proxyTarget, ', sni replace servername:', rOptions.servername) } else { + res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}`) log.info('proxy intercept: hostname:', originHostname, ', target:', proxyTarget) } diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/redirect.js b/packages/mitmproxy/src/lib/interceptor/impl/req/redirect.js index 5ef34e2e36..fc5f91b10f 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/redirect.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/redirect.js @@ -1,17 +1,34 @@ module.exports = { + name: 'redirect', + priority: 102, requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log } = context - const url = req.url + let redirect if (typeof interceptOpt.redirect === 'string') { - redirect = rOptions.protocol + '//' + interceptOpt.redirect + url + if (interceptOpt.redirect.indexOf('http:') === 0 || interceptOpt.redirect.indexOf('https:') === 0) { + redirect = interceptOpt.redirect + } else { + redirect = rOptions.protocol + '//' + interceptOpt.redirect + req.url + } } else { - redirect = interceptOpt.redirect(url) + redirect = interceptOpt.redirect(req.url) } - log.info('请求重定向:', rOptions.hostname, url, redirect) - res.writeHead(302, { Location: redirect }) + + // eslint-disable-next-line + // no-template-curly-in-string + // eslint-disable-next-line no-template-curly-in-string + redirect = redirect.replace('${host}', rOptions.hostname) + + res.writeHead(302, { + Location: redirect, + 'DS-Interceptor': 'redirect' + }) res.end() - return true// 是否结束 + + const url = `${rOptions.method} ➜ ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` + log.info(`redirect intercept: ${url} ➜ ${redirect}`) + return true // true代表请求结束 }, is (interceptOpt) { return interceptOpt.redirect // 如果配置中有redirect,那么这个配置是需要redirect拦截的 diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/sni.js b/packages/mitmproxy/src/lib/interceptor/impl/req/sni.js index c0159be49d..a60c04f24b 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/sni.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/sni.js @@ -1,13 +1,17 @@ module.exports = { - requestIntercept (context, interceptOpt) { + name: 'sni', + priority: 122, + requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log } = context - if (interceptOpt.sni != null) { - rOptions.servername = interceptOpt.sni - if (rOptions.agent && rOptions.agent.options) { - rOptions.agent.options.rejectUnauthorized = false - } - log.info('sni intercept: sni replace servername:', rOptions.hostname, '➜', rOptions.servername) + + rOptions.servername = interceptOpt.sni + if (rOptions.agent && rOptions.agent.options) { + rOptions.agent.options.rejectUnauthorized = false } + + res.setHeader('DS-Interceptor', 'sni: ' + interceptOpt.sni) + + log.info('sni intercept: sni replace servername:', rOptions.hostname, '➜', rOptions.servername) return true }, is (interceptOpt) { diff --git a/packages/mitmproxy/src/lib/interceptor/impl/req/success.js b/packages/mitmproxy/src/lib/interceptor/impl/req/success.js index de78077f17..f6d4d2e1d9 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/req/success.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/req/success.js @@ -1,11 +1,23 @@ module.exports = { - requestIntercept (context, interceptOpts, req, res, ssl, next) { + name: 'success', + priority: 101, + requestIntercept (context, interceptOpt, req, res, ssl, next) { const { rOptions, log } = context - log.info('success:', rOptions.hostname, req.url) - res.writeHead(200) - res.write('DevSidecar 200: \n\n request success, this request is matched by success intercept.\n\n 因配置success拦截器,本请求将直接返回成功') + + res.writeHead(200, { + 'Content-Type': 'text/plain; charset=utf-8', + 'DS-Interceptor': 'success' + }) + res.write( + 'DevSidecar 200: Request success.\n\n' + + ' This request is matched by success intercept.\n\n' + + ' 因配置success拦截器,本请求直接返回200成功。' + ) res.end() - return true// 是否结束 + + const url = `${rOptions.method} ➜ ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` + log.info('success intercept:', url) + return true // true代表请求结束 }, is (interceptOpt) { return !!interceptOpt.success diff --git a/packages/mitmproxy/src/lib/interceptor/impl/res/cacheRes.js b/packages/mitmproxy/src/lib/interceptor/impl/res/cacheRes.js index 2fa911e922..2f8a078795 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/res/cacheRes.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/res/cacheRes.js @@ -1,11 +1,14 @@ const cacheReq = require('../req/cacheReq') module.exports = { + name: 'cacheRes', + priority: 201, responseIntercept (context, interceptOpt, req, res, proxyReq, proxyRes, ssl, next) { const { rOptions, log } = context // 只有GET请求,且响应码为2xx时才进行缓存 if (rOptions.method !== 'GET' || proxyRes.statusCode < 200 || proxyRes.statusCode >= 300) { + // res.setHeader('DS-Cache-Interceptor', `skip: 'method' or 'status' not match`) return } @@ -48,6 +51,9 @@ module.exports = { if (interceptOpt.cacheImmutable !== false && originalHeaders.cacheControl.value.indexOf('immutable') < 0) { maxAge = maxAgeMatch[1] } else { + const url = `${rOptions.method} ➜ ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` + res.setHeader('DS-Cache-Interceptor', `skip: ${maxAgeMatch[1]} > ${maxAge}`) + log.info(`cache response intercept: skip: ${maxAgeMatch[1]} > ${maxAge}, url: ${url}`) return } } @@ -80,7 +86,7 @@ module.exports = { res.setHeader('Expires', replaceHeaders.expires) } - res.setHeader('Dev-Sidecar-Cache-Response-Interceptor', 'cacheRes:maxAge=' + maxAge) + res.setHeader('DS-Cache-Response-Interceptor', maxAge) }, is (interceptOpt) { const maxAge = cacheReq.getMaxAge(interceptOpt) diff --git a/packages/mitmproxy/src/lib/interceptor/impl/res/script.js b/packages/mitmproxy/src/lib/interceptor/impl/res/script.js index b8828ea96e..ac50212869 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/res/script.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/res/script.js @@ -13,6 +13,8 @@ function getScript (key, script) { } module.exports = { + name: 'script', + priority: 202, responseIntercept (context, interceptOpt, req, res, proxyReq, proxyRes, ssl, next) { const { rOptions, log, setting } = context let keys = interceptOpt.script @@ -20,20 +22,23 @@ module.exports = { keys = [keys] } try { - let tags = getScript('global', monkey.get(setting.script.dirAbsolutePath).global.script) + const scripts = monkey.get(setting.script.dirAbsolutePath) + let tags = getScript('global', scripts.global.script) for (const key of keys) { - const script = monkey.get(setting.script.dirAbsolutePath)[key] + const script = scripts[key] if (script == null) { continue } const scriptTag = getScript(key, script.script) tags += '\r\n' + scriptTag } - log.info('responseIntercept: insert script', rOptions.hostname, rOptions.path) + res.setHeader('DS-Script-Interceptor', 'true') + log.info('script response intercept: insert script', rOptions.hostname, rOptions.path, ', head:', tags) return { head: tags } } catch (err) { + res.setHeader('DS-Script-Interceptor', 'error') log.error('load monkey script error', err) } }, diff --git a/packages/mitmproxy/src/lib/proxy/middleware/overwall.js b/packages/mitmproxy/src/lib/proxy/middleware/overwall.js index 57bf3790cf..7c567d7ae9 100644 --- a/packages/mitmproxy/src/lib/proxy/middleware/overwall.js +++ b/packages/mitmproxy/src/lib/proxy/middleware/overwall.js @@ -18,7 +18,7 @@ function matched (hostname, overWallTargetMap) { log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' in pac.txt`) return true } else { - // log.debug(`matchHostname: matched overwall: Not-Matched '${hostname}' -> '${ret}' in pac.txt`) + log.debug(`matchHostname: matched overwall: Not-Matched '${hostname}' -> '${ret}' in pac.txt`) return false } } diff --git a/packages/mitmproxy/src/options.js b/packages/mitmproxy/src/options.js index 1a1cbe0e92..1a925a3b8d 100644 --- a/packages/mitmproxy/src/options.js +++ b/packages/mitmproxy/src/options.js @@ -1,4 +1,4 @@ -const interceptors = require('./lib/interceptor') +const interceptorImpls = require('./lib/interceptor') const dnsUtil = require('./lib/dns') const log = require('./utils/util.log') const matchUtil = require('./utils/util.match') @@ -49,7 +49,7 @@ module.exports = (config) => { const hostname = req.url.split(':')[0] const inWhiteList = matchUtil.matchHostname(whiteList, hostname, 'in whiteList') != null if (inWhiteList) { - log.info('白名单域名,不拦截', hostname) + log.info('为白名单域名,不拦截:', hostname) return false // 所有都不拦截 } // 配置了拦截的域名,将会被代理 @@ -57,29 +57,42 @@ module.exports = (config) => { if (matched === true) { return matched // 拦截 } - return null // 由下一个拦截器判断 + return null // 未匹配到任何拦截配置,由下一个拦截器判断 }, createIntercepts: (context) => { const rOptions = context.rOptions - const hostname = rOptions.hostname - const interceptOpts = matchUtil.matchHostname(intercepts, hostname, 'get interceptOpts') + const interceptOpts = matchUtil.matchHostnameAll(intercepts, rOptions.hostname, 'get interceptOpts') if (!interceptOpts) { // 该域名没有配置拦截器,直接过 return } const matchIntercepts = [] + const matchInterceptsOpts = {} for (const regexp in interceptOpts) { // 遍历拦截配置 const interceptOpt = interceptOpts[regexp] - interceptOpt.key = regexp - if (regexp !== true) { + // interceptOpt.key = regexp + if (regexp !== true && regexp !== 'true') { if (!matchUtil.isMatched(rOptions.path, regexp)) { continue } } - for (const impl of interceptors) { + log.info(`interceptor matched, regexp: '${regexp}' =>`, JSON.stringify(interceptOpt), ', path:', rOptions.path) + for (const impl of interceptorImpls) { // 根据拦截配置挑选合适的拦截器来处理 if (impl.is && impl.is(interceptOpt)) { - const interceptor = {} + let action = 'add' + + // 如果存在同名拦截器,则order值越大,优先级越高 + const matchedInterceptOpt = matchInterceptsOpts[impl.name] + if (matchedInterceptOpt) { + if (matchedInterceptOpt.order >= interceptOpt.order) { + log.warn(`duplicate interceptor: ${impl.name}, hostname: ${rOptions.hostname}`) + continue + } + action = 'replace' + } + + const interceptor = { name: impl.name, priority: impl.priority } if (impl.requestIntercept) { // req拦截器 interceptor.requestIntercept = (context, req, res, ssl, next) => { @@ -91,10 +104,26 @@ module.exports = (config) => { return impl.responseIntercept(context, interceptOpt, req, res, proxyReq, proxyRes, ssl, next) } } - matchIntercepts.push(interceptor) + + // log.info(`${action} interceptor: ${impl.name}, hostname: ${rOptions.hostname}, regexp: ${regexp}`) + if (action === 'add') { + matchIntercepts.push(interceptor) + } else { + matchIntercepts[matchedInterceptOpt.index] = interceptor + } + matchInterceptsOpts[impl.name] = { + order: interceptOpt.order || 0, + index: matchIntercepts.length - 1 + } } } } + + matchIntercepts.sort((a, b) => { return a.priority - b.priority }) + // for (const interceptor of matchIntercepts) { + // log.info('interceptor:', interceptor.name, 'priority:', interceptor.priority) + // } + return matchIntercepts } } diff --git a/packages/mitmproxy/src/utils/util.match.js b/packages/mitmproxy/src/utils/util.match.js index e5ebd6d433..b77e80c027 100644 --- a/packages/mitmproxy/src/utils/util.match.js +++ b/packages/mitmproxy/src/utils/util.match.js @@ -94,6 +94,16 @@ function merge (oldObj, newObj) { } }) } +function deleteNullItems (target) { + lodash.forEach(target, (item, key) => { + if (item == null || item === '[delete]') { + delete target[key] + } + if (lodash.isObject(item)) { + deleteNullItems(item) + } + }) +} function matchHostnameAll (hostMap, hostname, action) { // log.debug('matchHostnameAll:', action, hostMap) @@ -108,29 +118,9 @@ function matchHostnameAll (hostMap, hostname, action) { } let values = {} - let hasValue = false - - // 域名快速匹配:直接匹配 或者 两种前缀通配符匹配 - let value = hostMap.origin[hostname] - if (value) { - log.info(`matchHostnameAll: ${action}: '${hostname}' -> '${hostname}': ${JSON.stringify(value)}`) - values = merge(values, value) - hasValue = true - } - value = hostMap.origin['*' + hostname] - if (value) { - log.info(`matchHostnameAll: ${action}: '${hostname}' -> '*${hostname}': ${JSON.stringify(value)}`) - values = merge(values, value) - hasValue = true - } - value = hostMap.origin['*.' + hostname] - if (value) { - log.info(`matchHostnameAll: ${action}: '${hostname}' -> '*.${hostname}': ${JSON.stringify(value)}`) - values = merge(values, value) - hasValue = true - } + let value - // 通配符匹配 或 正则表达式匹配 + // 通配符匹配 或 正则表达式匹配(优先级:1,最低) for (const target in hostMap) { if (target === 'origin') { continue @@ -149,17 +139,37 @@ function matchHostnameAll (hostMap, hostname, action) { // 正则表达式匹配 if (hostname.match(regexp)) { value = hostMap[target] - // log.info(`matchHostname: ${action}: '${hostname}' -> '${target}': ${JSON.stringify(value)}`) + log.info(`matchHostnameOne: ${action}: '${hostname}' -> '${target}': ${JSON.stringify(value)}`) values = merge(values, value) - hasValue = true } } - if (hasValue) { - log.info(`*matchHostnameAll*: ${action}: '${hostname}':`, JSON.stringify(values)) + // 域名快速匹配:直接匹配 或者 两种前缀通配符匹配 + // 优先级:2 + value = hostMap.origin['*' + hostname] + if (value) { + log.info(`matchHostnameOne: ${action}: '${hostname}' -> '*${hostname}': ${JSON.stringify(value)}`) + values = merge(values, value) + } + // 优先级:3 + value = hostMap.origin['*.' + hostname] + if (value) { + log.info(`matchHostnameOne: ${action}: '${hostname}' -> '*.${hostname}': ${JSON.stringify(value)}`) + values = merge(values, value) + } + // 优先级:4,最高(注:优先级高的配置,可以覆盖优先级低的配置,甚至有空配置时,可以移除已有配置) + value = hostMap.origin[hostname] + if (value) { + log.info(`matchHostnameOne: ${action}: '${hostname}' -> '${hostname}': ${JSON.stringify(value)}`) + values = merge(values, value) + } + + if (!lodash.isEmpty(values)) { + deleteNullItems(values) + log.info(`matchHostnameAll: ${action}: '${hostname}':`, JSON.stringify(values)) return values } else { - log.debug(`*matchHostnameAll*: ${action}: '${hostname}' Not-Matched`) + log.debug(`matchHostnameAll: ${action}: '${hostname}' Not-Matched`) } }