Практика анализа ошибок JavaScript во внешнем интерфейсе

внешний интерфейс JavaScript

Автор: красный красавчик

предисловие

В повседневной работе front-end badjs — довольно распространенная проблема.Помимо очевидных ошибок в js-скриптах нашего бизнеса, в badjs также есть некоторые ошибки, зависящие от других ресурсов.Ошибки легко найти и исправить в собственном бизнесе. js., но не так просто найти ошибки, зависящие от ресурсов, то есть общие ошибки скрипта (внешние js, ошибки интерфейса).

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

Происхождение ошибки скрипта

Наши страницы часто хранят статические ресурсы (js, css, изображения) в сторонней CDN или полагаются на внешние статические ресурсы. Когда возникает ошибка при выполнении javascript, загруженного от третьей стороны, из-за политики того же источника, чтобы гарантировать, что информация о пользователе не просочится, подробная информация об ошибке не будет возвращена, а вместо этого будет возвращена ошибка скрипта. .

исходный код вебкита:

bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL) {
  KURL targetURL = completeURL(sourceURL);

  if (securityOrigin()->canRequest(targetURL)) return false;
  // 非同源,将相关的错误信息设置成默认,错误信息置为 Script error,行号置成0
  errorMessage = "Script error.";
  sourceURL = String();
  ineNumber = 0;
  return true;
}

bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int lineNumber, const String& sourceURL) {
  EventTarget* target = errorEventTarget();
  if (!target) return false;
  String message = errorMessage;
  int line = lineNumber;
  String sourceName = sourceURL;
  sanitizeScriptError(message, line, sourceName);
  ASSERT(!m_inDispatchErrorEvent);
  m_inDispatchErrorEvent = true;
  RefPtr<ErrorEvent> errorEvent = ErrorEvent::create(message, sourceName, line);
  target->dispatchEvent(errorEvent);
  m_inDispatchErrorEvent = false;
  return errorEvent->defaultPrevented();
}

Общие решения

Существует два распространенных метода составления подробных журналов ошибок для ошибок внешних скриптов:

1. Включите совместное использование ресурсов между доменами CORS.

а) Добавьте атрибут crossorigin="anonymous":

<script src="http://domain/path/*.js" crossorigin="anonymous"></script>

При наличии crossorigin="anonymous" браузер получает целевой скрипт анонимно и не отправляет информацию о пользователе (куки, http-сертификаты и т. д.) на сервер при запросе скрипта.

б) На этом этапе статическому серверу необходимо добавить заголовок междоменного протокола:

Access-Control-Allow-Origin: *

После выполнения этих двух шагов window.onerror может собирать подробную информацию об ошибке при возникновении соответствующей ошибки междоменного сценария.

2. try catch

crossorigin="anonymous" действительно может прекрасно решить проблему сообщения об ошибках сценария badjs, но для этого требуется поддержка междоменных заголовков на стороне сервера, и часто на крупных предприятиях количество доменных имен возмутительно, что приводит к очень сложным кросс- конфигурация правила домена, поэтому сложно выполнить все все настроено, и некоторые внешние ресурсы, которые зависят от них, не могут быть гарантированно поддержаны, поэтому мы используем упаковку try catch при вызове методов внешних ресурсов и некоторые методы ресурсов, которые не подтверждают, настроить междоменные заголовки и сообщить о соответствующей ошибке при обнаружении проблемы.

function invoke(obj, method, args) {
  try {
    return obj[method].apply(this, args);
  } catch (e) {
    reportBadjs(e); // report the error
  }
}

Анализ случая

1. Для ресурсов со статическими правами на конфигурацию сервера мы можем единообразно настраивать и поддерживать междоменные заголовки, а также единообразно добавлять crossorigin="anonymous" при запросе, чтобы можно было точно сообщать соответствующую информацию о стеке ошибок.

2. Проблема с запросом jsonp.

Чтобы решить междоменную проблему в запросах страниц, наш интерфейс страницы часто использует jsonp для получения данных.Существуют две ситуации, в которых badjs обычно вызывается запросом jsonp:

  • а) Запрос интерфейса является ненормальным. В сети часто встречается ошибка 302, которая возвращает страницу с ошибкой при наличии ненормального интерфейса. В этом случае ошибка скрипта напрямую вызвана тем, что возвращаемый контент не может быть проанализирован; В этом случае, хотя мы не можем напрямую подробно сообщить об ошибке сценария, мы можем сообщить об ошибке интерфейса в соответствии с загрузкой обратного вызова и интерфейсом загрузки.Конкретный метод выглядит следующим образом:
