如何使用 JavaScript 检测页面 404 错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8504673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect on-page 404 errors using JavaScript?
提问by Santoo
I have an HTML page where several JavaScript, CSS and images files are referenced. These references are dynamically injected and user can manually copy the HTML page and the support files to another machine.
我有一个 HTML 页面,其中引用了多个 JavaScript、CSS 和图像文件。这些引用是动态注入的,用户可以手动将 HTML 页面和支持文件复制到另一台机器。
If some JS or CSS are missing, the browser complains in the console. For example:
如果缺少某些 JS 或 CSS,浏览器会在控制台中报错。例如:
Error GET file:///E:/SSC_Temp/html_005/temp/Support/jquery.js
错误 GET file:///E:/SSC_Temp/html_005/temp/Support/jquery.js
I need somehow these errors reported back to me on the inline JavaScript of the HTML page so I can ask user to first verify that support files are copied correctly.
我需要以某种方式在 HTML 页面的内联 JavaScript 上向我报告这些错误,以便我可以要求用户首先验证支持文件是否被正确复制。
There's the window.onerror
event which just inform me that there's a JS error on the page such as an Unexpected Syntax error, but this doesn't fire in the event of a 404 Not Founderror. I want to check for this condition in case of any resource type, including CSS, JS, and images.
有一个window.onerror
事件只是通知我页面上有一个 JS 错误,例如意外的语法错误,但在出现404 Not Found错误时不会触发。我想在任何资源类型(包括 CSS、JS 和图像)的情况下检查这种情况。
I do not like to use jQuery AJAX to verify that file physically exists - the I/O overhead is expensive for every page load.
我不喜欢使用 jQuery AJAX 来验证文件物理存在 - 每次页面加载的 I/O 开销都很昂贵。
The error report has to contain the name of the filemissing so I can check if the file is core or optional.
错误报告必须包含丢失文件的名称,以便我可以检查文件是核心文件还是可选文件。
Any Ideas?
有任何想法吗?
回答by Alexander O'Mara
To capture all error
events on the page, you can use addEventListener
with the useCapture
argument set to true
. The reason window.onerror
will not do this is because it uses the bubble event phase, and the error
events you want to capture do not bubble.
要捕获error
页面上的所有事件,您可以addEventListener
将useCapture
参数设置为true
。之所以window.onerror
不会这样做,是因为它使用了冒泡事件阶段,而error
您要捕获的事件不会冒泡。
If you add the following script to your HTML before you load any external content, you should be able to capture all the error
events, even when loading offline.
如果您在加载任何外部内容之前将以下脚本添加到您的 HTML 中,您应该能够捕获所有error
事件,即使在离线加载时也是如此。
<script type="text/javascript">
window.addEventListener('error', function(e) {
console.log(e);
}, true);
</script>
You can access the element that caused the error through e.target
. For example, if you want to know what file did not load on an img
tag, you can use e.target.src
to get the URL that failed to load.
您可以通过 访问导致错误的元素e.target
。例如,如果您想知道img
标签上没有加载哪个文件,您可以使用e.target.src
获取加载失败的 URL。
NOTE: This technically will not detect the error code, it detects if the image failed to load, as it technically behaves the same regardless of the status code. Depending on your setup this would probably be enough, but for example if a 404 is returned with a valid image it will not trigger an error event.
注意:这在技术上不会检测错误代码,它会检测图像是否加载失败,因为无论状态代码如何,它在技术上的行为都是相同的。根据您的设置,这可能就足够了,但例如,如果使用有效图像返回 404,则不会触发错误事件。
回答by Santoo
I've put together the code below in pure JavaScript, tested, and it works. All the source code (html, css, and Javascript) + images and example font is here: on github.
我已经将下面的代码放在纯 JavaScript 中,经过测试,它可以工作。所有源代码(html、css 和 Javascript)+图像和示例字体都在这里:在 github 上。
The first code block is an object with methods for specific file extensions: html
and css
.
The second is explained below, but here is a short description.
第一个代码块是一个对象,具有特定文件扩展名的方法:html
和css
. 第二个在下面解释,但这里是一个简短的描述。
It does the following:
它执行以下操作:
- the function
check_file
takes 2 arguments: a string path and a callback function. - gets the contents of given path
- gets the file extension (
ext
) of the given path - calls the
srcFrom
[ext
] object method that returns an array of relative paths that was referenced in the string context bysrc
,href
, etc. - makes a synchronous call to each of these paths in the paths array
- halts on error, and returns the HTTP error message and the path that had a problem, so you can use it for other issues as well, like 403 (forbidden), etc.
- 该函数
check_file
有两个参数:一个字符串路径和一个回调函数。 - 获取给定路径的内容
- 获取
ext
给定路径的文件扩展名 ( ) - 调用
srcFrom
[ext
返回相对路径的阵列是在字符串上下文通过引用]对象的方法src
,href
等 - 对路径数组中的每个路径进行同步调用
- 出错时暂停,并返回 HTTP 错误消息和出现问题的路径,因此您也可以将其用于其他问题,例如 403(禁止)等。
For convenience, it resolves to relative path names and does not care about which protocol is used (http or https, either is fine). It also cleans up the DOM after parsing the CSS.
为方便起见,它解析为相对路径名并且不关心使用哪个协议(http 或 https,都可以)。它还在解析 CSS 后清理 DOM。
var srcFrom = // object
{
html:function(str)
{
var prs = new DOMParser();
var obj = prs.parseFromString(str, 'text/html');
var rsl = [], nds;
['data', 'href', 'src'].forEach(function(atr)
{
nds = [].slice.call(obj.querySelectorAll('['+atr+']'));
nds.forEach(function(nde)
{ rsl[rsl.length] = nde.getAttribute(atr); });
});
return rsl;
},
css:function(str)
{
var css = document.createElement('style');
var rsl = [], nds, tmp;
css.id = 'cssTest';
css.innerHTML = str;
document.head.appendChild(css);
css = [].slice.call(document.styleSheets);
for (var idx in css)
{
if (css[idx].ownerNode.id == 'cssTest')
{
[].slice.call(css[idx].cssRules).forEach(function(ssn)
{
['src', 'backgroundImage'].forEach(function(pty)
{
if (ssn.style[pty].length > 0)
{
tmp = ssn.style[pty].slice(4, -1);
tmp = tmp.split(window.location.pathname).join('');
tmp = tmp.split(window.location.origin).join('');
tmp = ((tmp[0] == '/') ? tmp.substr(1) : tmp);
rsl[rsl.length] = tmp;
}
});
});
break;
}
}
css = document.getElementById('cssTest');
css.parentNode.removeChild(css);
return rsl;
}
};
And here is the function that gets the file contents and calls the above object method according to the file extension:
下面是获取文件内容并根据文件扩展名调用上述对象方法的函数:
function check_file(url, cbf)
{
var xhr = new XMLHttpRequest();
var uri = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function()
{
var ext = url.split('.').pop();
var lst = srcFrom[ext](this.response);
var rsl = [null, null], nds;
var Break = {};
try
{
lst.forEach(function(tgt)
{
uri.open('GET', tgt, false);
uri.send(null);
if (uri.statusText != 'OK')
{
rsl = [uri.statusText, tgt];
throw Break;
}
});
}
catch(e){}
cbf(rsl[0], rsl[1]);
};
xhr.send(null);
}
To use it, simply call it like this:
要使用它,只需像这样调用它:
var uri = 'htm/stuff.html'; // html example
check_file(uri, function(err, pth)
{
if (err)
{ document.write('Aw Snap! "'+pth+'" is missing !'); }
});
Please feel free to comment and edit as you wish, i did this is a hurry, so it may not be so pretty :)
请随意评论和编辑,我这样做很匆忙,所以它可能不那么漂亮:)
回答by Zeronex
you can use the onloadand onerrorattributes to detect the error
您可以使用onload和onerror属性来检测错误
for example upon loading the following html it gives alert error1and error2you can call your own function e.g onerror(logError(this);)
and record them in an Array and once the page is fully loaded post is with single Ajax call.
例如,在加载以下 html 时,它会给出警报error1和error2,您可以调用自己的函数,例如onerror(logError(this);)
,将它们记录在一个数组中,一旦页面完全加载,post 将使用单个 Ajax 调用。
<html>
<head>
<script src="file:///SSC_Temp/html_005/temp/Support/jquery.js" onerror="alert('error1');" onload="alert('load');" type="text/javascript" ></script>
</head>
<body>
<script src="file:///SSC_Temp/html_005/temp/Support/jquery.js" onerror="alert('error2');" onload="alert('load');" type="text/javascript" ></script>
</body>
</html>
回答by centurian
@alexander-omara gave the solution.
@alexander-omara 给出了解决方案。
You can even add it in many files but the window handler can/should be added once.
您甚至可以将它添加到许多文件中,但窗口处理程序可以/应该添加一次。
I use the singleton patternto achieve this:
我使用单例模式来实现这一点:
some_global_object = {
error: (function(){
var activate = false;
return function(enable){
if(!activate){
activate = true;
window.addEventListener('error', function(e){
// maybe extra code here...
// if(e.target.custom_property)
// ...
}, true);
}
return activate;
};
}());
Now, from any context call it as many times you want as the handler is attached only once:
现在,从任何上下文调用它你想要的次数,因为处理程序只附加一次:
some_global_object.error();