บทนำ
การบันทึกข้อผิดพลาดของเครือข่าย (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"
}]
}
หาก URL ปลายทางอยู่ในต้นทางอื่นที่ไม่ใช่เว็บไซต์ของคุณ ปลายทางควรรองรับคำขอ 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" จะทําให้ระบบนํากลุ่มอุปกรณ์ปลายทางออกจากแคชการรายงานของ User Agent |
endpoints |
อาร์เรย์<ออบเจ็กต์> | ต้องระบุ อาร์เรย์ของออบเจ็กต์ JSON ที่ระบุ URL จริงของเครื่องรวบรวมรายงาน |
include_subdomains |
บูลีน | ไม่บังคับ บูลีนที่ใช้เปิดใช้กลุ่มปลายทางสําหรับโดเมนย่อยทั้งหมดของโฮสต์ของต้นทางปัจจุบัน หากไม่ระบุหรือระบุเป็นค่าอื่นที่ไม่ใช่ "จริง" ระบบจะไม่รายงานโดเมนย่อยไปยังปลายทาง |
ชื่อ 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 Header รายการเดียวก็ได้
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
และส่งคำเตือน/ข้อผิดพลาดที่น่ารำคาญทั้งหมดในคอนโซลไปยัง URL
การเปลี่ยนเส้นทางในกรณีที่ระบบไม่ทำงานและการจัดสรรภาระงาน
ส่วนใหญ่แล้วคุณจะกําหนดค่าเครื่องมือรวบรวม URL 1 ตัวต่อกลุ่ม อย่างไรก็ตาม เนื่องจากการรายงานอาจสร้างการเข้าชมจำนวนมาก ข้อมูลจำเพาะจึงรวมฟีเจอร์สํารองและโหลดบาลานซ์ที่ได้จากระเบียน SRV ของ DNS
โดยเบราว์เซอร์จะพยายามอย่างเต็มที่เพื่อส่งรายงานไปยังปลายทางไม่เกิน 1 รายการในกลุ่ม คุณกําหนด 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
และทรัพยากรนั้นโหลดไม่สำเร็จ
- ผู้รวบรวม NEL ของ
foobar.com
ได้รับการแจ้งเตือน - ผู้รวบรวม NEL ของ
example.com
ไม่ได้รับการแจ้งเตือน
หลักการคร่าวๆ คือ NEL จะสร้างบันทึกฝั่งเซิร์ฟเวอร์ขึ้นมาใหม่ ซึ่งเพิ่งสร้างขึ้นในไคลเอ็นต์
เนื่องจาก example.com
ไม่มีสิทธิ์เข้าถึงบันทึกเซิร์ฟเวอร์ของ foobar.com
จึงไม่มีสิทธิ์เข้าถึงรายงาน NEL ด้วย
การกําหนดค่ารายงานการแก้ไขข้อบกพร่อง
หากไม่เห็นรายงานแสดงในเซิร์ฟเวอร์ ให้ไปที่
chrome://net-export/
หน้าดังกล่าวมีประโยชน์ในการยืนยันว่ามีการกําหนดค่าอย่างถูกต้องและมีการส่งรายงานอย่างเหมาะสม
แล้ว ReportingObserver ล่ะ
ReportingObserver
เป็นกลไกการรายงานที่เกี่ยวข้องแต่แตกต่างกัน โดยอิงตามการเรียกใช้ JavaScript
ไม่เหมาะกับการบันทึกข้อผิดพลาดของเครือข่าย เนื่องจากข้อผิดพลาดของเครือข่ายจะไม่สามารถดักรับผ่าน JavaScript ได้
เซิร์ฟเวอร์ตัวอย่าง
ด้านล่างนี้คือตัวอย่างเซิร์ฟเวอร์ Node ที่ใช้ 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}`);
});