Skip to content

Commit 552a113

Browse files
committed
fix(proxy): 降低代理开启配置和地址输入成本
代理初始化需要保留默认自动开启的兼容行为,但也要允许通过环境变量显式关闭自动探测,避免 profile 缓存回放绕过用户配置。代理开启命令同时支持完整 URL,减少 host/port 分拆输入的心智负担,并让 Bash 与 PowerShell 入口保持一致。 Constraint: 默认自动开启代理的历史行为必须保持兼容 Constraint: 项目要求修改 psutils/pwsh 相关内容后执行 pnpm qa 与 pnpm test:pwsh:all Rejected: 将默认行为改为关闭 | 会破坏既有 profile 自动代理体验 Rejected: 只改 PowerShell 入口 | shell/shared.d/proxy.sh 仍会出现不一致输入体验 Confidence: high Scope-risk: narrow Directive: 后续新增代理子命令时复用同一套 endpoint 解析语义,避免 URL、端口、host+port 行为分叉 Tested: bash -n shell/shared.d/proxy.sh Tested: Invoke-Pester -Path ./psutils/tests/proxy.Tests.ps1 -Output Detailed Tested: pnpm qa Tested: pnpm test:pwsh:all Not-tested: 实际写入 Docker daemon/container 代理配置,避免触碰本机 Docker 服务配置
1 parent a61f10f commit 552a113

8 files changed

Lines changed: 235 additions & 39 deletions

File tree

