切换host后Chrome无缓存刷新

对于开发者来说,可能或多或少的都需要切换host吧。那么,你是否碰到过下面这个问题:明明host已经切换了,可是浏览器却还是之前环境的配置呢?
这时候,你会选择干什么:疯狂刷新?清空缓存?重启浏览器?或者上个厕所回来继续等着?
但这些,都不是很奏效,而且还非常的浪费时间。
所以,👏欢迎使用这个 Chrome 插件Chrome No Cache Refresh,解决你切换host之后不生效的问题。

有效的解决方案

如果你不想使用插件(插件实现本身也是基于这种方式,只是不需要使用者手动操作),也可以麻烦一点,但方法是有效的,步骤如下:

  1. chrome地址栏输入 chrome://net-internals/
  2. 选择 DNS 并点击 Clear host cache
  3. 选择 Sockets 并点击 Flush Socket pools

原理分析

从上面的操作来看,就是点击两个设置按钮,那么他具体的原理是什么呢?

Clear host cache

作为开发者,假设大家都了解一个网页加载的整个过程,这里要说的就是其中有一个步骤——DNS解析:
简单来讲就是 Chrome 在打开一个页面前先会通过有效的办法解析出 IP 和 域名 的对应关系,并缓存下来。下一个相同域名请求就不需要重复解析,直接从DNS缓存中获取对于关系,从而降低整个连接的时间。

在切换 host 之后,如果该条DNS解析记录没有被标记为失效时,此时刷新浏览器,由于对应DNS解析记录已经存在,就会导致实际访问地址并不是我们真实设置的 host 的 IP 地址。

不过正常来讲,我们使用host工具切换host之后, Chrome 中的DNS解析记录会自动标记为失效,所以第二步 Clear host cache 其实并不是必须的。

这是在 Chrome 70 以前版本中看到的界面(新版本只有操作按钮,没有日志记录),在这里可以看到当前有效的DNS缓存条数,表格里面还标注了具体的过期状态和过期时间,当我们点击 Clear host cache 后,所有的DNS缓存都会被清空。

Flush Socket pools

这里其实也是网络请求中的一个重要环节,那就是socket连接:
我们都知道一个新的TCP连接,需要三次握手,而 Chrome 限制每一个主机最多能建立6个TCP连接,这就导致资源较多时,往往需要等待。而建立TCP连接的过程也是相当耗时的,所以 Chrome 会让某些连接在完成请求后,可以不立即关闭通道,而是保存在socket池中等待重用。

所以,这种情况下由于连接通道已经存在,切换host之后自然就没有办法生效,只能等到连接通道自动关闭后才行。而 Flush Socket pools 按钮就能刷新 Chrome 的连接池,从而解决这个问题。

插件介绍

一直以来,我都是使用点击 net-internals 里面的按钮解决 host 不生效的问题。
也尝试使用 Chrome 插件来解决这个问题,当时思考的方式是引入这个页面下的js,然后进行方法调用,结果被安全限制问题给困住了。
后来看到一个类似的插件,通过插入js的方式,解决类似的问题。但使用上多有不方便的地方,于是根据自己的开发需求,重新开发一个插件。

主要功能:

  • 可配置执行选项
  • 可配置是否需要自动刷新
  • 自动关闭设置见面,使用过程无感知

安装及使用方式

由于 Chrome 限制,安装前需要开启权限。

  • 权限开启
    打开 chrome://flags/#extensions-on-chrome-urls ;
    设置 Extensions on chrome:// URLs 选项为 Enabled 状态;
    然后根据提示重启浏览器。
  • 安装插件
    Chrome 应用商店搜索,或直接打开连接:Chrome No Cache Refresh
  • 如需配置插件,在插件图标上:右键 -> 选项 -> 配置并保存

插件实现

实现方式跟前面介绍的有效的解决方案类似,实现流程如下:

  1. 插件会自动打开 net-internals 设置页
  2. 尝试插入代码并执行
  3. 关闭打开的 net-internals 设置页
  4. 检查是否需要刷新当前页面

插件会根据配置,执行相关命令,理论上 net-internals 页面支持的全局方法都能执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const socketsTabUrl = 'chrome://net-internals/#sockets';
// 根据配置自动生成hackJS/socketsTabHack.js内容
const CmdLink = {
clearHostCache: 'window.g_browser.sendClearHostResolverCache()',
closeIdleSockets: 'window.g_browser.sendCloseIdleSockets()',
flushSocketPools: 'window.g_browser.sendFlushSocketPools()',
};

// 监听插件图标点击事件
chrome.browserAction.onClicked.addListener(function (currentTab) {

// 打开网络设置tab
chrome.tabs.create({url: socketsTabUrl, active: false}, function (netTab) {

// 往设置页插入代码
chrome.tabs.executeScript(netTab.id, {
file: "hackJS/socketsTabHack.js"
}, function() {
// 刷新当前页面 autoRefreshPage 从配置中读取
if (autoRefreshPage && currentTab.url && currentTab.url !== socketsTabUrl) {
chrome.tabs.reload(currentTab.id);
}
});
});

});