// 资源加载完成触发 onload 事件
el.onload = el.onreadystatechange = function () {
 	if(!cgiloadOk) { // 没有正常的回调,则上报对应的错误信息
 		report(cgi, 'servererror');
 	}
}

window.newFunction = function(rsp) {
 	cgiloadOk = true;
 	window.originFunction(rsp);
}

Как и в приведенном выше псевдокоде, мы перехватываем функцию обратного вызова пользователя, помечаем функцию обратного вызова, запускаем onload при загрузке ресурса, а затем оцениваем, нормально ли вызывается интерфейс при загрузке, если нормального обратного вызова нет, то сообщаем соответствующее сообщение об ошибке cgi и определения. Таким образом, можно объединить ошибку сервера в системе мониторинга, чтобы проанализировать, поднимается ли страница badjs из-за интерфейса, и в то же время сообщить о соответствующей проблеме соответствующему ответственному лицу интерфейса, чтобы избежать страницы аномалия, вызванная подключением интерфейса к сети или проблемой работы в сети.

  • б) Интерфейс возвращает исключение данных (нестандартный json), что также напрямую приведет к ошибке скрипта.

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

  let sc = document.createElement('script');
  let head = document.getElementsByTagName('head')[0];
  sc.setAttribute('charset', charset || 'utf-8');
  sc.src = url;
  head.appendChild(sc);

  window.newFunction = function(text) {
    // 采用try catch捕获异常
    try {
      let jsonStr = JSON.parse(text)
    } catch(e) {
      // 出现转换异常,则将对应的错误数据进行上报
      reportBadjs(text);
    }
  }

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

3. Метод запроса Ajax.

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

let xmlHttp = new XMLHttpRequest();

xmlHttp.onreadystatechange = function() {
 	if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
 		let str = xmlHttp.responseText;
 		try {
 			let json = JSON.parse(jsonstr);
 			//TODO,渲染对应的数据
 		} catch(e) {
 			report(jsonstr, 'data parse err'); // 数据解析错误,则将原数据进行上报,用于错误分析,修正接口返回
 		}
 	} else if (xmlHttp.readyState == 4) {
 		report(cgi, xmlHttp.status); // 接口返回重定向,则将对应的接口以及对应的status进行上报
 	}
}

xmlHttp.open('GET', cgi, true);            
xmlHttp.send();

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

4. Зависимые внешние ресурсы не поддерживают настройку междоменных заголовков.

В этом случае мы можем использовать только try catch для перехвата и сообщения об исключениях при вызове методов внешних ресурсов.

Наиболее часто используемые в повседневной работе jqeury и zepto могут быть упакованы следующими способами:

function myBind (obj) {
  let o = {
    'type': 'click', // 事件类型
    'src': '.', // jquery 选择器
    'fun': function () {}, // 方法
    'isStop': true // 阻止事件冒泡
  };
  let i;

  for (i in obj) {
    o[i] = obj[i];
  }

  if (typeof o.src === 'string') {
    o.$src = $(o.src);
  }

  $(o.src).off(o.type).on(o.type, function (e) {
    try {
      o.fun.apply(o, [e, $(this)]);
    } catch (ea) {
      reportBadjs(ea.stack);  //上报错误
    }
    if (o.isStop) {
      return false;
    }
  });
}

Альтернативные аналитические идеи

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

1. Анализ клиента

а) Доля каналов:

Анализ на стороне клиента в основном основан на статистическом анализе, основанном на ua, который сообщает об ошибке скрипта. Доля канала — это доля ошибки скрипта страницы каждого канала, например конец WeChat, конец sq, конец H5 (другие браузеры). Вы можете судить о том, является ли ошибка сценария определенного канала нормальной, в зависимости от доли трафика страницы, например: когда в определенный момент времени количество баджей внезапно возрастает, а выпуска нет, когда на трафик WeChat приходится подавляющее большинство, а канал sq или другие каналы значительно увеличиваются, можно сделать вывод, что баджы могут быть вызваны движением щетки, и оказывается, что это часто имеет место. На следующем рисунке показана доля каждого канала баджей при обычных запросах.

На следующем рисунке показана доля баджей каждого канала при возникновении исключения.

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

б) пропорция ua:

Пропорция ua анализировать долю каждого ua.Поскольку дистрибутив ua относительно разбросан и версий клиентов много, то узнать по нему вообще не просто, но когда выйдет определенная версия, если определенная ua пропорция очевидна, можно сделать вывод, что может быть несовместимость с клиентом при написании js (часто используется для нового синтаксиса, и каждый клиент поддерживает свой синтаксис).

