查看 Chrome 控制台是否打开

我使用这个小脚本来查看 Firebug 是否打开:

if (window.console && window.console.firebug) {
//is open
};

而且效果很好。现在,我花了半个小时寻找一种方法来检测谷歌 Chrome 内置的网络开发者控制台是否打开,但是我找不到任何提示。

这个:

if (window.console && window.console.chrome) {
//is open
};

没用。

编辑:

因此,似乎不可能检测到 Chrome 控制台是否打开。但有一种“ 黑客”是可行的,但也有一些缺点:

  • 当控制台解除对接时将无法工作
  • 当控制台在页面加载时打开时将无法工作

所以,我现在要选择无签名的答案,但如果有人想出了一个绝妙的主意,他仍然欢迎回答,我改变选定的答案!谢谢!

144732 次浏览

RequestAnimationFrame (2019年底)

让我们把这些前面的答案留在这里,看看历史背景。目前,穆罕默德 · 乌默尔的方法可以在 Chrome78上运行,具有检测关闭事件和打开事件的额外优势。

函数 toString (2019)

这要归功于 超时对这个答案的评论。用一个空函数对象替换正则表达式 /./仍然可以工作。

var devtools = function() {};
devtools.toString = function() {
if (!this.opened) {
alert("Opened");
}
this.opened = true;
}


console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

Regex toString (2017-2018)

由于最初的提问者似乎已经不在了,这仍然是可接受的答案,因此添加了这个解决方案以提高可见性。功劳归于 Antonin Hildebrand评论Zswang回答台。这个解决方案利用了这样一个事实: 除非控制台打开,否则不会对记录的对象调用 toString()

var devtools = /./;
devtools.toString = function() {
if (!this.opened) {
alert("Opened");
}
this.opened = true;
}


console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

Console. profile (2013)

更新: 从 Chrome 中移除了 console.profiles,这个解决方案不再有效。

感谢 Paul Irish发现 DevTools中指出了这个解决方案,使用了分析器:

function isInspectOpen() {
console.profile();
console.profileEnd();
if (console.clear) {
console.clear();
}
return console.profiles.length > 0;
}
function showIfInspectIsOpen() {
alert(isInspectOpen());
}
<button onClick="showIfInspectIsOpen()">Is it open?</button>

window.innerHeight (2011)

This other option can detect the docked inspector being opened, after the page loads, but will not be able to detect an undocked inspector, or if the inspector was already open on page load. There is also some potential for false positives.

window.onresize = function() {
if ((window.outerHeight - window.innerHeight) > 100) {
alert('Docked inspector was opened');
}
}

Chrome 开发工具实际上只是 WebKit 的 WebCore 库的一部分。因此,这个问题适用于 Safari、 Chrome 和其他 WebCore 用户。

如果存在解决方案,那么当 WebKit web 检查器打开和关闭时,它将基于 DOM 中的差异。不幸的是,这是一个先有鸡还是先有蛋的问题,因为当检查器关闭时,我们不能使用检查器来观察 DOM。

您可以编写一些 JavaScript 来转储整个 DOM 树。然后在检查员打开的时候运行一次,在检查员关闭的时候运行一次。DOM 中的任何差异都可能是 web 检查器的副作用,我们可以用它来测试用户是否在检查。

这个 链接是 DOM 转储脚本的良好开端,但是您需要转储整个 DOMWindow对象,而不仅仅是 document

更新:

看来现在有办法了,看看 铬检测器

我创建了 Devtools-检测,它可以检测 DevTools 何时打开:

console.log('is DevTools open?', window.devtools.open);

你也可以收听一个事件:

window.addEventListener('devtoolschange', function (e) {
console.log('is DevTools open?', e.detail.open);
});

当 DevTools 被解除对接时它不工作,但是它可以与 Chrome/Safari/Firefox DevTools 和 Firebug 一起工作。


——更新: ——

