feature: 指定域名的请求超时时间和连接超时时间可配置化。

pull/354/head
王良 2024-09-12 11:26:55 +08:00
parent 9d12aa4516
commit 497c199084
7 changed files with 88 additions and 59 deletions

View File

@ -44,8 +44,6 @@ module.exports = {
setting: {
NODE_TLS_REJECT_UNAUTHORIZED: true,
verifySsl: true,
timeout: 20000, // 代理请求超时时间
keepAliveTimeout: 30000, // socket连接的超时时间
script: {
enabled: true,
defaultDir: './extra/scripts/'
@ -54,6 +52,18 @@ module.exports = {
rootCaFile: {
certPath: getRootCaCertPath(),
keyPath: getRootCaKeyPath()
},
// 默认超时时间配置
defaultTimeout: 20000, // 请求超时时间
defaultKeepAliveTimeout: 30000, // 连接超时时间
// 指定域名超时时间配置
timeoutMapping: {
'github.com': {
timeout: 20000,
keepAliveTimeout: 30000
}
}
},
intercept: {

View File

@ -37,13 +37,6 @@
<div class="form-help">修改后需要重启应用</div>
</a-form-item>
<hr/>
<a-form-item label="请求超时时间" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-number v-model="config.server.setting.timeout" :step="1000" :min="1000"/> ms对应 timeout 属性
</a-form-item>
<a-form-item label="连接超时时间" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-number v-model="config.server.setting.keepAliveTimeout" :step="1000" :min="1000"/> ms对应 keepAliveTimeout 属性
</a-form-item>
<hr/>
<a-form-item label="全局校验SSL" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.server.setting.NODE_TLS_REJECT_UNAUTHORIZED">
NODE_TLS_REJECT_UNAUTHORIZED
@ -81,7 +74,19 @@
<vue-json-editor style="height:100%;" ref="editor" v-model="config.server.intercepts" mode="code"
:show-btns="false" :expandedOnStart="true"></vue-json-editor>
</a-tab-pane>
<a-tab-pane tab="域名白名单" key="3">
<a-tab-pane tab="超时时间设置" key="3">
<div style="height:100%;display:flex;flex-direction:column;padding-right:10px">
<a-form-item label="默认超时时间" :label-col="labelCol" :wrapper-col="wrapperCol">
请求<a-input-number v-model="config.server.setting.defaultTimeout" :step="1000" :min="1000"/> ms对应 timeout 属性<br/>
连接<a-input-number v-model="config.server.setting.defaultKeepAliveTimeout" :step="1000" :min="1000"/> ms对应 keepAliveTimeout 属性
</a-form-item>
<hr/>
<div>这里指定域名的超时时间<span class="form-help">以下github的配置为示例预计将在 1.8.7 版本删除</span></div>
<vue-json-editor style="flex-grow:1;min-height:300px;margin-top:10px" ref="editor" v-model="config.server.setting.timeoutMapping" mode="code"
:show-btns="false" :expandedOnStart="true"></vue-json-editor>
</div>
</a-tab-pane>
<a-tab-pane tab="域名白名单" key="4">
<a-row style="margin-top:10px">
<a-col span="19">
<div>这里配置哪些域名不需要通过代理</div>
@ -99,16 +104,18 @@
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane tab="IP预设置" key="4">
<div>注意IP预设置功能需要与 `DNS设置` `IP测速` 功能一起使用才会生效</div>
<vue-json-editor style="height:94%;margin-top:10px;" ref="editor" v-model="config.server.preSetIpList" mode="code"
:show-btns="false" :expandedOnStart="true"></vue-json-editor>
<a-tab-pane tab="IP预设置" key="5">
<div style="height:100%;display:flex;flex-direction:column">
<div>注意IP预设置功能需要与 `DNS设置` `IP测速` 功能一起使用才会生效</div>
<vue-json-editor style="flex-grow:1;min-height:300px;margin-top:10px;" ref="editor" v-model="config.server.preSetIpList" mode="code"
:show-btns="false" :expandedOnStart="true"></vue-json-editor>
</div>
</a-tab-pane>
<a-tab-pane tab="DNS服务管理" key="5">
<a-tab-pane tab="DNS服务管理" key="6">
<vue-json-editor style="height:100%;" ref="editor" v-model="config.server.dns.providers" mode="code"
:show-btns="false" :expandedOnStart="true"></vue-json-editor>
</a-tab-pane>
<a-tab-pane tab="DNS设置" key="6">
<a-tab-pane tab="DNS设置" key="7">
<div>
<a-row style="margin-top:10px">
<a-col span="19">
@ -136,7 +143,7 @@
</a-row>
</div>
</a-tab-pane>
<a-tab-pane tab="IP测速" key="7">
<a-tab-pane tab="IP测速" key="8">
<div class="ip-tester" style="padding-right: 10px">
<a-alert type="info" message="对从dns获取到的ip进行测速使用速度最快的ip进行访问。对使用增强功能的域名没啥用"></a-alert>
<a-form-item label="开启dns测速" :label-col="labelCol" :wrapper-col="wrapperCol">
@ -375,7 +382,7 @@ export default {
}, 5000)
},
async handleTabChange (key) {
if (key !== '2' && key !== '4' && key !== '5') {
if (key !== '2' && key !== '3' && key !== '5' && key !== '6') {
return
}

View File

@ -3,18 +3,9 @@ const Agent = require('./ProxyHttpAgent')
const HttpsAgent = require('./ProxyHttpsAgent')
const tunnelAgent = require('tunnel-agent')
const log = require('../../../utils/util.log')
const matchUtil = require('../../../utils/util.match')
const util = exports
const httpsAgent = new HttpsAgent({
keepAlive: true,
timeout: 20000,
keepAliveTimeout: 30000, // free socket keepalive for 30 seconds
rejectUnauthorized: false
})
const httpAgent = new Agent({
keepAlive: true,
timeout: 20000,
keepAliveTimeout: 30000 // free socket keepalive for 30 seconds
})
const httpsAgentCache = {}
const httpAgentCache = {}
@ -22,41 +13,46 @@ let socketId = 0
let httpsOverHttpAgent, httpOverHttpsAgent, httpsOverHttpsAgent
function createHttpsAgent (serverSetting) {
const key = (serverSetting.timeout || 20000) + '-' + (serverSetting.keepAliveTimeout || 30000)
function getTimeoutConfig (hostname, serverSetting) {
const timeoutMapping = serverSetting.timeoutMapping
const timeoutConfig = matchUtil.matchHostname(timeoutMapping, hostname, 'get timeoutConfig') || {}
return {
timeout: timeoutConfig.timeout || serverSetting.defaultTimeout || 20000,
keepAliveTimeout: timeoutConfig.keepAliveTimeout || serverSetting.defaultKeepAliveTimeout || 30000
}
}
function createHttpsAgent (timeoutConfig) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout
if (!httpsAgentCache[key]) {
httpsAgentCache[key] = new HttpsAgent({
keepAlive: true,
timeout: serverSetting.timeout || 20000,
keepAliveTimeout: serverSetting.keepAliveTimeout || 30000,
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout,
rejectUnauthorized: false
})
}
return httpsAgentCache[key]
}
function createHttpAgent (serverSetting) {
const key = (serverSetting.timeout || 20000) + '-' + (serverSetting.keepAliveTimeout || 30000)
function createHttpAgent (timeoutConfig) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout
if (!httpAgentCache[key]) {
httpAgentCache[key] = new Agent({
keepAlive: true,
timeout: serverSetting.timeout || 20000,
keepAliveTimeout: serverSetting.keepAliveTimeout || 30000
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout
})
}
return httpAgentCache[key]
}
function createAgent (protocol, serverSetting) {
if (protocol === 'https:') {
return !serverSetting || (serverSetting.timeout === 20000 && serverSetting.keepAliveTimeout === 30000)
? httpsAgent
: createHttpsAgent(serverSetting)
} else {
return !serverSetting || (serverSetting.timeout === 20000 && serverSetting.keepAliveTimeout === 30000)
? httpAgent
: createHttpAgent(serverSetting)
}
function createAgent (protocol, timeoutConfig) {
return protocol === 'https:'
? createHttpsAgent(timeoutConfig)
: createHttpAgent(timeoutConfig)
}
util.parseHostnameAndPort = (host, defaultPort) => {
@ -102,12 +98,19 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting) =>
}
}
// 解析host和port
const arr = util.parseHostnameAndPort(req.headers.host)
const hostname = arr[0]
const port = arr[1] || defaultPort
delete headers['proxy-connection']
let agent
if (!externalProxyUrl) {
// keepAlive
if (headers.connection !== 'close') {
agent = createAgent(protocol, serverSetting)
const timeoutConfig = getTimeoutConfig(hostname, serverSetting)
// log.info(`get timeoutConfig: hostname: ${hostname}, timeoutConfig:`, timeoutConfig)
agent = createAgent(protocol, timeoutConfig)
headers.connection = 'keep-alive'
} else {
agent = false
@ -116,19 +119,16 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting) =>
agent = util.getTunnelAgent(protocol === 'https:', externalProxyUrl)
}
// 解析host和port
const arr = util.parseHostnameAndPort(req.headers.host)
// 初始化options
const options = {
protocol: protocol,
protocol,
method: req.method,
url: req.url,
hostname: arr[0],
port: arr[1] || defaultPort,
hostname,
port,
path: urlObject.path,
headers: req.headers,
agent: agent
agent
}
// eslint-disable-next-line node/no-deprecated-api

View File

@ -48,6 +48,16 @@ function loadPacLastModifiedTime (pacTxt) {
}
}
function formatDate (date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hours = date.getHours().toString().padStart(2, '0')
const minutes = date.getMinutes().toString().padStart(2, '0')
const seconds = date.getSeconds().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
// 保存 pac 内容到 `~/pac.txt` 文件中
function savePacFile (pacTxt) {
const pacFilePath = getTmpPacFilePath()
@ -68,7 +78,7 @@ function savePacFile (pacTxt) {
if (utimesErr) {
log.error('修改 pac.txt 文件时间失败:', utimesErr)
} else {
log.info(`${pacFilePath} 文件时间已被修改其最近更新时间 '${lastModifiedTime}'`)
log.info(`'${pacFilePath}' 文件的修改时间已更新为其最近更新时间 '${formatDate(lastModifiedTime)}'`)
}
})
})

View File

@ -5,10 +5,10 @@ const log = require('../../../utils/util.log')
// copy from node-http-proxy. ^_^
// create connectHandler function
module.exports = function createUpgradeHandler () {
module.exports = function createUpgradeHandler (serverSetting) {
// return
return function upgradeHandler (req, cltSocket, head, ssl) {
const clientOptions = util.getOptionsFromRequest(req, ssl)
const clientOptions = util.getOptionsFromRequest(req, ssl, null, serverSetting)
const proxyReq = (ssl ? https : http).request(clientOptions)
proxyReq.on('error', (e) => {
log.error('upgradeHandler error:', e)

View File

@ -60,7 +60,7 @@ module.exports = {
setting
)
const upgradeHandler = createUpgradeHandler()
const upgradeHandler = createUpgradeHandler(setting)
const fakeServersCenter = createFakeServerCenter({
caCertPath,

View File

@ -19,6 +19,7 @@ function buildIntercepts (intercepts) {
module.exports = (serverConfig) => {
const intercepts = matchUtil.domainMapRegexply(buildIntercepts(serverConfig.intercepts))
const whiteList = matchUtil.domainMapRegexply(serverConfig.whiteList)
const timeoutMapping = matchUtil.domainMapRegexply(serverConfig.setting.timeoutMapping)
const dnsMapping = serverConfig.dns.mapping
const setting = serverConfig.setting
@ -29,6 +30,7 @@ module.exports = (serverConfig) => {
if (setting.verifySsl !== false) {
setting.verifySsl = true
}
setting.timeoutMapping = timeoutMapping
const overWallConfig = serverConfig.plugin.overwall
if (overWallConfig.pac && overWallConfig.pac.enabled) {