2017-06-06 164 views
25

随着Chrome 59的发布,“无头”模式为now available稳定版Linux和macOS(以及即将推出的Windows与Chrome 60)。这使我们能够运行功能齐全的Chrome版本,而不需要任何可见的用户界面,这是一种用于自动化测试的强大功能。 Here are examples.检测Chrome以JavaScript运行在无头模式下

chrome --headless --disable-gpu --dump-dom https://stackoverflow.com/ 

在我的JavaScript测试跑步,我喜欢使用的浏览器来记录尽可能多的信息越好,以帮助隔离问题。例如,我记录了许多navigator的属性,包括当前的浏览器插件:

JSON.stringify(Array.from(navigator.plugins).map(p => p.name)) 
["Chrome PDF Viewer","Widevine Content Decryption Module","Shockwave Flash","Native Client","Chrome PDF Viewer"] 

我的理解是,Chrome的应该行为相同的无头模式,但我有足够的经验,怀疑可能会显着改变渲染流水线的新特性。

现在,我要在两种模式下运行测试。我希望测试运行人员记录是否正在使用无头模式。我可以在测试配置中传递这些信息,但我宁愿有一个纯粹的JavaScript解决方案,我可以将其构建到测试运行器本身中。但是,我一直无法找到任何揭示无头模式是否激活的浏览器界面。

有没有什么方法可以检测Chrome是否在JavaScript的无头模式下运行?

回答

16

用户代理字符串includes HeadlessChrome instead of Chrome。这可能是你要去找信号,因此您可以使用:

/\bHeadlessChrome\//.test(navigator.userAgent) 

其他有趣的信号包括:

  • 看起来window.chrome是不确定的,当无头。
  • [innerWidth, innerHeight][800, 600](硬编码在headless_browser.cc),而[outerWidth, outerHeight][0, 0](通常不应该发生)。
+1

[我确认'window.chrome === undefined'似乎工作](https://i.stack.imgur.com/68yHd.png )。 –

+0

我已经浏览了无代码的Chrome代码,但不知何故错过了[该用户代理的最高定义](https://chromium.googlesource.com/chromium/src.git/+/lkgr/headless/public/ headless_browser.cc#19)。感谢您指出。如果有更明确的东西,我会让赏金流通,但这可能是我将要解决的问题。 –

3

navigator.plugins应包含浏览器中存在的插件数组(如Flash,ActiveX或Java小程序)。对于headless浏览器,它将为空。

作为安全的一部分,检查它可以用来alert,无头将被忽略:

var start = Date.now(); 
alert('Press OK'); 
var elapse = Date.now() - start; 
if (elapse < 15) { 
    console.log("headless environment detected"); 
} 

一些技术用于检测无头的浏览器在OWASP AppSecUSA 2014通话模拟浏览器隐藏&讨论通过Sergey Shekyan和Bei Zhang寻找video,slides)。

+0

我确认我在无头Chrome浏览器中看到了'navigator.plugins.length === 0'。测试命令:'chrome --headless --disable-gpu --dump-dom'data:text/html,<!doctype html>'' –

1

到目前为止,我所拥有的最佳解决方案就是这种破解。我不会在prod代码中使用它,但可能在测试中。

Chrome的弹出式窗口拦截器通常可用于所有网站,但在无头模式下禁用。我们可以使用打开弹出窗口的能力作为处于无头模式的相当准确的代理。执行很简单:尝试到open(...)一个窗口,并检查我们是否得到null(表示它被阻止)而不是Window对象。如果我们打开一个,尽快关闭它。

function canPopUp() { 
    var w = open(""); 
    if (w !== null) { 
    w.close(); 
    return true; 
    } else { 
    return false; 
    } 
} 

var isHeadless = canPopUp; 

对于一个简单的例子,你可以尝试使用和不使用--headless标志如下:

chrome --headless --disable-gpu --dump-dom 'data:text/html,<!doctype html><body><script>document.body.innerHTML = `headless: ${open("") !== null}`;</script>'

+0

可能相关:https://crbug.com/696439 –

1

刚看完this article by Antoine Vastel它提供了几个方法:用/HeadlessChrome/.test(window.navigator.userAgent)

  • 测试用户代理,但是这是很容易欺骗
  • 测试插件与navigator.plugins.length == 0
  • 测试语言与navigator.languages == ""
  • 测试WebGL供应商和渲染器信息(请参阅有关详细信息的文章)
  • 测试Modernizr检测支持的功能:似乎不支持“细线”(hidpi/retina细线,其宽度小于1px的CSS边界,在hidpi屏幕上物理上为1px)。测试是!Modernizr["hairline"]
  • 测试丢失图像占位符的大小。插入带有无效网址的图片,然后在image.onerror中测试image.width == 0 && image.height == 0(他们发现这是最稳健的)。

无法对谷歌的动机发言(是无头的Chrome只有帮助web应用程序的测试?嗯...),但是这可能被看作是可能会有朝一日修复的bug列表,以便人们不知道这些测试将工作多长时间:)

+0

我在发帖之后注意到Josh Lee在昨天的问题下的评论中提到了这一点。我读了同一篇文章,并记起了上个月的这个问题......我希望我能在原作者的广告之间取得平衡,并且不会抄袭。如果这太多,我可以编辑,删除等(谢谢Jeremy的版本) –

相关问题