Chrome 不恢复上次标签页:两个常被忽略的原因和一份可用的关闭脚本

举报
yd_268799136 发表于 2026/10/26 14:51:33 2026/10/26
【摘要】 给自动化用的独立 Chrome 加了 --restore-last-session 之后仍然不恢复标签页。排查下来是两处:restore_on_startup 会被 Chrome 启动后清空,profile.exit_type=Crashed 会让它跳过恢复。附关闭时修正 profile 的 PowerShell 脚本,以及多实例场景下按命令行精确匹配进程的写法。

现象

场景:一台 Windows 机器上跑一个独立的 Chrome for Testing 实例,专门给自动化用,profile 放在 C:\profiles\work,与自己日常用的浏览器完全隔离。想法很简单,任务做完就把浏览器关掉释放内存,下次需要时再启动,最好能接着上次打开的页面继续。

于是加了启动参数 --restore-last-session,又在 profile 里把 session.restore_on_startup 设成 4(继续浏览上次打开的网页)。重启一看,只有一个新标签页,之前开的页面一个都没回来。

没有报错,没有提示,设置看起来完全"没生效"。

原因一:这个值 Chrome 启动后会自己清掉

把浏览器完全退出后,直接去看 profile 里的 Preferences 文件,检索 restore_on_startup:

grep -o '"restore_on_startup":[0-9]*' "C:/profiles/work/Default/Preferences"

没有任何输出。也就是说这个键不是"设了但值不对",而是启动一次之后整条都没了。Chrome 读到它、按其恢复会话,然后把这条配置抹掉,避免下次再恢复同一批页面。

结论很直接:restore_on_startup 不能在第一次配置时写一次了事,必须在每次关闭时重新写回。而且要在进程完全退出之后写,否则运行中的实例在退出时会把内存里的配置整个覆盖回文件。

原因二:exit_type=Crashed 会让 Chrome 跳过恢复

第二个坑更隐蔽。profile 里有个 profile.exit_type 字段,正常退出是 Normal,进程被直接杀掉是 Crashed。Chrome 看到 Crashed 会认为"上次可能是崩溃退出",于是即使配置写着恢复也不执行——它不希望用户一启动就被一堆可能有害的页面环绕。

自动化场景里进程经常是被主动杀掉的,所以这个字段几乎总是 Crashed。查一下就知道:

grep -o '"exit_type":"[A-Za-z]*"' "C:/profiles/work/Default/Preferences"

两个原因叠在一起:配置被清掉,状态又是"崩溃退出",恢复自然一次都不会发生。

修复:关闭时顺手改回来

把两件事都放进关闭脚本:先让浏览器优雅退出(Windows 上向窗口发 WM_CLOSE),给 8 秒超时,还不退再强杀;确认进程退出之后,再改 Preferences。

$ErrorActionPreference = 'SilentlyContinue'
$prefs = "C:\profiles\work\Default\Preferences"

# 1. 优雅关闭,超时强杀(略,见后文进程匹配部分)

# 2. 进程退出后修正配置
$enc = New-Object System.Text.UTF8Encoding($false)
$t = [System.IO.File]::ReadAllText($prefs, [System.Text.Encoding]::UTF8)

$t = $t -replace '"exit_type":"[A-Za-z]*"', '"exit_type":"Normal"'
$t = $t -replace '"exited_cleanly":(true|false)', '"exited_cleanly":true'

if ($t -match '"restore_on_startup":\d+') {
    $t = $t -replace '"restore_on_startup":\d+', '"restore_on_startup":4'
} elseif ($t -match '"session":\{') {
    $t = $t -replace '"session":\{', '"session":{"restore_on_startup":4,'
} else {
    $t = $t -replace '^\{', '{"session":{"restore_on_startup":4},'
}

[System.IO.File]::WriteAllText($prefs, $t, $enc)

几个细节值得说明:

  • 写文件用 UTF-8 无 BOM。带 BOM 的 JSON 交给 Chrome 读有解析风险,一旦它判定配置损坏就重建,等于白改。
  • session 键可能整个不存在,所以要兼容三种情况:键在、session 在但键不在、两层都不在。直接替换字符串在这三种情况下行为不同。
  • 必须等进程真的退出再写。Chrome 退出时会回写整个 Preferences,早写的会被覆盖掉,看起来就是"改了没效果"。
  • 用 -replace 做文本替换而不是 parse 成对象再序列化。Preferences 是个几万行的单行 JSON,Chrome 对键顺序和格式不敏感,但序列化会丢掉别的字段,风险更大。

改完实测:关之前开着 4 个标签页,重启后 4 个全部回来。冷启动到自动化能接管大约 2 秒,标签页恢复到渲染就绪再等 7 到 8 秒。

顺带一个多实例的坑:别用 taskkill /IM

如果机器上同时跑多个实例、每个实例有独立 profile,关闭某个实例时最容易写错的命令是 taskkill /IM chrome.exe。那会把所有 Chrome 一起关掉,包括正在用的那个日常浏览器。

正确做法是按命令行里的 profile 路径精确匹配进程:

$esc = [regex]::Escape("C:\profiles\work")
Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" |
    Where-Object { $_.CommandLine -match $esc } |
    ForEach-Object { Stop-Process -Id $_.ProcessId -Force }

两个容易踩的点:

  • 必须用 [regex]::Escape。路径里的反斜杠在正则里是转义符,不转义的话 C:\profiles\work 匹配不到任何东西,脚本会安静地什么也不做,看起来像"杀不掉"。
  • 匹配要落到完整路径而不是目录名。work 这样的名字会命中 workspace,关一个实例顺手把另一个也关了。

清单

  • 每次关闭后重写 session.restore_on_startup = 4,不能只写一次
  • 把 profile.exit_type 改回 Normal,否则 Chrome 跳过恢复
  • 写 Preferences 必须在进程退出之后,UTF-8 无 BOM
  • 多实例按 profile 路径匹配进程,不要按进程名

这两处都算不上文档里显眼的东西,但它们决定了"配置写了为什么不生效"。排查顺序也清楚了:先看配置文件里键还在不在,再看 exit_type 是什么值,两个都正常再怀疑别的地方。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。