这是一个古老的问题,有许多伟大的答案,工作了一段时间。目前 2022年9月5日的最佳答案是@david-fong https://stackoverflow.com/a/68494829/275333

顺便说一下,我的答案还是一样的工作,因为我已经发布了它,只是有点难以使它始终准确。点击“手动基准”链接在我的演示与控制台关闭/打开,看看我的意思-总是有很大的区别。

----------------------

我找到了一种方法来判断 Chrome 控制台是否打开。 它仍然是一个黑客,但它的方式更准确,并将工作,无论控制台是否取消停靠。

基本上,在关闭控制台的情况下运行这段代码大约需要100微秒,而当控制台打开时,大约需要200微秒。

console.log(1);
console.clear();

(1毫秒 = 1000微秒)

我已经写了更多关于它 给你

演示是 给你

有一个棘手的方法来检查它的扩展与’标签’权限:

chrome.tabs.query({url:'chrome-devtools://*/*'}, function(tabs){
if (tabs.length > 0){
//devtools is open
}
});

你也可以检查它是否为你的页面打开:

chrome.tabs.query({
url: 'chrome-devtools://*/*',
title: '*example.com/your/page*'
}, function(tabs){ ... })

我写了一篇关于这个的博文: http://nepjua.org/check-if-browser-console-is-open/

它可以检测是否停靠或解除停靠

function isConsoleOpen() {
var startTime = new Date();
debugger;
var endTime = new Date();


return endTime - startTime > 100;
}


$(function() {
$(window).resize(function() {
if(isConsoleOpen()) {
alert("You're one sneaky dude, aren't you ?")
}
});
});

Chrome65 + (2018)

    r = /./
r.toString = function () {
document.title = '1'
}
console.log('%c', r);

样本: https://jsbin.com/cecuzeb/edit?output(2018-03-16更新)

包裹: https://github.com/zswang/jdetects


当打印“ Element”时,Chrome 开发工具将得到它的 id

    var checkStatus;
    

var element = document.createElement('any');
element.__defineGetter__('id', function() {
checkStatus = 'on';
});
    

setInterval(function() {
checkStatus = 'off';
console.log(element);
console.clear();
}, 1000);

另一个版本(来自评论)

var element = new Image();
Object.defineProperty(element, 'id', {
get: function () {
/* TODO */
alert('囧');
}
});
console.log('%cHello', element);

打印一个正则变量:

    var r = /./;
r.toString = function() {
document.title = 'on';
};
console.log(r);

你也可以试试这个: https://github.com/sindresorhus/devtools-detect

// check if it's open
console.log('is DevTools open?', window.devtools.open);
// check it's orientation, null if not open
console.log('and DevTools orientation?', window.devtools.orientation);


// get notified when it's opened/closed or orientation changes
window.addEventListener('devtoolschange', function (e) {
console.log('is DevTools open?', e.detail.open);
console.log('and DevTools orientation?', e.detail.orientation);
});

如果您的目标是阻塞开发人员工具,请尝试下面的方法(我在一个 JS 代码被混淆的地方发现了一个更复杂的版本,它非常烦人) :

setTimeout(function() {while (true) {eval("debugger");}}, 0);

如果你是开发人员,在开发过程中做一些事情。看看这个 Chrome 扩展。它可以帮助您检测何时打开或关闭 ChromeDevtos。

Https://chrome.google.com/webstore/detail/devtools-status-detector/pmbbjdhohceladenbdjjoejcanjijoaa?authuser=1

这个扩展帮助 Javascript 开发人员检测当前页面上打开或关闭 ChromeDevtools 的时间。 当 Chrome Devtools 关闭/打开时,扩展将在 window.document 元素上引发一个名为“ devtoolsStatusChanged”的事件。

这是示例代码:

 function addEventListener(el, eventName, handler) {
if (el.addEventListener) {
el.addEventListener(eventName, handler);
} else {
el.attachEvent('on' + eventName,
function() {
handler.call(el);
});
}
}




