JavaScript 오류를 캡처하고 분석하는 방법
프론트 엔드 엔지니어는 모두 JavaScript에 기본 예외 처리 기능이 있음을 알고 있습니다. 새로운 오류 ()를 던질 수 있으며 브라우저는 API 오류를 호출 할 때 예외를 던집니다. 그러나 대부분의 프론트 엔드 엔지니어는 이러한 예외적 인 정보를 수집하는 것을 고려하지 않은 것으로 추정됩니다. 어쨌든, JavaScript 오류 후 새로 고침이 재현되지 않는 한, 사용자는 새로 고침으로 문제를 해결할 수 있으며 브라우저가 충돌하지 않으며 발생하지 않으면 괜찮습니다. 이 가정은 단일 페이지 앱이 인기를 얻기 전에 사실이었습니다. 현재 단일 페이지 앱은 일정 시간 동안 실행 한 후에 매우 복잡합니다. 이전 작업을 완전히 재 작업하지 않겠습니까? 따라서 이러한 예외 정보를 캡처하고 분석해야하며 사용자 경험에 영향을 미치지 않도록 코드를 수정할 수 있습니다.
예외를 포착하는 방법
우리는 스스로 새로운 오류를 썼다. 그러나 브라우저 API를 호출 할 때 발생하는 예외는 반드시 포착하기 쉬운 것은 아니며 일부 API는 구현 차이 또는 결함으로 인해 개별 브라우저가 예외 만 발생한다고 말합니다. 전자의 경우 우리는 시도 캐치를 통해 그것을 잡을 수 있습니다. 후자는 전 세계 예외를 듣고 잡아야합니다.
Try-Catch
일부 브라우저 API가 예외를 던지는 것으로 알려져있는 경우, 오류로 인해 불법 상태에 들어가는 전체 프로그램이 불법 상태로 들어가는 것을 피하기 위해 Try-Catch에 전화를 걸어야합니다. 예를 들어, Window.localStorage는 API입니다. 데이터 작성이 용량 제한을 초과 한 후에도 예외가 발생합니다.
코드 사본은 다음과 같습니다.
노력하다 {
LocalStorage.setitem ( 'date', date.now ());
} catch (오류) {
리포터 (오류);
}
또 다른 일반적인 Try-Catch 해당 시나리오는 콜백입니다. 콜백 함수의 코드는 통제 할 수 없기 때문에 코드가 얼마나 좋은지, 예외를 제외하고 다른 API가 호출되는지 여부를 알 수 없습니다. 콜백 오류로 인해 콜백을 호출 한 후 다른 코드가 실행되지 않으려면 통화를 다시 시도 캐치로 다시 넣어야합니다.
코드 사본은 다음과 같습니다.
청취자 .foreach (기능 (청취자) {
노력하다 {
경청자();
} catch (오류) {
리포터 (오류);
}
});
Window.onerror
Try-Catch를 다룰 수없는 장소의 경우 예외가 발생하면 Window.onerror를 통해서만 캡처 할 수 있습니다.
코드 사본은 다음과 같습니다.
Window.onerror =
함수 (errormessage, scripturi, linenumber) {
리포터 ({{
메시지 : errormessage,
대본 : Scripturi,
라인 : LineNumber
});
}
영리하지 않고 Window.AdDeventListener 또는 Window.attachevent를 사용하여 Window.onerror를 들어보십시오. 많은 브라우저는 Window.Onerror 또는 Window 만 구현합니다. ONERROR 구현은 표준입니다. 표준 드래프트가 Window.onerror를 정의하는 것을 고려하면 Window.onerror를 사용하면됩니다.
속성 누락
잡힌 예외를 수집 한 후 쿼리 및 분석을 위해 서버 측 스토리지에 배치로 전송하는 리포터 기능이 있다고 가정 해 봅시다. 수집하려는 정보는 무엇입니까? 보다 유용한 정보에는 오류 유형 (이름), 오류 메시지 (메시지), 스크립트 파일 주소 (스크립트), 줄 번호 (줄), 열 번호 (열) 및 스택 추적이 포함됩니다. Try-Catch를 통해 예외가 발생하면 이러한 모든 정보는 오류 개체 (주류 브라우저에서 지원)에 있으므로 Reporterror 도이 정보를 수집 할 수 있습니다. 그러나 Window.onerror를 통해 캡처되면이 이벤트 기능에는 3 개의 매개 변수 만 있으므로이 3 개의 매개 변수 이외의 정보가 손실됩니다.
메시지 직렬화
오류 객체가 스스로 생성되면 오류. 메신저는 당사에 의해 제어됩니다. 기본적으로, 우리가 오류에 넣은 것. message, 그리고 Window.onerror의 첫 번째 매개 변수 (메시지)가 될 것입니다. (브라우저는 실제로 'uppher error :'prefix를 추가하는 것과 같은 약간의 수정을합니다. 따라서 우리는 우리가 관련된 속성을 직렬화하고 (예 : json.stringify) 오류에 저장 한 다음 읽기를 읽을 수 있습니다. 창에서. 물론 이것은 우리가 만든 오류 객체로 제한됩니다.
다섯 번째 매개 변수
브라우저 제조업체는 또한 Window.onerror를 사용할 때 사람들이 적용하는 제한 사항을 알고 있으므로 Window.onerror에 새 매개 변수를 추가하기 시작합니다. 행 번호와 열 숫자만이 매우 대칭적인 것으로 보인다는 점을 고려하면 먼저 열 숫자를 추가하여 네 번째 매개 변수에 배치했습니다. 그러나 모든 사람이 더 염려하는 것은 완전한 스택을 얻을 수 있는지 여부입니다. 그러나 Chrome은 전체 오류 객체를 5 번째 매개 변수에 넣는 것이 좋습니다. 결과적으로 Chrome이 빠르기 때문에 새로운 창이 더 빠르기 때문에 Crome 30에서 정기 서명이 구현되어 다음과 같은 표준 초안을 작성했습니다.
코드 사본은 다음과 같습니다.
Window.onerror = 함수 (
errormessage,
Scripturi,
Linenumber,
칼럼 번호,
오류
) {
if (오류) {
리포터 (오류);
} 또 다른 {
리포터 ({{
메시지 : errormessage,
대본 : Scripturi,
라인 : LineNumber,
열 : 칼럼 번호
});
}
}
속성의 규칙 성
이전에 논의한 오류 객체 속성의 이름은 크롬 이름 지정 방법을 기반으로합니다. 예를 들어 오류 객체 속성을 다르게 이름을 지정합니다. 따라서 오류 객체를 정규화하려면 특수 함수가 필요합니다. 즉 다른 속성 이름을 통합 된 속성 이름에 매핑합니다. 특정 관행은이 기사를 참조하십시오. 브라우저 구현이 업데이트되지만 인간이 그러한 매핑 테이블을 유지하는 것은 그리 어렵지 않습니다.
스택 추적 형식도 비슷합니다. 이 속성은 각 브라우저에서 사용하는 텍스트 형식이 다르기 때문에 예외의 스택 정보를 저장합니다. . 이름 (식별자), 파일 (스크립트), 줄 (줄) 및 열 (열).
보안 제한
또한 '스크립트 오류'에 오류가 발생한 경우, 내가 말하는 내용을 이해할 수 있습니다. 이것은 실제로 다른 소스의 스크립트 파일에 대한 브라우저의 한계입니다. 이 보안 제한의 이유는 다음과 같습니다. 로그인 한 후 온라인 은행가가 반환 한 HTML이 익명 사용자가 보이는 HTML과 다르다고 가정하면 타사 웹 사이트 가이 온라인 은행의 URI를 스크립트에 넣을 수 있습니다. SRC 속성. 물론 HTML은 JS로 구문 분석 할 수 없으므로 브라우저는 예외를 던지고이 타사 웹 사이트는 예외의 위치를 분석하여 사용자가 로그인되는지 여부를 결정할 수 있습니다. 이러한 이유로 브라우저는 다른 소스 스크립트 파일에 의해 던져진 모든 예외를 필터링하여 '스크립트 오류'와 같은 변경되지 않은 메시지 만 남겨두고 다른 모든 속성은 사라집니다.
특정 규모의 웹 사이트의 경우 스크립트 파일이 CDN에 배치되는 것이 일반적이며 다른 소스가 배치됩니다. 이제 작은 웹 사이트를 직접 구축하더라도 JQuery 및 Backbone과 같은 일반적인 프레임 워크는 공개 CDN의 버전을 직접 참조하여 사용자 다운로드 속도를 높일 수 있습니다. 따라서이 보안 제한으로 인해 약간의 문제가 발생하여 Chrome 및 Firefox에서 수집 한 예외 정보가 쓸모없는 '스크립트 오류'가됩니다.
코스
이 제한을 우회하려면 스크립트 파일과 페이지 자체가 동일했는지 확인하십시오. 그러나 CDN에 의해 가속되지 않은 서버에 스크립트 파일을 배치하지 않으면 사용자의 다운로드 속도가 줄어 듭니까? 한 가지 해결책은 Script 파일을 CDN에 계속 배치하고 XMLHTTPREQUEST를 사용하여 CORS를 통해 컨텐츠를 다시 다운로드 한 다음 <Script> 태그를 작성하여 페이지에 주입하는 것입니다. 페이지에 내장 된 코드는 물론 같은 원점입니다.
이것은 간단하지만 구현해야 할 세부 사항이 많이 있습니다. 간단한 예를 들기 위해 :
코드 사본은 다음과 같습니다.
<script src = "http://cdn.com/step1.js"> </script>
<cript>
(함수 step2 () {}) ();
</스크립트>
<script src = "http://cdn.com/step3.js"> </script>
우리는 모두 1, step2 및 step3에 종속성이 있으면이 순서로 엄격하게 실행되어야한다는 것을 알고 있습니다. 그렇지 않으면 오류가 발생할 수 있습니다. 브라우저는 STEP1 및 STEP3 파일을 병렬로 요청할 수 있지만 실행되면 주문이 보장됩니다. xmlhttprequest를 사용하여 STEP1 및 STEP3의 파일 내용을 얻는 경우 직접 올바른 순서를 보장해야합니다. 또한 STEP2를 잊지 마십시오. STEP1은 비 블로킹 양식으로 다운로드 할 수 있으므로 STEP2를 방해하고 실행하기 전에 Step1을 완료 할 때까지 기다려야합니다.
웹 사이트의 다른 페이지에 대한 <cript> 태그를 생성 할 수있는 전체 도구 세트가 이미 있다면 <cript> 태그를 변경하기 위해이 도구 세트를 조정해야합니다.
코드 사본은 다음과 같습니다.
<cript>
scheduleremotescript ( 'http://cdn.com/step1.js');
</스크립트>
<cript>
ScheduleInLinescript (function code () {
(함수 step2 () {}) ();
});
</스크립트>
<cript>
scheduleremotescript ( 'http://cdn.com/step3.js');
</스크립트>
두 가지 함수 scheduleremotescript 및 scheduleInlineScript를 구현하고 외부 스크립트 파일을 참조하는 첫 번째 <cript> 태그 앞에 정의되도록하고 나머지 <Script> 태그가 위 형식으로 다시 작성됩니다. 즉시 실행 된 STEP2 함수는 더 큰 코드 함수에 배치되었습니다. 코드 함수는 실행되지 않고 컨테이너 일 뿐이므로 원래 Step2 코드를 탈출하지 않고 유지할 수 있지만 즉시 실행되지 않습니다.
다음으로, 주소를 기반으로 SchedulerEmotescript와 SchedareInlineScript에 의해 직접 얻은 코드를 올바른 순서로 하나씩 실행할 수 있도록 완전한 메커니즘을 구현해야합니다. 나는 여기에 자세한 코드를주지 않을 것입니다.
줄 번호 검사
CORS를 통해 컨텐츠를 가져 와서 페이지에 코드를 주입하면 보안 제한을 뚫을 수 있지만 새로운 문제, 즉 줄 번호 충돌이 발생할 수 있습니다. 원래 고유 스크립트 파일은 Error.Script를 통해 위치 할 수 있으며 고유 한 줄 번호는 error.line을 통해 위치 할 수 있습니다. 이제 모든 코드가 페이지에 포함되어 있으므로 여러 <cript> 태그를 Error.script로 구별 할 수는 없으므로 각 <cript> 태그 내부의 줄 번호는 1에서 계산됩니다. 예외 정보가있는 소스 코드 위치.
줄 번호 충돌을 피하기 위해 각 <cript> 태그에서 실제 코드에서 사용하는 줄 번호 간격이 서로 겹치지 않도록 일부 줄 번호를 낭비 할 수 있습니다. 예를 들어, 각 <cript> 태그의 실제 코드가 1000 행을 초과하지 않는다고 가정하면 첫 번째 <cript> 태그에서 코드를 take 11000과 두 번째 <cript>의 코드 태그로 코드를 점유 할 수 있습니다. 10012000 (1000 개의 빈 줄이 삽입되기 전에 삽입되었습니다), 세 번째 <cript>의 코드는 20013000 줄 (2000 개의 빈 줄이 삽입되기 전에 삽입 됨) 등을 차지했습니다. 그런 다음 Data-* 속성을 사용 하여이 정보를 쉽게 검색하기 위해이 정보를 기록합니다.
코드 사본은 다음과 같습니다.
<스크립트
data-src = "http://cdn.com/step1.js"
데이터 라인 스타트 = "1"
>
// 1 단계 코드
</스크립트>
<스크립트 데이터 라인 스타트 = "1001">
// '/n' * 1000
// 2 단계 코드
</스크립트>
<스크립트
data-src = "http://cdn.com/step3.js"
데이터 라인 스타트 = "2001"
>
// '/n' * 2000
// 3 단계 코드
</스크립트>
이 처리 후 오류 오류 오류가 3005 인 경우 실제 error.script는 'http://cdn.com/step3.js'가되어야하며 실제 오류는 5 여야합니다. 앞에서 언급 한 리포터 기능 에서이 줄 번호 리버스 점검을 완료 할 수 있습니다.
물론 각 스크립트 파일에 1000 줄만이 있음을 보장 할 수 없으므로 일부 스크립트 파일이 1000 줄보다 상당히 작을 수도 있으므로 각 <cript> 태그에 1000 줄 간격을 고정으로 할당 할 필요가 없습니다. 실제 스크립트 라인 수를 기반으로 간격을 할당 할 수 있습니다. 각 <cript> 태그가 사용하는 간격이 겹치지 않도록하십시오.
Crossorigin 속성
다른 소스의 컨텐츠에 대한 브라우저가 부과하는 보안 제한은 물론 <cript> 태그에 국한되지 않습니다. xmlhttprequest는 CORS를 통해이 제한을 뚫을 수 있으므로 태그를 통해 자원이 직접 참조되는 이유는 무엇입니까? 이것은 확실히 괜찮습니다.
<cript> 태그에 대한 다른 소스 스크립트 파일을 참조하는 제한은 <Img> 태그의 다른 소스 이미지 파일을 참조하는데도 적용됩니다. <Img> 태그가 다른 소스 인 경우 <canvas> 드로잉에 한 번 사용 된 경우 <canvas>는 쓰기 전용 상태가되어 웹 사이트가 JavaScript를 통해 다른 소스에서 무단 이미지 데이터를 훔칠 수 없도록합니다. 나중에 <Img> 태그는 Crossorigin 속성을 도입 하여이 문제를 해결했습니다. Crossorigin = "익명"인 경우, Crossorigin = "사용 간질"이라는 것은 익명의 CORS와 동일합니다.
<Img> 태그가 이것을 할 수 있기 때문에 왜 <cript> 태그가 이것을 할 수 없습니까? 따라서 브라우저 제조업체는 위의 보안 제한을 해결하기 위해 <Script> 태그에 동일한 Crossorigin 속성을 추가했습니다. 이제이 부동산에 대한 Chrome 및 Firefox 지원은 완전히 무료입니다. Safari는 Crossorigin = "익명"을 Crossorigin = "use-credentials"로 취급 할 것이며, 그 결과 서버가 익명 CORS 만 지원하면 Safari가 인증을 실패로 취급합니다. CDN 서버는 성능의 이유로 정적 컨텐츠 만 반환하도록 설계되었으므로 요청에 따라 CORS를 인증하는 데 필요한 HTTP 헤더를 동적으로 반환 할 수 없습니다.
요약
JavaScript 예외 처리는 단순 해 보이고 다른 언어와 다르지 않지만 모든 예외를 포착하고 속성을 분석하는 것은 쉽지 않습니다. 일부 타사 서비스는 이제 JavaScript 예외를 포착하는 Google 웹 로그 분석 서비스를 제공하지만 세부 사항과 원칙을 이해하려면 직접해야합니다.