簡介
網路錯誤記錄 (NEL) 機制可從來源收集用戶端網路錯誤。
這項功能會使用 NEL HTTP 回應標頭,告知瀏覽器收集網路錯誤,然後與 Reporting API 整合,將錯誤回報給伺服器。
舊版 Reporting API 總覽
舊版 Report-To 標頭
如要使用舊版 Reporting API,請設定 Report-To HTTP 回應標頭。這個物件的值會說明瀏覽器要回報錯誤的端點群組:
Report-To:
{
"max_age": 10886400,
"endpoints": [{
"url": "https://analytics.provider.com/browser-errors"
}]
}
如果端點網址與網站位於不同來源,端點應支援 CORS 預檢要求。(例如 Access-Control-Allow-Origin: *; Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS; Access-Control-Allow-Headers: Content-Type, Authorization, Content-Length, X-Requested-With)。
在範例中,使用主要網頁傳送這個回應標頭,可設定瀏覽器在 max_age 秒內,將瀏覽器產生的警告回報給端點 https://analytics.provider.com/browser-errors。請注意,網頁發出的所有後續 HTTP 要求 (適用於圖片、指令碼等) 都會遭到忽略。設定是在主頁面的回應期間設定。
標頭欄位說明
每個端點設定都包含 group 名稱、max_age 和 endpoints 陣列。您也可以使用 include_subdomains 欄位,選擇是否要在回報錯誤時將子網域納入考量。
| 欄位 | 類型 | 說明 |
|---|---|---|
group |
字串 | (選用步驟) 如果未指定 group 名稱,端點會命名為「default」。 |
max_age |
數字 | 必填。非負整數,用來定義端點的生命週期 (以秒為單位)。如果值為「0」,端點群組就會從使用者代理程式的報表快取中移除。 |
endpoints |
Array<Object> | 必填。JSON 物件陣列,指定報表收集器的實際網址。 |
include_subdomains |
布林值 | (選用步驟) 布林值,可為目前來源主機的所有子網域啟用端點群組。如果省略這個參數,或設為「true」以外的值,系統就不會向端點回報子網域。 |
group 名稱是唯一名稱,用於將字串與端點建立關聯。在與 Reporting API 整合的其他位置使用這個名稱,即可參照特定端點群組。
max-age 欄位也是必填,用於指定瀏覽器應使用端點的時間長度,以及向端點回報錯誤。
endpoints 欄位是陣列,可提供容錯移轉和負載平衡功能。請參閱「容錯移轉和負載平衡」一節。請務必注意,即使群組在 endpoints 中列出多個收集器,瀏覽器也只會選取一個端點。如要一次將報告傳送至多個伺服器,後端必須轉送報告。
瀏覽器如何傳送報表?
瀏覽器會定期批次處理報表,並傳送至您設定的報表端點。
如要傳送報告,瀏覽器會發出 POST 要求,其中包含 Content-Type: application/reports+json 和主體,主體內含擷取的警告/錯誤陣列。
瀏覽器何時會傳送報告?
報表會透過應用程式以外的管道傳送,也就是說,瀏覽器會控管報表傳送至伺服器的時間。
瀏覽器會在最合適的時間嘗試傳送已加入佇列的報表。瀏覽器可能會在準備就緒後立即傳送 (以便及時向開發人員提供意見回饋),但如果忙於處理優先順序較高的工作,或使用者當時的網路速度緩慢和/或壅塞,瀏覽器也可能會延遲傳送。如果使用者經常造訪特定來源,瀏覽器也可能會優先傳送該來源的報告。
使用 Reporting API 時,幾乎不用擔心效能問題 (例如與應用程式的網路爭用)。此外,您也無法控制瀏覽器傳送已加入佇列的報表時間。
設定多個端點
單一回應可透過傳送多個 Report-To 標頭,一次設定多個端點:
Report-To: {
"group": "default",
"max_age": 10886400,
"endpoints": [{
"url": "https://example.com/browser-reports"
}]
}
Report-To: {
"group": "network-errors-endpoint",
"max_age": 10886400,
"endpoints": [{
"url": "https://example.com/network-errors"
}]
}
或將這些標頭合併為單一 HTTP 標頭:
Report-To: {
"group": "network-errors-endpoint",
"max_age": 10886400,
"endpoints": [{
"url": "https://example.com/network-errors"
}]
},
{
"max_age": 10886400,
"endpoints": [{
"url": "https://example.com/browser-errors"
}]
}
傳送 Report-To 標頭後,瀏覽器會根據端點的 max_age 值快取端點,並將所有難看的控制台警告/錯誤傳送至您的網址。
容錯移轉和負載平衡
在大多數情況下,每個群組都會設定一個網址收集器。不過,由於報表可能會產生大量流量,因此規格包含 DNS SRV 記錄啟發的容錯移轉和負載平衡功能。
瀏覽器會盡力將報表傳送至群組中「最多一個」端點。您可以為端點指派 weight 來分配負載,每個端點都會收到指定比例的報表流量。您也可以為端點指派 priority,設定備用收集器。
只有在無法上傳至主要收集器時,系統才會嘗試使用備用收集器。
範例:在 https://backup.com/reports 建立備用收集器:
Report-To: {
"group": "endpoint-1",
"max_age": 10886400,
"endpoints": [
{"url": "https://example.com/reports", "priority": 1},
{"url": "https://backup.com/reports", "priority": 2}
]
}
設定網路錯誤記錄
設定
如要使用 NEL,請設定 Report-To 標頭,並搭配使用具名群組的收集器:
Report-To: {
...
}, {
"group": "network-errors",
"max_age": 2592000,
"endpoints": [{
"url": "https://analytics.provider.com/networkerrors"
}]
}
接著,傳送 NEL 回應標頭,開始收集錯誤。由於 NEL 是來源的選擇啟用功能,因此您只需要傳送一次標頭。NEL 和 Report-To 都會套用至日後對相同來源的要求,並根據用於設定收集器的 max_age 值,繼續收集錯誤。
標頭值應為 JSON 物件,其中包含 max_age 和 report_to 欄位。後者則用於參照網路錯誤收集器的群組名稱:
GET /index.html HTTP/1.1
NEL: {"report_to": "network-errors", "max_age": 2592000}
子資源
範例:如果 example.com 載入 foobar.com/cat.gif,但該資源無法載入:
foobar.com的 NEL 收集器會收到通知example.com的 NEL 收集器不會收到通知
一般來說,NEL 會重現伺服器端記錄,只是這些記錄是在用戶端產生。
由於 example.com 無法查看 foobar.com 的伺服器記錄,因此也無法查看 NEL 報表。
偵錯報表設定
如果伺服器上未顯示報表,請前往 chrome://net-export/。這個頁面有助於確認設定是否正確,以及報表是否正常傳送。
ReportingObserver 呢?
ReportingObserver 是相關但不同的檢舉機制。這項功能是以 JavaScript 呼叫為基礎。
不適合記錄網路錯誤,因為 JavaScript 無法攔截網路錯誤。
範例伺服器
以下是使用 Express 的 Node 伺服器範例。這個範例說明如何設定網路錯誤的報告功能,並建立專屬處理常式來擷取結果。
const express = require('express');
const app = express();
app.use(
express.json({
type: ['application/json', 'application/reports+json'],
}),
);
app.use(express.urlencoded());
app.get('/', (request, response) => {
// Note: report_to and not report-to for NEL.
response.set('NEL', `{"report_to": "network-errors", "max_age": 2592000}`);
// The Report-To header tells the browser where to send network errors.
// The default group (first example below) captures interventions and
// deprecation reports. Other groups, like the network-error group, are referenced by their "group" name.
response.set(
'Report-To',
`{
"max_age": 2592000,
"endpoints": [{
"url": "https://reporting-observer-api-demo.glitch.me/reports"
}],
}, {
"group": "network-errors",
"max_age": 2592000,
"endpoints": [{
"url": "https://reporting-observer-api-demo.glitch.me/network-reports"
}]
}`,
);
response.sendFile('./index.html');
});
function echoReports(request, response) {
// Record report in server logs or otherwise process results.
for (const report of request.body) {
console.log(report.body);
}
response.send(request.body);
}
app.post('/network-reports', (request, response) => {
console.log(`${request.body.length} Network error reports:`);
echoReports(request, response);
});
const listener = app.listen(process.env.PORT, () => {
console.log(`Your app is listening on port ${listener.address().port}`);
});