// Add an event listener.
addEventListener(document, 'devtoolsStatusChanged', function(e) {
if (e.detail === 'OPENED') {
// Your code when Devtools opens
} else {
// Your code when Devtools Closed
}
});

这里的一些答案将停止在 Chrome65中工作。在 Chrome 中运行非常可靠的 这里有一个时间攻击的替代方案,并且比 toString()方法更难缓解。不幸的是,它在 Firefox 中并不那么可靠。

addEventListener("load", () => {


var baseline_measurements = [];
var measurements = 20;
var warmup_runs = 3;


const status = document.documentElement.appendChild(document.createTextNode("DevTools are closed"));
const junk = document.documentElement.insertBefore(document.createElement("div"), document.body);
junk.style.display = "none";
const junk_filler = new Array(1000).join("junk");
const fill_junk = () => {
var i = 10000;
while (i--) {
junk.appendChild(document.createTextNode(junk_filler));
}
};
const measure = () => {
if (measurements) {
const baseline_start = performance.now();
fill_junk();
baseline_measurements.push(performance.now() - baseline_start);
junk.textContent = "";
measurements--;
setTimeout(measure, 0);
} else {
baseline_measurements = baseline_measurements.slice(warmup_runs); // exclude unoptimized runs
const baseline = baseline_measurements.reduce((sum, el) => sum + el, 0) / baseline_measurements.length;


setInterval(() => {
const start = performance.now();
fill_junk();
const time = performance.now() - start;
// in actual usage you would also check document.hasFocus()
// as background tabs are throttled and get false positives
status.data = "DevTools are " + (time > 1.77 * baseline ? "open" : "closed");
junk.textContent = "";
}, 1000);
}
};


setTimeout(measure, 300);


});

非常可靠的黑客

基本上是在属性上设置一个 getter 并将其记录到控制台中。显然只有在控制台打开时才能访问。

Https://jsfiddle.net/gcdfs3oo/44/

var checkStatus;
var indicator = document.querySelector('#devtool-status');


var element = new Image();
Object.defineProperty(element, 'id', {
get: function() {
checkStatus='on';
throw new Error("Dev tools checker");
}
});


requestAnimationFrame(function check() {
checkStatus = 'off';
console.dir(element);
indicator.className  = checkStatus;
requestAnimationFrame(check);
});
.on{
color:limegreen;
}