2. В сочетании с анализом поведения пользователей

а) Записывать действия пользователя (клики) на примере мобильного терминала:

  let eventElemArr = [];
  document.body.addEventListener('touchend', function (e) {
    // 记录点击的dom相关信息
    eventElemArr.push([e.target.tagName, className].join('_'));
  }, false);

  window.onerror = function(msg, url='', line='', col='', error='') {
    // 将用户点击dom相关信息拼接到错误信息中并进行上报
    let errStr = [JSON.stringify(msg), url, line , col, error, eventElemArr.join('|')].join('$');
    report(errStr);
    return false;
  };

В системе анализа мы объединяем поведение пользователя на странице, чтобы определить, является ли страница, которую пользователь посещает в данный момент, нормальной.

б) Ошибка сценария часто обновляется, клиентский анализ может только сделать вывод, вызвана ли ошибка (кистью) из-за операции исключения, но он действительно хочет подтвердить, что BadJS влияет на страницу, влияет на нормальную работу пользователя, может судить с сервером. Конкретная идея заключается в том, чтобы войти на страницу, внешний интерфейс генерирует traceid (генерация TraceID может быть временной меткой + сервис + случайный код, базовый уникальный), страница запрашивает все интерфейсы для получения traceID и фоновой записи, соответствующей журналу (вы также может сообщать о фронте Когда сообщается отчетность BADJS, TRACEID будет сообщен, так что общая запись доступа будет записана, когда пользователь появится (TRACEID).

  // 页面配置场景值,用于生成traceid
  window.initTraceid = {
    bizId // 页面bizId
    operateId // 页面traceid
  }

  // 公共代码(公共头)生成traceid
  (function(){
    window.initTraceid {
      window.traceid = genTraceid(window.initTraceid);
    }
  })()

  // 上报badjs时带上对应的traceid
  window.onerror = function(msg, url='', line='', col='', error='') {
    let errStr = [JSON.stringify(msg), url, line , col, error, window.traceid || ''].join('$');
    report(errStr);
    return false;
  };

  // 请求接口带上对应的traceid,用于与badjs进行关联,这样就可以记录用户进入页面页面接口的请求状况
  function myRequst(url) {
    url = url.addParam({traceid: window.traceid || ''});
    requst(url);
  }

Этот метод может сопоставлять статус запроса интерфейса, когда пользователь входит на страницу, в соответствии с идентификатором трассировки в badjs, который используется для определения наличия проблемы с доступом пользователя к странице. Например, если вы часто сталкиваетесь с ошибками сценария на работе, вы можете запросить журнал ошибок за период времени, а затем запросить записи доступа через traceid.Часто ошибка сценария вызвана тем, что у популярного продукта были очень плохо почищены, и некоторые кисти не являются дефектами страницы, вызванными нормальной работой.

3. Восстановление на месте

3.1 Запись видео

Когда возникает ошибка сценария, снимок экрана пользователя, заходящего на страницу, записывается как видео и сообщается вместе с ошибкой сценария. В настоящее время существует два основных способа реализации этой функции: один — использовать рисование на холсте для захвата изображений экрана, второй — записывать изменения домена страницы, сообщать о соответствующих записях, а затем воспроизводить их в системе анализа на основе моментальных снимков и изображений. цепочки операций.

а) Холст для захвата изображений. Идея этого метода заключается в использовании холста для создания изображений с веб-страниц, а затем их кэширования. Чтобы сделать сгенерированные видео плавными, нам нужно генерировать около 25 кадров в секунду, что То есть нужно 25 скриншотов, а потом при их появлении При возникновении ошибки скрипта будет сообщено о кешированном изображении страницы, а затем просмотр страницы восстановится через технологию в системе анализа.

Недостаток этого метода очевиден: если пользователь долго находится на странице, будет сгенерировано большое количество картинок, что принесет много накладных расходов на сеть и хранение.

б) воспроизведение операции пользователя

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

Общая идея такова:

  1. Войдите на страницу и сгенерируйте виртуальный полный снимок страницы в DOM;

  2. Используйте API: MutationObserver, запишите измененный пользователем дом и запишите некоторые операции пользователя со строками (щелчок, выбор, ввод, прокрутка и т. д. события);

3) При возникновении ошибки сценария будет сообщена соответствующая информация о моментальном снимке;

4) Восстановить снимки и пользовательские операции в системе анализа.

