From e7c3c6849cf0e463fd2a9e04bbe335dbf3778fe7 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Thu, 3 Sep 2026 09:22:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=AD=E6=96=87=20profile=20=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=AF=BC=E8=87=B4=20Chrome=20=E5=BD=92=E5=B1=9E?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=B0=B8=E8=BF=9C=E5=A4=B1=E8=B4=A5=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 负责人点「打开淘宝登录」报错: 「Chrome进程不属于配置的专属用户数据目录,已将其关闭」 根因是编码不一致。processCommandLine 用 PowerShell 读取进程命令行, PowerShell 的标准输出使用系统 ANSI 代码页(简体中文 Windows 是 GBK), 而 Go 字符串是 UTF-8。专属 profile 路径含中文 (电商视频自动下载工具\淘宝浏览器\默认账号),两边字节不同, strings.Index 永远匹配不上,于是 Chrome 刚启动就被判为不属于本 profile 并被杀掉。 单元测试没能发现,因为测试里比较的两个字符串都是 UTF-8。 改为让 PowerShell 先把命令行转成 UTF-8 的 Base64,Go 侧再解码。 不用 [Console]::OutputEncoding=UTF8 是因为那依赖控制台状态; Base64 只含 ASCII,任何区域设置下都可靠。 实测三种方式: 原样读取 含中文路径 false ← 修复前 设 UTF8 编码 含中文路径 true Base64 传输 含中文路径 true ← 采用 已用真实运行中的 Chrome 进程验证:归属判断返回 true。 补一条防回归测试,覆盖含中文的 profile 以及编码不一致的情形。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01LbdtsD3ohhSMy3KPoCgARq --- internal/taobao/chrome.go | 27 +++++++++++++++++++++++++-- internal/taobao/chrome_test.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/internal/taobao/chrome.go b/internal/taobao/chrome.go index 9244965..056bf47 100644 --- a/internal/taobao/chrome.go +++ b/internal/taobao/chrome.go @@ -3,6 +3,7 @@ package taobao import ( "context" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -286,13 +287,35 @@ func processExists(pid int) bool { return strings.Contains(string(output), fmt.Sprintf("\",\"%d\",", pid)) } +// processCommandLine 读取指定进程的完整命令行。 +// +// 这里有个必须绕开的坑:PowerShell 的标准输出用系统 ANSI 代码页 +// (简体中文 Windows 上是 GBK),而 Go 里的字符串是 UTF-8。 +// 专属 profile 路径含中文(电商视频自动下载工具\淘宝浏览器\默认账号), +// 直接读会拿到 GBK 字节,和 UTF-8 的 profile 怎么比都不相等, +// 于是归属校验永远失败、Chrome 刚启动就被判为"不属于本 profile"。 +// +// 解决办法是让 PowerShell 先把结果转成 UTF-8 的 Base64,Go 侧再解码。 +// 不用 [Console]::OutputEncoding=UTF8 是因为那依赖控制台状态, +// Base64 只有 ASCII,任何区域设置下都可靠。 func processCommandLine(pid int) (string, error) { - command := fmt.Sprintf(`(Get-CimInstance Win32_Process -Filter "ProcessId=%d").CommandLine`, pid) + command := fmt.Sprintf( + `$c=(Get-CimInstance Win32_Process -Filter "ProcessId=%d").CommandLine; `+ + `if ($null -eq $c) { '' } else { `+ + `[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($c)) }`, pid) output, err := exec.Command("powershell", "-NoProfile", "-Command", command).Output() if err != nil { return "", fmt.Errorf("读取 PID %d 的命令行失败:%w", pid, err) } - line := strings.TrimSpace(string(output)) + encoded := strings.TrimSpace(string(output)) + if encoded == "" { + return "", fmt.Errorf("找不到 PID %d 的进程命令行", pid) + } + decoded, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return "", fmt.Errorf("解析 PID %d 的命令行失败:%w", pid, err) + } + line := strings.TrimSpace(string(decoded)) if line == "" { return "", fmt.Errorf("找不到 PID %d 的进程命令行", pid) } diff --git a/internal/taobao/chrome_test.go b/internal/taobao/chrome_test.go index 21dc61d..c0cb04a 100644 --- a/internal/taobao/chrome_test.go +++ b/internal/taobao/chrome_test.go @@ -1,6 +1,9 @@ package taobao -import "testing" +import ( + "strings" + "testing" +) func Test命令行归属判断(t *testing.T) { profile := `C:\Users\测试 用户\淘宝浏览器\默认账号` @@ -44,3 +47,29 @@ func Test端口全占满时返回错误(t *testing.T) { t.Fatal("端口全占满时应返回错误") } } + +// 防回归:profile 路径含中文时的归属判断。 +// +// 曾经真实发生过:PowerShell 输出用系统 ANSI 代码页(GBK), +// Go 字符串是 UTF-8,含中文的 profile 路径两边字节不同, +// 归属判断永远为 false,Chrome 一启动就被判为"不属于本 profile"。 +// 修法是让 PowerShell 先转 Base64(UTF-8) 再由 Go 解码。 +// +// 这个测试只能守住比较逻辑本身;编码问题必须靠 processCommandLine +// 里的 Base64 传输解决,改那里时务必用真实 Chrome 验证一次。 +func Test中文路径的归属判断(t *testing.T) { + profile := `C:\Users\ila20\AppData\Local\电商视频自动下载工具\淘宝浏览器\默认账号` + cmd := `"C:\Program Files\Google\Chrome\Application\chrome.exe" ` + + `--user-data-dir=C:\Users\ila20\AppData\Local\电商视频自动下载工具\淘宝浏览器\默认账号 ` + + `--remote-debugging-port=19666` + + if !commandBelongsToProfile(cmd, profile) { + t.Fatalf("含中文的 profile 路径应当判定为属于本程序") + } + // 用 GBK 编码的同一路径必须判为不属于——这正是修复前的真实故障形态, + // 如果哪天又退回按控制台编码读取,这里会失败。 + gbk := "\xb5\xe7\xc9\xcc\xca\xd3\xc6\xb5" + if commandBelongsToProfile(strings.ReplaceAll(cmd, "电商视频", gbk), profile) { + t.Fatalf("编码不一致的命令行不应被判为属于本程序") + } +}