引言
網路錯誤記錄 (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
)。
在此範例中,將此回應標頭與主頁面傳送後,瀏覽器就會將瀏覽器產生的警告回報給端點 https://analytics.provider.com/browser-errors
並持續 max_age
秒。請務必注意,系統會忽略網頁發出的所有後續 HTTP 要求 (圖片、指令碼等)。系統會在主頁面回應期間進行設定。
標頭欄位的說明
每項端點設定都包含 group
名稱、max_age
和 endpoints
陣列。您也可以使用 include_subdomains
欄位,選擇在回報錯誤時是否將子網域納入考量。
欄位 | 類型 | 說明 |
---|---|---|
group |
字串 | 選用設定。如果未指定 group 名稱,系統會將端點的名稱指定為「default」。 |
max_age |
號碼 | 必填。非負整數,定義端點的生命週期 (以秒為單位)。如果這個值為「0」,系統會從使用者代理程式的報表快取中移除端點群組。 |
endpoints |
陣列<物件> | 必填。JSON 物件的陣列,用於指定報表收集器的實際網址。 |
include_subdomains |
boolean | 選用設定。這個布林值可讓目前來源主機的所有子網域啟用端點群組。如果省略或設為「true」以外的任何值,系統就不會向端點回報子網域。 |
group
名稱是不重複的名稱,用於將字串與端點建立關聯。在其他與 Reporting API 整合的地方使用這個名稱,以參照特定端點群組。
此外,max-age
欄位也是必要欄位,用於指定瀏覽器應使用端點及回報錯誤的時間長度。
endpoints
欄位是一個陣列,可提供容錯移轉和負載平衡功能。請參閱容錯移轉和負載平衡一節。請注意,即使群組在 endpoints
中列出多個收集器,瀏覽器還是只會選取一個端點。如果您想一次將報表傳送到多部伺服器,則後端必須轉送報表。
瀏覽器如何傳送報表?
瀏覽器會定期批次處理報表,並將這些報表傳送至您設定的報表端點。
如要傳送報表,瀏覽器會以 Content-Type: application/reports+json
發出 POST
要求,且包含一個包含所擷取警告/錯誤陣列的主體。
瀏覽器何時傳送報表?
報表會以頻外形式從應用程式傳送,也就是說,瀏覽器會控管將報表傳送至伺服器的時間。
瀏覽器會在最短的時間內嘗試傳送已排入佇列的報表。這也許在準備就緒後 (為了即時向開發人員提供回饋),但瀏覽器在忙於處理高優先順序的工作、或是使用者的網路速度緩慢和/或連線速度較慢時,也可能延遲傳送作業。如果使用者經常造訪,瀏覽器也會優先傳送特定來源的報表。
使用 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
值收集錯誤。
標頭值應為包含 max_age
和 report_to
欄位的 JSON 物件。請使用後者參照網路錯誤收集器的群組名稱:
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 的節點伺服器範例。說明如何設定網路錯誤的報告,以及建立專用處理常式來擷取結果。
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}`);
});
延伸閱讀
- 使用 Reporting API 監控網頁應用程式 (Reporting API 的主要文章)
- 從 Reporting API v0 遷移至 v1
- 規格:舊版 Reporting API (v0)
- 規格:新版 Reporting API (v1)