profile/Debug-ProfilePerformance.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ if ($IsLinux) {
213213
Lap '4.02-linux-path-sync'
214214

215215
# 4.3 代理自动检测
216-
if (-not $SkipProxy) {
216+
if ((-not $SkipProxy) -and (Test-EnvSwitchEnabled -Name 'PROXY_AUTO_ENABLE' -DefaultEnabled)) {
217217
try {
218218
$proxyState = Invoke-WithCache `
219219
-Key "proxy-auto-detect" `

profile/core/mode.ps1

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
function Test-EnvSwitchEnabled {
2+
<#
3+
.SYNOPSIS
4+
解析环境变量形式的布尔开关。
5+
6+
.DESCRIPTION
7+
支持 0/false/off/no/n 作为显式关闭值,其他非空值视为开启;DefaultEnabled 用于描述默认开启的配置项。
8+
9+
.PARAMETER Name
10+
需要读取的环境变量名称。
11+
12+
.PARAMETER DefaultEnabled
13+
环境变量不存在或为空白时是否返回开启。
14+
15+
.OUTPUTS
16+
System.Boolean。返回 $true 表示开关开启,返回 $false 表示开关关闭。
17+
#>
218
[CmdletBinding()]
319
param(
420
[Parameter(Mandatory = $true)]
5-
[string]$Name
21+
[string]$Name,
22+
23+
[switch]$DefaultEnabled
624
)
725

826
$rawValue = [System.Environment]::GetEnvironmentVariable($Name)
9-
if ($null -eq $rawValue) { return $false }
10-
if ([string]::IsNullOrWhiteSpace($rawValue)) { return $false }
27+
if ($null -eq $rawValue) { return [bool]$DefaultEnabled }
28+
if ([string]::IsNullOrWhiteSpace($rawValue)) { return [bool]$DefaultEnabled }
1129

1230
switch ($rawValue.Trim().ToLowerInvariant()) {
1331
'0' { return $false }

profile/features/environment.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,8 @@ function Initialize-Environment {
348348
}
349349
}
350350

351-
# 自动检测代理(缓存 5 分钟避免每次 profile 加载都做 TCP 探测)
352-
if (-not $SkipProxy) {
351+
# 自动检测代理默认保持开启;PROXY_AUTO_ENABLE=0/false/off/no/n 时跳过检测与缓存回放。
352+
if ((-not $SkipProxy) -and (Test-EnvSwitchEnabled -Name 'PROXY_AUTO_ENABLE' -DefaultEnabled)) {
353353
try {
354354
$proxyState = Invoke-WithCache -Key "proxy-auto-detect" -MaxAge ([TimeSpan]::FromMinutes(30)) -CacheType Text -ScriptBlock {
355355
Set-Proxy -Command auto

psutils/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ New-Shortcut -Path "C:\Program Files\App\app.exe" -Destination "C:\Users\Desktop
424424

425425
提供网络代理配置管理功能。
426426

427+
默认会在 profile 初始化或 shell 脚本加载时自动探测 `PROXY_DEFAULT_HOST:PROXY_DEFAULT_PORT`,端口可连通则自动开启当前会话代理。若希望保留 `proxy on/off` 命令但关闭自动开启,可设置 `PROXY_AUTO_ENABLE=0`(也支持 `false``off``no``n`)。
428+
427429
### 💻 PowerShell 工具 (pwsh)
428430

429431
提供 PowerShell 环境增强功能。

psutils/modules/proxy.psm1

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,17 @@ function Set-Proxy {
7979
支持通过环境变量配置默认代理:
8080
- $env:PROXY_DEFAULT_HOST: 默认代理主机 (默认: 127.0.0.1)
8181
- $env:PROXY_DEFAULT_PORT: 默认代理端口 (默认: 7890)
82+
- $env:PROXY_AUTO_ENABLE: 是否允许 auto 自动开启代理 (默认: 1;0/false/off/no/n 表示关闭)
8283
8384
.PARAMETER Command
8485
操作命令: on, off, status, test, docker, container, auto, help。
8586
默认值为 'status'。
8687
8788
.PARAMETER Target
88-
目标主机或端口
89+
目标主机、端口或完整代理 URL
8990
如果仅提供端口 (如 7890),则主机默认为 127.0.0.1。
9091
如果提供主机 (如 192.168.1.10),则需要通过 Port 参数提供端口,或使用默认端口。
92+
如果提供完整 URL (如 http://192.168.1.10:7890),则直接使用该地址的协议、主机和端口。
9193
9294
.PARAMETER Port
9395
代理端口,仅在 Target 为主机时使用。
@@ -100,6 +102,10 @@ function Set-Proxy {
100102
proxy on 192.168.1.100 1080
101103
开启代理,指向 192.168.1.100:1080
102104
105+
.EXAMPLE
106+
proxy on http://192.168.21.90:7890
107+
使用完整 URL 开启代理。
108+
103109
.EXAMPLE
104110
proxy off
105111
关闭当前会话代理
@@ -127,16 +133,70 @@ function Set-Proxy {
127133
$DefaultHost = if (-not [string]::IsNullOrWhiteSpace($env:PROXY_DEFAULT_HOST)) { $env:PROXY_DEFAULT_HOST } else { "127.0.0.1" }
128134
$DefaultPort = if (-not [string]::IsNullOrWhiteSpace($env:PROXY_DEFAULT_PORT)) { $env:PROXY_DEFAULT_PORT } else { "7890" }
129135
$NoProxyList = "localhost,127.0.0.1,::1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12"
136+
137+
function Test-ProxyAutoEnable {
138+
<#
139+
.SYNOPSIS
140+
判断是否允许自动探测并开启代理。
141+
142+
.DESCRIPTION
143+
通过 PROXY_AUTO_ENABLE 控制 profile 或 auto 命令的自动开启行为;未设置时保持兼容,默认允许自动开启。
144+
145+
.OUTPUTS
146+
System.Boolean。返回 $true 表示允许自动开启,返回 $false 表示跳过自动开启。
147+
#>
148+
param()
149+
150+
$rawValue = [System.Environment]::GetEnvironmentVariable('PROXY_AUTO_ENABLE')
151+
if ([string]::IsNullOrWhiteSpace($rawValue)) { return $true }
152+
153+
switch ($rawValue.Trim().ToLowerInvariant()) {
154+
'0' { return $false }
155+
'false' { return $false }
156+
'off' { return $false }
157+
'no' { return $false }
158+
'n' { return $false }
159+
default { return $true }
160+
}
161+
}
130162

131163
# 内部辅助函数:解析主机和端口
132164
function Get-ProxyEndpoint {
165+
<#
166+
.SYNOPSIS
167+
解析代理目标参数。
168+
169+
.DESCRIPTION
170+
兼容端口、主机加端口、完整 URL 三种输入形式,并统一返回代理环境变量使用的 URL。
171+
172+
.PARAMETER InputTarget
173+
端口、主机或完整代理 URL。
174+
175+
.PARAMETER InputPort
176+
当 InputTarget 为主机时使用的代理端口。
177+
178+
.OUTPUTS
179+
System.Management.Automation.PSCustomObject。包含 Host、Port、Url 三个字段。
180+
#>
133181
param ($InputTarget, $InputPort)
134182

135183
$hostName = $DefaultHost
136184
$portNum = $DefaultPort
185+
$scheme = "http"
137186

138187
if (-not [string]::IsNullOrWhiteSpace($InputTarget)) {
139-
if ($InputTarget -match '^\d+$') {
188+
if ($InputTarget -match '^[a-zA-Z][a-zA-Z0-9+.-]*://') {
189+
$uri = [System.Uri]$InputTarget
190+
$scheme = $uri.Scheme
191+
$hostName = $uri.Host
192+
if (-not $uri.IsDefaultPort) {
193+
$portNum = [string]$uri.Port
194+
}
195+
elseif (-not [string]::IsNullOrWhiteSpace($InputPort)) {
196+
$portNum = $InputPort
197+
}
198+
}
199+
elseif ($InputTarget -match '^\d+$') {
140200
$portNum = $InputTarget
141201
}
142202
else {
@@ -146,7 +206,7 @@ function Set-Proxy {
146206
}
147207
}
148208
}
149-
return [pscustomobject]@{ Host = $hostName; Port = $portNum; Url = "http://${hostName}:${portNum}" }
209+
return [pscustomobject]@{ Host = $hostName; Port = $portNum; Url = "${scheme}://${hostName}:${portNum}" }
150210
}
151211
}
152212

@@ -185,6 +245,11 @@ function Set-Proxy {
185245
}
186246

187247
"auto" {
248+
if (-not (Test-ProxyAutoEnable)) {
249+
Write-Verbose "PROXY_AUTO_ENABLE 已关闭,跳过代理自动开启。"
250+
return
251+
}
252+
188253
# 自动尝试连接默认端口,如果通了就开启
189254
$endpoint = Get-ProxyEndpoint -InputTarget $null -InputPort $null
190255
try {

psutils/tests/proxy.Tests.ps1

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ BeforeAll {
2121
$proxyVarNames = @(
2222
"http_proxy", "https_proxy", "ftp_proxy", "rsync_proxy", "all_proxy", "no_proxy",
2323
"HTTP_PROXY", "HTTPS_PROXY", "FTP_PROXY", "RSYNC_PROXY", "ALL_PROXY", "NO_PROXY",
24-
"PROXY_DEFAULT_HOST", "PROXY_DEFAULT_PORT"
24+
"PROXY_DEFAULT_HOST", "PROXY_DEFAULT_PORT", "PROXY_AUTO_ENABLE"
2525
)
2626
foreach ($varName in $proxyVarNames) {
2727
$script:savedEnvVars[$varName] = [System.Environment]::GetEnvironmentVariable($varName)
@@ -76,6 +76,7 @@ Describe "Set-Proxy 函数测试" -Tag 'Proxy' {
7676
# 清除默认值环境变量,确保测试使用硬编码默认值
7777
Remove-Item "env:\PROXY_DEFAULT_HOST" -ErrorAction SilentlyContinue
7878
Remove-Item "env:\PROXY_DEFAULT_PORT" -ErrorAction SilentlyContinue
79+
Remove-Item "env:\PROXY_AUTO_ENABLE" -ErrorAction SilentlyContinue
7980
}
8081

8182
Context "on 命令 - 开启代理" {
@@ -140,6 +141,25 @@ Describe "Set-Proxy 函数测试" -Tag 'Proxy' {
140141
$env:all_proxy | Should -Be "http://192.168.1.100:1080"
141142
}
142143

144+
It "使用完整 URL 时应该直接设置代理地址" {
145+
Mock -ModuleName proxy New-Object {
146+
$mockTcp = [PSCustomObject]@{}
147+
$mockAsync = [PSCustomObject]@{
148+
AsyncWaitHandle = [PSCustomObject]@{}
149+
}
150+
$mockAsync.AsyncWaitHandle | Add-Member -MemberType ScriptMethod -Name WaitOne -Value { param($ms) return $false } -Force
151+
$mockTcp | Add-Member -MemberType ScriptMethod -Name BeginConnect -Value { param($h, $p, $a, $b) return $mockAsync } -Force
152+
$mockTcp | Add-Member -MemberType ScriptMethod -Name Close -Value {} -Force
153+
return $mockTcp
154+
} -ParameterFilter { $TypeName -eq 'System.Net.Sockets.TcpClient' }
155+
156+
Set-Proxy -Command "on" -Target "http://192.168.21.90:7890"
157+
158+
$env:http_proxy | Should -Be "http://192.168.21.90:7890"
159+
$env:https_proxy | Should -Be "http://192.168.21.90:7890"
160+
$env:all_proxy | Should -Be "http://192.168.21.90:7890"
161+
}
162+
143163
It "应该同时设置 ftp_proxy 和 rsync_proxy" {
144164
Mock -ModuleName proxy New-Object {
145165
$mockTcp = [PSCustomObject]@{}
@@ -293,6 +313,21 @@ Describe "Set-Proxy 函数测试" -Tag 'Proxy' {
293313
It "不传参数时应该默认执行 status 命令且不抛出异常" {
294314
{ Set-Proxy } | Should -Not -Throw
295315
}
316+
317+
It "PROXY_AUTO_ENABLE 关闭时 auto 命令不应该探测或开启代理" {
318+
$env:PROXY_AUTO_ENABLE = "0"
319+
320+
Mock -ModuleName proxy New-Object {
321+
throw "关闭自动代理时不应创建 TCP 客户端"
322+
} -ParameterFilter { $TypeName -eq 'System.Net.Sockets.TcpClient' }
323+
324+
Set-Proxy -Command "auto"
325+
326+
$env:http_proxy | Should -BeNullOrEmpty
327+
Should -Invoke New-Object -ModuleName proxy -Times 0 -Exactly -ParameterFilter {
328+
$TypeName -eq 'System.Net.Sockets.TcpClient'
329+
}
330+
}
296331
}
297332

298333
Context "环境变量默认值" {

0 commit comments

Comments
 (0)