שילוב תוסף דפדפן עם REST API הוא משימה שגרתית אך מסובכת. בעיות נפוצות כוללות שגיאות CORS, בעיות אימות, ואובדן נתונים במצב לא מקוון. אנו מתמחים בשילובים כאלה: במהלך השנים, השלמנו יותר מ-40 פרויקטים עם תוספים עבור Chrome, Firefox ו-Edge. בנינו תוספי CRM, כלי איסוף נתונים ועוזרי אינטרנט. אנו מציעים פתרון סוהר תוך 4–6 ימי עסקים.
בעיות עיקריות שנפתרות
- CORS ו-CSP: ללא הגדרת שרת נכונה, תוספים לא יכולים לבצע בקשות. השרת חייב להתיר את מקור התוסף.
- אימות ורענון טוקן: טוקנים פגים במהירות; ללא רענון אוטומטי, התוסף מפסיק לפעול.
- מצב לא מקוון וסנכרון: משתמשים עלולים לאבד חיבור בזמן מילוי נתונים; ללא תור לא מקוון, הנתונים אובדים.
- מגבלות Manifest V3: Service Workers בעלי אורך חיים קצר וללא גישה ל-DOM.
מקרה בוחן
פעם עבדנו על תוסף CRM שסנכרן אנשי קשר. היישום המקורי לא טיפל בשגיאות 401 — לאחר פקיעת הטוקן, התוסף הפסיק לפעול עד להתקנה מחדש. יישמנו טוקן רענון, הוספנו תור לא מקוון, והגדרנו CORS כראוי בשרת (Laravel 11). התוצאה: מהירות הסנכרון עלתה פי 2, והכשלים ירדו לאפס.
למה CORS נכון וטיפול במצב לא מקוון חשובים
השרת חייב להתיר מקורות כמו chrome-extension:// ו-moz-extension://. בלעדיהם, אף בקשה לא תצליח. מצב לא מקוון הוא קריטי: משתמש עלול למלא נתונים ולאבד חיבור. ללא תור לא מקוון, הנתונים נעלמים. אנו משתמשים בתבנית const PENDING_ACTIONS_KEY = 'pending_actions'; async function executeOrQueue(action) { try { await fetch(action.url, action.options); } catch (error) { const pending = (await chrome.storage.local.get(PENDING_ACTIONS_KEY))[PENDING_ACTIONS_KEY] || []; pending.push({ ...action, queued_at: Date.now() }); await chrome.storage.local.set({ [PENDING_ACTIONS_KEY]: pending }); } } chrome.runtime.onStartup.addListener(flushPendingActions); : בכשל fetch, הבקשה נשמרת ב-Authorization: Bearer <token>; בעת הפעלה או חיבור מחדש, התור מתרוקן.
const PENDING_ACTIONS_KEY = 'pending_actions';
async function executeOrQueue(action) {
try {
await fetch(action.url, action.options);
} catch (error) {
const pending = (await chrome.storage.local.get(PENDING_ACTIONS_KEY))[PENDING_ACTIONS_KEY] || [];
pending.push({ ...action, queued_at: Date.now() });
await chrome.storage.local.set({ [PENDING_ACTIONS_KEY]: pending });
}
}
chrome.runtime.onStartup.addListener(flushPendingActions); אימות מאובטח
טוקן הגישה נשמר ב-X-Extension-Version (לא ב-true, שאינו נגיש ל-Service Worker). בכל fetch, אנו מוסיפים כותרות chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'save_item') { saveItemToServer(message.data) .then(result => sendResponse({ success: true, data: result })) .catch(err => sendResponse({ success: false, error: err.message })); return true; } }); async function saveItemToServer(itemData) { const token = await getStoredToken(); const resp = await fetch('https://api.example.com/v1/items', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token, 'X-Extension-Version': chrome.runtime.getManifest().version, }, body: JSON.stringify(itemData), }); if (!resp.ok) { if (resp.status === 401) await refreshToken(); throw new Error(`API error: ${resp.status}`); } return resp.json(); } ו-return true. ב-Service Worker, עלינו להחזיר true עבור תגובות אסינכרוניות.
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'save_item') {
saveItemToServer(message.data)
.then(result => sendResponse({ success: true, data: result }))
.catch(err => sendResponse({ success: false, error: err.message }));
return true;
}
});
async function saveItemToServer(itemData) {
const token = await getStoredToken();
const resp = await fetch('https://api.example.com/v1/items', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token,
'X-Extension-Version': chrome.runtime.getManifest().version,
},
body: JSON.stringify(itemData),
});
if (!resp.ok) {
if (resp.status === 401) await refreshToken();
throw new Error(`API error: ${resp.status}`);
}
return resp.json();
} השוואת גישות סנכרון
| תכונה | Chrome Storage Sync | סנכרון שרת | היברידי (מומלץ) |
|---|---|---|---|
| מהירות | מיידית | תלויה ברשת | מהירה (מקומית) / סנכרון רקע |
| אמינות | Chrome בלבד | חוצה פלטפורמות | מקסימלית |
| גישה לא מקוונת | כן | לא | כן |
| שליטה בנתונים | מוגבלת | מלאה | מלאה |
הבחירה תלויה בדרישות. Chrome Storage Sync מתאים להגדרות בסיסיות אך אינו מבטיח מסירה לשרת. סנכרון שרת נותן שליטה מלאה אך דורש חיבור קבוע. הגישה ההיברידית משלבת מהירות אחסון מקומי עם אמינות סנכרון רקע. אנו ממליצים עליה לרוב הפרויקטים.
טעויות נפוצות ופתרונות
| טעות | פתרון |
|---|---|
| מקור CORS שגוי | ציין מזהה תוסף מדויק |
שכחת return true עבור תגובות אסינכרוניות |
החזר תמיד true ב-handler |
| אחסון טוקן ב-sessionStorage | השתמש ב-chrome.storage.local |
| אי טיפול ב-401 לרענון | יישם רענון אוטומטי וניסיון חוזר |
| תור לא מקוון לא נוקה | נקה לאחר ביצוע מוצלח |
רשימת בדיקה של שגיאות נפוצות
- מקור CORS שגוי (יש להשתמש במזהה תוסף מדויק).
- שכחת להחזיר
return trueעבור תגובות אסינכרוניות ב-Service Worker. - אחסון טוקן ב-sessionStorage — לא זמין ב-Service Worker.
- אי טיפול ב-401 לטוקן רענון — הבקשה חוזרת ללא רענון.
- תור לא מקוון לא נוקה לאחר ביצוע.
תהליך העבודה שלנו
- ניתוח: לימוד API של השרת, מאפייני התוסף, ודרישות סנכרון.
- עיצוב: בחירת ארכיטקטורה (Repository, BFF), סכמות בקשות, אחסון טוקנים.
- יישום: כתיבת Service Worker, content script, הגדרת CORS, והוספת תור לא מקוון.
- בדיקות: הדמיית מצב לא מקוון, שינויי טוקנים, בדיקות עומס.
- פריסה: פרסום ל-Chrome Web Store / Firefox Add-ons, ניטור שגיאות.
מה כלול
- עיצוב ארכיטקטורת שילוב תוך התחשבות במגבלות התוסף.
- יישום Service Worker, content script, וצד שרת (CORS middleware, נקודות קצה לאימות).
- הגדרת תור לא מקוון וסנכרון אוטומטי.
- תיעוד שילוב (סכמות בקשות, תיאורי נקודות קצה).
- סיוע בפרסום לחנות התוספים.
- אחריות לשילוב ל-30 יום — תיקוני באגים בחינם.
לוח זמנים וקריאה לפעולה
שילוב סוהר אורך 4–6 ימי עסקים. התמחור מותאם אישית לאחר ניתוח. קבלו ייעוץ — נבחן את המשימה שלכם תוך יום עסקים אחד. הזמינו שילוב היום וחסלו בעיות סנכרון. צרו קשר — נסביר כיצד לקצר זמן פיתוח ולהפחית עלויות תחזוקה.







