יישום טכני של יירוט בקשות HTTP בתוסף דפדפן
לקוח מגיע עם דרישה: לחסום סקריפטים של טלמטריה, להוסיף כותרות הרשאה ל-API פנימיים, ולהפנות את כל בקשות המדיה ל-CDN מהיר. ללא יירוט בקשות HTTP, זה בלתי אפשרי. יישמנו עשרות תוספים כאלה ואנחנו מכירים את כל המלכודות—ממגבלות Manifest V3 ועד לניואנסים של תאימות בין דפדפנים.
בעבר, מפתחים השתמשו באופן פעיל ב-chrome.webRequest עם הדגל blocking, אך עם המעבר ל-Manifest V3, שיטה זו איבדה גמישות. התקן המודרני הוא declarativeNetRequest, API הצהרתי שמעביר את עיבוד הכללים לרמת הדפדפן. זה מהיר יותר, מאובטח יותר, ולא מעמיס על ה-thread הראשי, אבל מטיל מגבלות נוקשות: לא יותר מ-5,000 כללים יכולים להיות פעילים בו-זמנית. בואו נצלול לאיך לתכנן מערכת כללים כדי להתגבר על מגבלות אלה תוך שמירה על שליטה מלאה בתעבורה.
איך ליירט בקשות ב-MV3?
הבסיס הוא גישה הצהרתית: אתה מתאר כללים ב-JSON, והדפדפן מיישם אותם. התוסף לא מבזבז CPU על ניתוח כל בקשה, כך ש-Core Web Vitals לא נפגעים.
כללים סטטיים
כללים המוגדרים בקובץ rules/static.json חלים כל הזמן. דוגמה לתצורה לחסימת אנליטיקס, שינוי כותרות, והפנייה:
[
{
"id": 1,
"priority": 1,
"action": {
"type": "block"
},
"condition": {
"urlFilter": "||analytics.example.com^",
"resourceTypes": ["script", "xmlhttprequest", "image"]
}
},
{
"id": 2,
"priority": 2,
"action": {
"type": "modifyHeaders",
"requestHeaders": [
{
"header": "X-Custom-Token",
"operation": "set",
"value": "my-token"
},
{
"header": "Referer",
"operation": "remove"
}
]
},
"condition": {
"urlFilter": "https://api.internal.corp/*",
"resourceTypes": ["xmlhttprequest"]
}
},
{
"id": 3,
"priority": 1,
"action": {
"type": "redirect",
"redirect": {
"regexSubstitution": "https://cdn.example.com\\1"
}
},
"condition": {
"regexFilter": "^https://slow-cdn\\.com(.*)",
"resourceTypes": ["image", "media", "font"]
}
}
]מגבלות: עד 30,000 כללים סטטיים בסך הכול, עם לא יותר מ-5,000 פעילים בו-זמנית. את השאר ניתן להפעיל דינמית דרך ה-service worker.
כללים דינמיים
אם אתה צריך להוסיף כללים תוך כדי תנועה—השתמש ב-service worker. לדוגמה, חסימה/ביטול חסימה של דומיין או הזרקת token אימות:
// background/sw.js
async function blockDomain(domain) {
const existingRules = await chrome.declarativeNetRequest.getDynamicRules();
const maxId = existingRules.reduce((max, r) => Math.max(max, r.id), 0);
await chrome.declarativeNetRequest.updateDynamicRules({
addRules: [{
id: maxId + 1,
priority: 10,
action: { type: 'block' },
condition: {
urlFilter: `||${domain}^`,
resourceTypes: [
'main_frame',
'sub_frame',
'script',
'stylesheet',
'image',
'xmlhttprequest',
'other'
]
}
}],
removeRuleIds: []
});
} איך לשנות את גוף הבקשה דרך Content Script?
declarativeNetRequest לא מאפשר לשנות את הגוף. לשם כך, השתמש ב-content script עם world 'MAIN', תוך יירוט של [ { "id": 1, "priority": 1, "action": { "type": "block" }, "condition": { "urlFilter": "||analytics.example.com^", "resourceTypes": ["script", "xmlhttprequest", "image"] } }, { "id": 2, "priority": 2, "action": { "type": "modifyHeaders", "requestHeaders": [ { "header": "X-Custom-Token", "operation": "set", "value": "my-token" }, { "header": "Referer", "operation": "remove" } ] }, "condition": { "urlFilter": "https://api.internal.corp/*", "resourceTypes": ["xmlhttprequest"] } }, { "id": 3, "priority": 1, "action": { "type": "redirect", "redirect": { "regexSubstitution": "https://cdn.example.com\\1" } }, "condition": { "regexFilter": "^https://slow-cdn\\.com(.*)", "resourceTypes": ["image", "media", "font"] } } ] ו-// background/sw.js async function blockDomain(domain) { const existingRules = await chrome.declarativeNetRequest.getDynamicRules(); const maxId = existingRules.reduce((max, r) => Math.max(max, r.id), 0); await chrome.declarativeNetRequest.updateDynamicRules({ addRules: [{ id: maxId + 1, priority: 10, action: { type: 'block' }, condition: { urlFilter: `||${domain}^`, resourceTypes: [ 'main_frame', 'sub_frame', 'script', 'stylesheet', 'image', 'xmlhttprequest', 'other' ] } }], removeRuleIds: [] }); } . דוגמה להזרקת שדה לגוף של בקשת POST:
const originalFetch = window.fetch;
window.fetch = async function(input, init = {}) {
const url = typeof input === 'string' ? input : input.url;
if (url.includes('api.target.com')) {
init.headers = {
...init.headers,
'X-Injected-Header': 'value',
};
if (init.body) {
const body = JSON.parse(init.body);
body.extraField = 'injected';
init.body = JSON.stringify(body);
}
}
return originalFetch.call(this, input, init);
};שים לב: monkey-patching לא עובד עבור בקשות מ-web workers ו-WebSocket. לשליטה מלאה בתעבורה (פרוקסי ארגוניים), המדיניות הארגונית של Chrome עדיין מאפשרת MV2, אבל חנות האינטרנט הציבורית של Chrome לא מקבלת אותו.
למה declarativeNetRequest מהיר יותר מ-webRequest?
ההבדל העיקרי הוא עיבוד כללים מקורי על ידי הדפדפן ללא מעורבות JavaScript. WebRequest דורש טיפול סינכרוני בכל בקשה בתוסף, מה שמעכב את התגובה ומחמיר את TTFB. declarativeNetRequest מעבד כללים ברמת מחסנית הרשת, ומפחית את LCP ב-10–20% במקרים טיפוסיים.
| מאפיין | webRequest (MV2) | declarativeNetRequest (MV3) |
|---|---|---|
| שינוי גוף | כן (דרך חסימה) | לא |
| ביצועים | נמוכים יותר (עיבוד JS) | גבוהים יותר (דפדפן מקורי) |
| אבטחה | נמוכה יותר (XSS פוטנציאלי) | גבוהה יותר (כללים מבודדים) |
| כללים דינמיים | דרך listener | updateDynamicRules |
| הפניות עם החלפה | כן | כן (regexSubstitution) |
טבלה נוספת: מתי להשתמש בכללים סטטיים לעומת דינמיים
| סוג כלל | מתי להשתמש | דוגמה |
|---|---|---|
| סטטי | תרחישים קבועים שאינם דורשים שינויים תכופים | חסימת עוקבים ידועים, שינוי כותרות לשירותים ארגוניים |
| דינמי | שינויי תצורה: הפעלה/כיבוי לפי בקשת משתמש, tokens זמניים | מעבר בין staging ל-production, הוספת הרשאה עם תוחלת חיים מוגבלת |
מהן המגבלות של declarativeNetRequest?
מלבד מגבלת מספר הכללים (5,000 פעילים), זכור: כללים דינמיים ניתן להוסיף רק מה-service worker, לא מה-popup או content script. כמו כן, יש להצהיר על כל הכללים מראש—לא ניתן ליצור כלל על סמך חישוב JS שרירותי. לניפוי באגים, השתמש ב-fetch ו-XMLHttpRequest. שיטות אלה עוזרות לוודא איזה כלל יפעל עבור URL מסוים ולזהות התנגשויות.
מה היישום שלנו כולל
- ארכיטקטורה: תכנון מערכת כללים (סטטי + דינמי) תוך כיבוד מגבלות MV3.
- Content scripts: monkey-patching לשינוי גוף הבקשה כשנדרש.
- ניפוי באגים: בדיקת כללים דרך
const originalFetch = window.fetch; window.fetch = async function(input, init = {}) { const url = typeof input === 'string' ? input : input.url; if (url.includes('api.target.com')) { init.headers = { ...init.headers, 'X-Injected-Header': 'value', }; if (init.body) { const body = JSON.parse(init.body); body.extraField = 'injected'; init.body = JSON.stringify(body); } } return originalFetch.call(this, input, init); };, רישום הפעלות. - תיעוד: תיאור מלא של כל הכללים, תוכנית ההפניות.
- תמיכה: תחזוקה לאחר השקה, עדכונים כשממשקי API משתנים.
תהליך העבודה שלנו
- אנליטיקה — חקר מבנה הבקשות של היישום שלך, זיהוי יעדי יירוט.
- עיצוב — יצירת מפרט כללים, תיאום איתך.
- יישום — כתיבת קוד התוסף, כולל service worker ו-content scripts.
- בדיקות — אימות בתרחישים אמיתיים, תפיסת מקרי קצה.
- השקה — פרסום ל-Chrome Web Store (או לרישום ארגוני).
לוח זמנים ואחריות
לוח זמנים לפיתוח: מ-5 עד 15 ימי עבודה בהתאם למורכבות. אנו מבטיחים פעולה יציבה ועמידה במדיניות Chrome Web Store. ניסיון: מעל 50 פרויקטים של תוספי דפדפן.
לפרטים נוספים, עיין בתיעוד הרשמי של declarativeNetRequest. קבל ייעוץ לפרויקט שלך—צור קשר כדי לדון.







