מידלוור מותאם אישית ל-Strapi
הפרויקט שלך ב-Strapi מתמודד עם 1000 בקשות בדקה? לוגים מפוזרים, לקוחות מתלוננים על שגיאות 429? תרחיש טיפוסי: הניווט מתחיל לגמגם, זמן התגובה יורד ל-800 אלפיות השנייה. כדי לתקן זאת, אנו מיישמים מידלוור מותאם אישית — פונקציות שמיירטות בקשות לפני ואחרי עיבוד הבקר. הניסיון שלנו: יישמנו מידלוור כזה ביותר מ-50 פרויקטים — מחנויות מסחר אלקטרוני ועד מערכות CMS מורכבות. מידלוור מותאם אישית ל-Strapi מאפשר ניהול גמיש של בקשות: הגבלת קצב, תיעוד ביקורת, בקרת גישה, שינוי תגובה.
מידלוור הוא מושג המוכר למפתחי Express או Koa: הם עובדים בשרשרת, ומעבירים שליטה דרך await next(). Strapi תומך בשני סוגים: גלובלי (מוחל על כל המסלולים) וספציפי למסלול (רק על מסלולים מסוימים). הנה השוואה:
| סוג | היקף | רישום |
|---|---|---|
| גלובלי | כל הבקשות | config/middlewares.js |
| מסלול | מסלול ספציפי | הגדרת מסלול |
כיצד הגבלת קצב משפיעה על ביצועי Strapi
הגבלת קצב בזיכרון היא אחד מהמידלוורים המבוקשים ביותר. היא מאחסנת חותמות זמן של בקשות לפי כתובת IP ב-Map. כאשר מספר הבקשות בחלון (לדוגמה, 100 ב-60 שניות) חורג מהמגבלה, היא מחזירה 429. הגבלה בזיכרון מהירה פי 10 מזו מבוססת קבצים — זמן השהייה מינימלי מתחת ל-1 אלפית השנייה. עבור מערכות מבוזרות, אנו משתמשים ב-Redis (מוסיף 1-3 אלפיות השנייה אך מתקשם אופקית); אנו עוזרים גם בזה. הנה קוד טיפוסי:
// src/middlewares/rate-limit.ts
const requests = new Map<string, number[]>()
export default (config: any) => {
const { maxRequests = 100, windowMs = 60_000 } = config
return async (ctx: any, next: any) => {
const ip = ctx.request.ip
const now = Date.now()
const windowStart = now - windowMs
const timestamps = (requests.get(ip) || []).filter(t => t > windowStart)
if (timestamps.length >= maxRequests) {
ctx.status = 429
ctx.body = { error: 'Too Many Requests' }
ctx.set('Retry-After', String(Math.ceil(windowMs / 1000)))
return
}
timestamps.push(now)
requests.set(ip, timestamps)
await next()
}
}הגדר ב-// src/middlewares/rate-limit.ts const requests = new Map<string, number[]>() export default (config: any) => { const { maxRequests = 100, windowMs = 60_000 } = config return async (ctx: any, next: any) => { const ip = ctx.request.ip const now = Date.now() const windowStart = now - windowMs const timestamps = (requests.get(ip) || []).filter(t => t > windowStart) if (timestamps.length >= maxRequests) { ctx.status = 429 ctx.body = { error: 'Too Many Requests' } ctx.set('Retry-After', String(Math.ceil(windowMs / 1000))) return } timestamps.push(now) requests.set(ip, timestamps) await next() } } כ-config/middlewares.js עם פרמטרים 'global::rate-limit' ו-maxRequests.
הגבלת קצב בזיכרון עם Map מניבה זמן השהייה מתחת ל-1 אלפית השנייה, Redis נותן 1-3 אלפיות השנייה אך מתקשם אופקית. עבור פרויקטים עד 1000 בקשות/שנייה, הגבלה בזיכרון מספיקה; מ-1000 עד 5000, אנו משתמשים ב-Redis. בפרויקט אחד (חנות מסחר אלקטרוני עם 3000 מוצרים), לאחר יישום הגבלת קצב ומידלוור מטמון, TTFB ירד מ-800 אלפיות השנייה ל-200 אלפיות השנייה (הפחתה של 75%), ושגיאות 429 נעלמו לחלוטין. זה חסך $500 בחודש על משאבי שרת (כ-$6000 בשנה).
למה לרשום בקשות דרך מידלוור
הלוגר המוגדר כברירת מחדל של Strapi אינו יכול לעקוב אחר בקשות איטיות. מידלוור מותאם אישית עם תזמון פותר זאת: הוא רושם את כל הבקשות ומסמן איטיות (מעל שנייה אחת). זה עוזר למצוא צווארי בקבוק לפני שהם הופכים קריטיים. דוגמה:
// src/middlewares/request-logger.ts
export default (config: any, { strapi }: any) => {
return async (ctx: any, next: any) => {
const start = Date.now()
await next()
const duration = Date.now() - start
const { method, url, status } = ctx
if (duration > 1000) {
strapi.log.warn(`Slow request: ${method} ${url} — ${duration}ms (${status})`)
}
strapi.log.debug(`${method} ${url} — ${duration}ms [${status}]`)
}
}הוא נרשם גלובלית דרך קובץ הגדרות המידלוור. אנו מבטיחים שלא תפספס שום בקשה בעייתית לאחר ההתקנה.
כיצד אנו מיישמים בדיקת מנוי דרך מידלוור
עבור תוכן פרימיום, אנו משתמשים במידלוור מסלול שבודק את המנוי הפעיל של המשתמש. מידלוור כזה חל רק על מסלול אחד, ואינו מכביד על אחרים:
// src/middlewares/check-subscription.ts
export default (config: any, { strapi }: any) => {
return async (ctx: any, next: any) => {
const userId = ctx.state.user?.id
if (!userId) {
ctx.unauthorized('Authentication required')
return
}
const user = await strapi.entityService.findOne(
'plugin::users-permissions.user',
userId,
{ populate: ['subscription'] }
)
if (!user?.subscription?.active) {
ctx.forbidden('Active subscription required')
return
}
await next()
}
}בהגדרת המסלול, הוסף את השדה windowMs.
למה מידלוור חשוב ל-Core Web Vitals
כל מידלוור יכול לשפר את Core Web Vitals. לדוגמה, מידלוור מטמון מפחית TTFB, והגבלת קצב מונעת עומס על השרת והתדרדרות INP. אם ה-API שלך מחזיר נתונים ב-800 אלפיות השנייה, זה משפיע ישירות על LCP. מידלוור יכול לשמור תגובות במטמון או להגביל תדירות, ולהפחית את זמן ההשהיה בעד 75%.
שינוי תגובה ותמיכה רב-לשונית
לעתים קרובות יש צורך להוסיף שדה מחושב — לדוגמה, אחוז הנחה. מידלוור מיירט את התגובה ומוסיף // src/middlewares/request-logger.ts export default (config: any, { strapi }: any) => { return async (ctx: any, next: any) => { const start = Date.now() await next() const duration = Date.now() - start const { method, url, status } = ctx if (duration > 1000) { strapi.log.warn(`Slow request: ${method} ${url} — ${duration}ms (${status})`) } strapi.log.debug(`${method} ${url} — ${duration}ms [${status}]`) } } . עבור פרויקטים רב-לשוניים, מידלוור יכול לקבוע אוטומטית את האזור מהכותרת Accept-Language:
// src/middlewares/add-computed-fields.ts
export default () => {
return async (ctx: any, next: any) => {
await next()
if (ctx.url.startsWith('/api/products') && ctx.body?.data) {
const transform = (item: any) => ({
...item,
attributes: {
...item.attributes,
discountPercent: item.attributes.originalPrice
? Math.round((1 - item.attributes.price / item.attributes.originalPrice) * 100)
: 0,
},
})
if (Array.isArray(ctx.body.data)) {
ctx.body.data = ctx.body.data.map(transform)
} else {
ctx.body.data = transform(ctx.body.data)
}
}
}
} // src/middlewares/locale-redirect.ts
const localeMap: Record<string, string> = {
'ru-RU': 'ru',
'en-US': 'en',
'uk-UA': 'uk',
}
export default () => {
return async (ctx: any, next: any) => {
if (!ctx.query.locale) {
const acceptLang = ctx.get('Accept-Language')?.split(',')[0] || 'ru'
const locale = localeMap[acceptLang] || acceptLang.split('-')[0] || 'ru'
ctx.query.locale = locale
}
await next()
}
} אילו מידלוורים חיוניים לייצור
הסט החיוני כולל הגבלת קצב, תיעוד ביקורת, בקרת גישה ושינוי תגובה. בנוסף, ניתן להוסיף מטמון, הפניות ו-CORS. אנו עוזרים לבחור את הסט האופטימלי לעומס שלך. העלות משתנה לפי מורכבות; סט טיפוסי של 3–4 מידלוורים עולה $500–$1000 לפיתוח. אנו מספקים הצעת מחיר מפורטת לאחר ניתוח הפרויקט שלך.
הגדרה שלב אחר שלב של מידלוור הגבלת קצב
- צור את הקובץ
config/middlewares.jsעם הקוד מהדוגמה. - ב-
// src/middlewares/check-subscription.ts export default (config: any, { strapi }: any) => { return async (ctx: any, next: any) => { const userId = ctx.state.user?.id if (!userId) { ctx.unauthorized('Authentication required') return } const user = await strapi.entityService.findOne( 'plugin::users-permissions.user', userId, { populate: ['subscription'] } ) if (!user?.subscription?.active) { ctx.forbidden('Active subscription required') return } await next() } }, הוסף אתmiddlewares: ['api::check-subscription']למערךdiscountPercent. - הגדר את הפרמטרים
// src/middlewares/add-computed-fields.ts export default () => { return async (ctx: any, next: any) => { await next() if (ctx.url.startsWith('/api/products') && ctx.body?.data) { const transform = (item: any) => ({ ...item, attributes: { ...item.attributes, discountPercent: item.attributes.originalPrice ? Math.round((1 - item.attributes.price / item.attributes.originalPrice) * 100) : 0, }, }) if (Array.isArray(ctx.body.data)) { ctx.body.data = ctx.body.data.map(transform) } else { ctx.body.data = transform(ctx.body.data) } } } }ו-// src/middlewares/locale-redirect.ts const localeMap: Record<string, string> = { 'ru-RU': 'ru', 'en-US': 'en', 'uk-UA': 'uk', } export default () => { return async (ctx: any, next: any) => { if (!ctx.query.locale) { const acceptLang = ctx.get('Accept-Language')?.split(',')[0] || 'ru' const locale = localeMap[acceptLang] || acceptLang.split('-')[0] || 'ru' ctx.query.locale = locale } await next() } }לפי העומס שלך (לדוגמה, 100 בקשות ב-60 שניות). - בדוק מקומית עם
src/middlewares/rate-limit.ts. - לייצור, השתמש ב-Redis דרך אחסון חיצוני אם יש צורך בקנה מידה מעבר ל-1000 בקשות/שנייה.
לפרטים נוספים על הגדרת מידלוור, ראה את התיעוד הרשמי של Strapi.
תהליך העבודה ומה כלול
אנו עובדים כך: ניתוח דרישות → עיצוב ארכיטקטורת מידלוור → כתיבת קוד עם בדיקות → פריסה לסטייג'ינג → פריסה לייצור. התוצאה כוללת:
- קוד מקור של המידלוור עם הערות
- תיעוד התקנה והגדרה
- גישה למאגר Git
- הדרכה מקוונת של שעה לצוות שלך
- שבועיים של תמיכה לאחר ההשקה
לוח זמנים משוער
פיתוח סט של 3-4 מידלוורים (לדוגמה, הגבלת קצב, תיעוד ביקורת, בקרת גישה, שינוי תגובה) אורך 1 עד 2 ימים. העלות מחושבת באופן אישי, בדרך כלל $500–$1000.
צור קשר כדי להעריך את הפרויקט שלך — נבחר את סט המידלוורים האופטימלי לעומס שלך. קבל ייעוץ על מידלוור מותאם אישית ל-Strapi והזמן פיתוח סוהר עם אחריות לתמיכה של שבועיים.