.off{
color:red;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.1/css/all.css" integrity="sha256-DVK12s61Wqwmj3XI0zZ9MFFmnNH8puF/eRHTB4ftKwk=" crossorigin="anonymous" />


<p>
<ul>
<li>
dev toolbar open: icon is <span class="on">green</span>
</li>
<li>
dev toolbar closed: icon is <span class="off">red</span>
</li>
</ul>
</p>
<div id="devtool-status"><i class="fas fa-7x fa-power-off"></i></div>
<br/>
<p><b>Now press F12 to see if this works for your browser!</b></p>

var div = document.createElement('div');
Object.defineProperty(div,'id',{get:function(){
document.title = 'xxxxxx'
}});


setTimeout(()=>console.log(div),3000)


至于 Chrome/77.0.3865.75,一个版本的 二零一九年不工作。 ToString调用立即没有检查员打开。

const resultEl = document.getElementById('result')
const detector = function () {}


detector.toString = function () {
resultEl.innerText = 'Triggered'
}


console.log('%c', detector)
<div id="result">Not detected</div>

使用这个包中的 isDevToolsOpened()函数 < a href = “ https://www.npmjs.com/package/dev-tools-monitor”rel = “ nofollow norefrer”> dev-tools-monitor 除了 Firefox 之外,所有浏览器都能正常工作。

您可以捕获打开 dev 的事件。通过将事件侦听器添加到其打开时使用的键盘快捷方式来实现。这不是一个“黑客”,它的工作100% 的时间。

唯一不能捕捉到的情况是当用户用鼠标手动打开它时。因此,这是一个“部分解决方案”,或许对某些人有用。

<script>
function devToolsOpened(e){
alert("devtools opened");
// uncomment to prevent opening dev.tools:
// e.preventDefault();
}
window.addEventListener('keydown', function(e) {


if (
// CMD + Alt + I (Chrome, Firefox, Safari)
e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
// CMD + Alt + J (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
// CMD + Alt + C (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
// CMD + Shift + C (Chrome)
e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
// Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
// Ctrl + Shift + J (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
// Ctrl + Shift + C (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
// F12 (Chome, Firefox, Edge)
e.keyCode == 123 ||
// CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
e.ctrlKey == true && e.keyCode == 85
){
devToolsOpened(e);
}
});
</script>

打开开发工具的快捷键:

每次打开控制台时,强制使用彩色欢迎消息。

// Force a colorized welcome message
// each time the console is opened.


(() => {
w = new Function()
w.toString = () => { (!this.z) ? console.log("%cWelcome to the console\n %cMaster password:\n %c window.password = ' ... ':", "color: white; font-size: 20px; background-color: blue", "color: white; font-size: 16px; background-color: red;margin 20px 0", "background: #222; color: #bada55") : this.z = true
}
console.log('%c', w)
})()

我在 Chrome89上找到了新的方法

使用 console.profile、 setInterval 和函数 toString

    var devtools = function() {};
devtools.toString = function() {
alert('NOPE!!')
return '-'
}


setInterval(()=>{
console.profile(devtools)
console.profileEnd(devtools)
}, 1000)

在狩猎旅行中,这是行不通的。

铬89以下,我不能检查它是否工作。

似乎有几种常见的解决方案:

  • 依赖于在 devtools 出现时检测屏幕大小的调整(当 devtools/控制台作为单独的窗口打开时,这不起作用)
  • 拦截某些可以打开 devtools/控制台的用户操作,例如右击菜单、 F12、 Ctrl + Shift + C 等。这并不能涵盖浏览器中不能被页面检测到的用户界面机制。
  • 将某些内容记录到控制台,并依赖于特定于浏览器的懒惰、花哨的打印行为。从历史上看,这些似乎不是非常可靠,但他们很好,简单。如果您希望它们在同一个浏览会话中重复工作,那么您可能不得不接受某种程度的控制台垃圾邮件。
  • debugger语句使用计时启发式。棘手的部分是找到一种方法,使计时器不会被 事件循环队列中长时间运行的任务搞乱,而且调试器语句会暂停它所运行的线程的执行。还有一个挑战是,用户可以根据具体情况禁用常规调试器语句,也可以禁用所有常规调试器语句。

下面是我用 debugger方法解决具体问题的方法。我。当主线程在启发式计时器之间运行长任务时,避免误报,避免 debugger语句阻塞主线程,并防止禁用调试器语句。注意: 我不认为有一种方法可以防止用户禁用 所有调试器断点,这可能是最好的方法。

它是如何工作的

当 devtools 打开并且线程遇到调试语句时,Chrome 浏览器进入调试。

  1. 主线程向 webworker 线程发送消息。
  2. 辅助线程以打开心跳回复。
  3. 主线程通过启动计时器以期待关闭心跳来做出反应。
  4. 工作线程的消息处理程序遇到调试器语句(可以选择包装在 eval语句中,以防止用户禁用它)。
  5. 如果 devtools 关闭,工作者将立即向主线程发送确认,主线程将得出 devtools 关闭的结论。
  6. 如果 devtools 被打开,那么 工人将进入一个调试会话,主线程将注意到 Worker 的响应速度不够快,因此推断调试器必须打开。主线程 没有将被工作者的调试会话阻塞,但它的超时 回应将被事件队列中主线程前面的任何繁重处理阻塞。

我已经发布了一个参考实现(由我编写) 在 GitHub 上还有一个样带

优点

  • 与屏幕大小变化检测方法不同,这种方法在控制台位于单独的窗口中时可以工作。
  • 与用户动作拦截方法不同,这种方法不管用户动作带来什么控制台都可以工作。
  • console.log方法不同,这种方法可以用于控制台的多次开启关闭,而不会向控制台发送垃圾邮件。
  • 与基本的计时器调试器方法不同,检测不应该由于繁忙的线程(主线程或其他工作线程)而触发假阳性,调试器语句位于工作线程而不是主线程中,所以主线程不会被阻塞,eval-debug 语句防止禁用特定的调试器语句。

缺点

  • 用户可以禁用所有断点,这将禁用此检测方法。
  • Eval 包装的调试器语句不能在通过内容安全策略禁用 eval 的站点上工作,在这种情况下只能使用常规调试器语句。

Javascript 检测开发人员工具控制台打开

2022年2月2日开始工作

  • Chrome 97版本(开发工具 离岸/停靠/键盘快捷键)
  • Edge Version 97(开发工具 离岸/停靠/键盘快捷键)
  • FireFox Version 96.0.03(开发工具 < strong > Undocked /停靠/键盘快捷键)
  • Safari?
  • FireBug Detection (Developer Tools)

// Prevent Right Click (Optional)
document.addEventListener('contextmenu', function(event) {
event.preventDefault();
}, true);


// DevTools Opened Script
function DevToolsOpened() {
alert("Developer Tools Opened");
}


// Detect DevTools (Chrome/Edge)
// https://stackoverflow.com/a/67148898/9498503 (SeongJun)
var devtools = function() {};
devtools.toString = function() {
DevToolsOpened();
return '-';
}


setInterval(()=>{
console.profile(devtools);
console.profileEnd(devtools);
if (console.clear) {
console.clear();
}
}, 1000);


// Detect DevTools (FireFox)
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1){
// Detect Resize (Chrome/Firefox/Edge Works) but (Triggers on Zoom In Chrome and Zoom Out FireFox)
window.onresize = function() {
if ((window.outerHeight - window.innerHeight) > 100 || (window.outerWidth - window.innerWidth) > 100) {
DevToolsOpened();
}
}
}


