บทนำ
การบันทึกข้อผิดพลาดเกี่ยวกับเครือข่าย (NEL) เป็นกลไกสำหรับ รวบรวมข้อผิดพลาดเกี่ยวกับเครือข่ายฝั่งไคลเอ็นต์จากต้นทาง
โดยจะใช้ส่วนหัวการตอบกลับ HTTP NEL เพื่อบอกเบราว์เซอร์ให้รวบรวมข้อผิดพลาดของเครือข่าย จากนั้นจะผสานรวมกับ Reporting API เพื่อรายงานข้อผิดพลาดไปยังเซิร์ฟเวอร์
ภาพรวม Reporting API เดิม
ส่วนหัว Report-To เดิม
หากต้องการใช้ Reporting API แบบเดิม คุณจะต้องตั้งค่าส่วนหัวการตอบกลับ HTTP Report-To ค่าของฟิลด์นี้คือออบเจ็กต์ที่อธิบายกลุ่มปลายทางสำหรับเบราว์เซอร์เพื่อรายงานข้อผิดพลาด
Report-To:
{
"max_age": 10886400,
"endpoints": [{
"url": "https://analytics.provider.com/browser-errors"
}]
}
หาก URL ของปลายทางอยู่ในต้นทางอื่นที่ไม่ใช่เว็บไซต์ของคุณ ปลายทางควรรองรับคำขอ Preflight ของ 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 |
Array<Object> | ต้องระบุ อาร์เรย์ของออบเจ็กต์ 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 เดียว
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 ของ foobar.com ได้เช่นกัน
การแก้ไขข้อบกพร่องของการกำหนดค่ารายงาน
หากไม่เห็นรายงานแสดงในเซิร์ฟเวอร์ ให้ไปที่
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}`);
});