Как обнаружить на странице 404 ошибки с помощью JavaScript? - PullRequest
22 голосов
/ 14 декабря 2011

У меня есть HTML-страница, на которой есть ссылки на несколько файлов JavaScript, CSS и изображений. Эти ссылки вводятся динамически, и пользователь может вручную скопировать HTML-страницу и файлы поддержки на другой компьютер.

Если некоторые JS или CSS отсутствуют, браузер жалуется в консоли. Например:

Ошибка GET-файла: /// E: /SSC_Temp/html_005/temp/Support/jquery.js

Мне нужно как-нибудь сообщить об этих ошибках мне на встроенном JavaScript-коде HTML-страницы, чтобы я мог попросить пользователя сначала проверить, правильно ли скопированы файлы поддержки.

Это событие window.onerror, которое просто сообщает мне, что на странице есть ошибка JS, такая как непредвиденная синтаксическая ошибка, но она не срабатывает в случае ошибки 404 Not Found . Я хочу проверить это условие в случае любого типа ресурса, включая CSS, JS и изображения.

Мне не нравится использовать jQuery AJAX для проверки того, что файл физически существует - накладные расходы ввода-вывода являются дорогостоящими для каждой загрузки страницы.

Отчет об ошибке должен содержать имя файла, отсутствующего , чтобы я мог проверить, является ли файл основным или необязательным.

Есть идеи?

Ответы [ 5 ]

49 голосов
/ 27 февраля 2015

Чтобы захватить все error события на странице, вы можете использовать addEventListener с аргументом useCapture, установленным в true. Причина, по которой window.onerror не будет этого делать, заключается в том, что он использует фазу пузырькового события, а события error, которые вы хотите захватить, не пузыриваются.

Если вы добавите следующий скрипт в свой HTML-код перед загрузкой какого-либо внешнего контента, вы сможете захватить все события error, даже при загрузке в автономном режиме.

<script type="text/javascript">
window.addEventListener('error', function(e) {
    console.log(e);
}, true);
</script>

Вы можете получить доступ к элементу, вызвавшему ошибку, через e.target. Например, если вы хотите узнать, какой файл не был загружен в тег img, вы можете использовать e.target.src, чтобы получить URL, который не удалось загрузить.

ПРИМЕЧАНИЕ: Технически это не обнаружит код ошибки, он обнаружит, если изображение не удалось загрузить, поскольку оно технически ведет себя одинаково, независимо от кода состояния. В зависимости от вашей настройки этого, вероятно, будет достаточно, но, например, если 404 возвращается с действительным изображением, это не вызовет событие ошибки.

4 голосов
/ 06 марта 2015

Я собрал приведенный ниже код в чистом JavaScript, протестировал, и он работает.Весь исходный код (html, css и Javascript) + images и пример шрифта находятся здесь: на github .

Первый блок кода - это объект с методами для определенных расширений файлов: html и css.Второй поясняется ниже, но здесь есть краткое описание.

Это делает следующее:

  • функция check_file принимает 2 аргумента: путь строки и функцию обратного вызова.
  • получает содержимое заданного пути
  • получает расширение файла (ext) по указанному пути
  • вызывает метод объекта srcFrom [ext], которыйвозвращает массив относительных путей, на которые ссылались в строковом контексте src, href и т. д.
  • выполняет синхронный вызов для каждого из этих путей в массиве путей
  • haltsоб ошибке и возвращает сообщение об ошибке HTTP и путь, по которому возникла проблема, так что вы можете использовать его и для других проблем, таких как 403 (запрещено) и т. д.

Для удобства он разрешаетсяотносительные имена путей и не заботится о том, какой протокол используется (http или https, либо в порядке).Он также очищает DOM после анализа CSS.

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;
    }
};

А вот функция, которая получает содержимое файла и вызывает вышеуказанный объектный метод в соответствии с расширением файла:

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);
}

Чтобы использовать это, просто назовите это так:

var uri = 'htm/stuff.html';    // html example

check_file(uri, function(err, pth)
{
    if (err)
    { document.write('Aw Snap! "'+pth+'" is missing !'); }
});

Пожалуйста, не стесняйтесь комментировать и редактировать, как вы хотите, я сделал это спешка, так что это может быть не так красиво:)

3 голосов
/ 04 марта 2015

Вы можете использовать атрибуты onload и onerror для обнаружения ошибки

например, при загрузке следующего html выдает предупреждение error1 и error2 , вы можете вызвать свою собственную функцию, например, onerror(logError(this);) и записать их в массив, и как только страница полностью заполнится загруженное сообщение с одним вызовом 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>
0 голосов
/ 02 ноября 2018

@ alexander-omara дал решение.

Вы можете даже добавить его во многие файлы, но обработчик окна можно / нужно добавить один раз.

Я использую шаблон singleton для достижения этой цели:

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;
     };
  }());

Теперь из любого контекста вызывайте его столько раз, сколько вы хотите, так как обработчик подключен только один раз :

some_global_object.error();
0 голосов
/ 27 февраля 2015

Вы можете использовать XMLHttpRequest для файлов.

var oReq = new XMLHttpRequest();
oReq.addEventListener("error", transferFailed, false);

function transferFailed(evt) {
  alert("An error occurred while transferring the file.");
}

client.open("GET", "unicorn.xml");
client.send();

и использовать класс Image для изображений.

var img1 = new Image();
img1.src = 'http://yourdomain.net/images/onethatdoesnotexist.gif';
img1.onerror = function () { alert( 'Image not loaded' ); };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...