// Detect Fire Bug
if (window.console && window.console.firebug || console.assert(1) === '_firebugIgnore') {
DevToolsOpened();
};


// Detect Key Shortcuts
// https://stackoverflow.com/a/65135979/9498503 (hlorand)
window.addEventListener('keydown', function(e) {
if (
// CMD + Alt + I (Chrome, Firefox, Safari)
e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
// CMD + Alt + J (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
// CMD + Alt + C (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
// CMD + Shift + C (Chrome)
e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
// Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
// Ctrl + Shift + J (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
// Ctrl + Shift + C (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
// F12 (Chome, Firefox, Edge)
e.keyCode == 123 ||
// CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
e.ctrlKey == true && e.keyCode == 85
) {
DevToolsOpened();
}
});

定时解决方案(工程停靠和取消停靠)

它有点侵入性,但不像调试器陷阱那么严重

var opened = false;
var lastTime = Date.now();
const interval = 50;
const threshold = 30;
setInterval(() => {


let delta = Date.now() - lastTime;


if (delta > interval + threshold) {
document.title = "P3nis";
opened = true;
}


lastTime = Date.now();


if (!opened) {
debugger;
}


}, interval)

console.log(Object.defineProperties(new Error, {
message: {get() {alert('Chrome/Firefox')}},
toString: {value() {(new Error).stack.includes('toString@')&&alert('Safari')}}
}));

演示: https://jsbin.com/cateqeyono/edit?html,output

拥有 Debug-Mode on/off 特性的最佳方法是在 localStorage 中默认设置一个标志 'debugMode'='off'-

localStorage.setItem('debugMode', 'off');

然后,在浏览器的 本地仓库中手动更改为‘ on’,同时进行开发-

enter image description here

然后使用下面的条件在代码中执行不同的操作,如果它是‘ on’-

if(localStorage.getItem('debugMode') === 'on'){
//do something 1
}else {
//do something 2
}