3.2 Отчет о данных страницы

Этот метод очень удобен на страницах, использующих фреймворки, управляемые данными (vue, react), когда происходит ошибка, вместе с ошибкой может быть сообщена информация о фронтенде страницы, а затем страница восстанавливается через определенное время. технологии в системе анализа, и появляется повторяющаяся страница, о которой идет речь.

Отчеты по журналам, статистика, анализ и мониторинг

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

1. Отчет журнала

  // 全局的 onerror 用于捕获页面异常
  window.onerror = function(msg, url, line, col, error) {
    let excludeList = ['WeixinJSBrige']; // 剔除一些确认的本身客户端引起的问题,避免对上报后的数据分析引起干扰
    // 拼接错误信息
    let errStr = obj2str(msg) + (url ? ';URL:' + url : '') + (line ? ';Line:' + line : '') + (col ? ';Column:' + col : ''
    // 剔除白名单内错误上报,避免对上报结果干扰
    for (let item in excludeList) {
      if (errStr.indexof(item) > -1) {
        return;
      }
    }
    // 构造图片请求,用于上报
    let g = new Image()
    // 存在 traceid 则拼接 traceid 用于日志串联
    g.src = reportUrl + errStr + '&t=' + Math.random()+(window.traceid ? '&traceid=' + window.traceid : '')
  }
    return false;
};

"Для использования промисов и сам фреймворк (vue, react) будет перехватывать ошибки, нужно добавить соответствующий метод для ручной отчетности"

// promise 错误上报
window.addEventListener('rejectionhandled', event => {
  // 错误的详细信息在 reason 字段
  window.onerror('', '', '', '', event.reason)
});

// vue 错误上报
Vue.config.errorHandler = function (err, vm, info) {
  window.onerror(info, '', '', '', err)
}
// ...其他的就不一一列举了

Для сбора логов на стороне сервера, помимо отчётных логов, нужно собирать IP, userinfo, traceid, netType, ua, время и т.д. по запросу.

2. Статистика и анализ журнала

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

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

c) Подробное отображение журнала; подсчитывается подробная информация журнала ошибок. Благодаря подробной информации вы можете просмотреть пользовательский канал, тип сети, информацию о пользователе, информацию о пользователях и т. д., когда возникает ошибка. доступ к странице нормальный.

г) многомерный статистический анализ (оператор, пользователь, модель, сеть, система, канал и т. д.); благодаря многомерному статистическому агрегированию можно напрямую просматривать ошибки, отображаемые в различных измерениях (например, каналы в альтернативных идеях анализа). ) ratio, ua ratio), чтобы помочь проанализировать проблемы с позиционированием.

3. Мониторинг ошибок

В работе автора badjs подразделяются на обычные badjs и servererror колебания badjs и servererror в зависимости от того, вызваны ли они интерфейсом. Обычные badjs могут помочь в обнаружении и устранении в соответствии с соответствующим журналом и представлением анализа.В случае ошибки сервера соответствующий ответственный за интерфейс уведомляется о поиске и устранении проблемы. Два ключа (badjs и serveerror) автоматически генерируются для каждой страницы при ее создании. badjs и servererror), после сообщения о badjs ссылкой является URL-адрес страницы, а служба анализа выполняет расчет агрегации в соответствии с URL-адресом страницы для мониторинга в режиме реального времени.

а) Настройка правил. Мы установили правила будильника: сигнал тревоги желтого света и сигнал тревоги красного света.Желтый свет используется в качестве напоминания, а красный свет-это серьезная тревога.Когда правило срабатывает, оно автоматически отправляет сообщение соответствующему ответственному лицу. и подайте сигнал тревоги, чтобы можно было быстро отреагировать на проблему и решить ее.

На следующем рисунке показана конфигурация правила оповещения badjs:

На следующем рисунке показана конфигурация правила оповещения об ошибке сервера:

б) просмотр мониторинга. На следующем рисунке показан глюк badjs, вызванный определенной версией публичной страницы (обычный badjs, не влияющий на нормальный доступ к странице). Сразу после получения сигнала откатите версию, найдите проблему и устраните ее, а затем снова подключитесь к сети.

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

конец

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

использованная литература


Если вы считаете, что этот контент ценен для вас, пожалуйста, поставьте лайк и подпишитесь на нашуОфициальный сайтА на нашем официальном аккаунте WeChat (WecTeam) каждую неделю публикуются качественные статьи:

WecTeam

IMG10.360 не запускается с определенным.com/completely/jinfoshan/he1/4…