שילוב Cockpit CMS עם פרונטאנד באמצעות API

התוכן קיים במערכת ה-CMS, אבל הפרונטאנד לא מקבל אותו בגלל שגיאות הרשאה או CORS — כאב מוכר? אנחנו מגדירים את האינטגרציה של Cockpit CMS עם הפרונטאנד שלכם דרך API, ומטפלים בכל המחזור: מהגדרת טוקנים ו-headers ועד caching ופריסה. הצוות שלנו מספק את הפרויקט במפתח מלא, ומבטיח פעילות אמינה ותמיכה מתמשכת.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
שילוב Cockpit CMS עם פרונטאנד באמצעות API
בינוני
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1307
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

בנינו אתר סטטי על Next.js עם תוכן המאוחסן ב-Cockpit CMS. הכל עבד במצב פיתוח, אבל בייצור קיבלנו שגיאת 401. התברר שטוקן ה-API לא הועבר בכותרת הבקשה של הבנייה הסטטית. סיפור טיפוסי: CMS ללא ראש נותן גמישות אך דורש ארכיטקטורת בקשות נכונה. נסקור כיצד להגדיר את האינטגרציה כדי להימנע מהפתעות כאלה. להלן המחזור המלא: מהגדרת CORS ועד פריסה עם ISR. מניסיוננו, אינטגרציה טיפוסית יכולה להתבצע תוך 2–4 ימים, וחוסכת כ-$2,500 מתקציב פרויקט של $5,000 בהשוואה ל-Strapi או Contentful. גישת אינטגרציה זו של Cockpit CMS מבטיחה ביצועים חזקים.

למה Cockpit CMS נוח לפרונטאנד?

Cockpit הוא CMS קל משקל ללא ראש ללא סכמה נוקשה. אתה מגדיר אוספים ו-singletons דרך פאנל הניהול, והפרונטאנד מקבל אובייקטי JSON מוכנים. זה מאפשר לשנות את מבנה התוכן ללא מיגרציות מסד נתונים. עבור אתרים סטטיים (SSG) ודפים דינמיים (ISR), Cockpit מספק נקודת כניסה יחידה. לפי התיעוד הרשמי של Cockpit, זה אחד מה-CMS ללא ראש הקלים ביותר לפריסה — 10 דקות עד לבקשה הראשונה.

אילו בעיות אנו פותרים במהלך האינטגרציה

  • אימות: הטוקן לא צריך להיכנס לקוד הלקוח. אנו מעבירים אותו דרך משתני סביבה בשרת (process.env.COCKPIT_API_TOKEN).
  • מדיניות CORS וטיפול ב-preflight: אם Cockpit פרוס על דומיין אחר, הפרונטאנד לא יכול לבצע בקשות ישירות. אנו מגדירים כותרות CORS על שרת ה-Cockpit (cockpit/config/cors.php).
  • אסטרטגיות ביטול מטמון ו-revalidation: קריאות API תכופות מאטות את הטעינה. אנו משתמשים ב-ISR ב-Next.js או במטמון Redis עבור שאילתות טיפוסיות.
  • תמונות: Cockpit מייצר URLs עם פרמטרי טרנספורמציה תוך כדי תנועה. אל תשמור קישורים מקוריים — השתמש תמיד ב-/api/cockpit/image. מתודולוגיית האינטגרציה שלנו ל-Cockpit CMS מכסה את כל ההיבטים הללו.

איך אנחנו עושים את זה: מקרה מלא

עבור פרויקט אחד עם 3 אוספים (מאמרים, שירותים, ביקורות) ו-singleton הגדרות, יישמנו את האינטגרציה תוך 3 ימים. מחסנית: Next.js 14, Cockpit 2.3, TypeScript בשרת, ISR עבור כל סוג תוכן.

לקוח בסיסי

// lib/cockpit.ts
class CockpitClient {
  private baseUrl: string;
  private token: string;

  constructor(url: string, token: string) {
    this.baseUrl = url.replace(/\/$/, '');
    this.token = token;
  }

  private async request(path: string, options: RequestInit = {}) {
    const res = await fetch(`${this.baseUrl}${path}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        'Cockpit-Token': this.token,
        ...options.headers,
      },
      next: { revalidate: 3600 }, // Next.js ISR
    });
    if (!res.ok) throw new Error(`Cockpit API error: ${res.status}`);
    return res.json();
  }

  // Записи коллекции
  async getCollection(name: string, params: CollectionParams = {}) {
    const body = {
      limit: params.limit || 100,
      skip: params.skip || 0,
      sort: params.sort || { _created: -1 },
      filter: params.filter || {},
      populate: params.populate || 1,
      fields: params.fields,
    };
    return this.request(`/api/collections/get/${name}`, {
      method: 'POST',
      body: JSON.stringify(body),
    });
  }

  // Одна запись по ID
  async getCollectionItem(collection: string, id: string) {
    return this.request(`/api/collections/get/${collection}`, {
      method: 'POST',
      body: JSON.stringify({ filter: { _id: id }, limit: 1 }),
    });
  }

  // Singleton
  async getSingleton(name: string) {
    return this.request(`/api/singletons/get/${name}`);
  }

  // Изображение с трансформацией
  getImageUrl(path: string, options: ImageOptions = {}) {
    const params = new URLSearchParams({
      src: path,
      w: String(options.width || 800),
      h: String(options.height || 600),
      m: options.mode || 'thumbnail',
      q: String(options.quality || 80),
      o: '1',
    });
    return `${this.baseUrl}/api/cockpit/image?${params}&token=${this.token}`;
  }
}

export const cockpit = new CockpitClient(
  process.env.COCKPIT_URL!,
  process.env.COCKPIT_API_TOKEN!
);

Next.js: דפים סטטיים

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const { entries } = await cockpit.getCollection('posts', {
    filter: { published: true },
    fields: { slug: 1 },
  });
  return entries.map((post: any) => ({
    slug: post.slug,
  }));
}

export default async function PostPage({ params }) {
  const { entries } = await cockpit.getCollection('posts', {
    filter: { slug: params.slug, published: true },
    limit: 1,
    populate: 2,
  });
  if (!entries.length) notFound();
  const post = entries[0];
  return (
    <article>
      <h1>{post.title}</h1>
      {post.image && (
        <img
          src={cockpit.getImageUrl(post.image.path, {
            width: 1200,
            height: 630,
          })}
          alt={post.title}
        />
      )}
      <div dangerouslySetInnerHTML={{ __html: post.description }} />
    </article>
  );
}

יישום חיפוש

REST API של Cockpit לא תומך בחיפוש טקסט מלא באופן טבעי. אנו מיישמים דרך פילטר regex:

async function searchPosts(query: string) {
  const { entries } = await cockpit.getCollection('posts', {
    filter: {
      published: true,
      $or: [
        { title: { $regex: query, $options: 'i' } },
        { description: { $regex: query, $options: 'i' } },
      ],
    },
    limit: 20,
  });
  return entries;
}

עבור חיפוש ייצור מלא, אנו מייצרים אינדקס ב-Algolia דרך webhook בעת שינויים.

GraphQL API

Cockpit מספק גם נקודת קצה GraphQL ב-// lib/cockpit.ts class CockpitClient { private baseUrl: string; private token: string; constructor(url: string, token: string) { this.baseUrl = url.replace(/\/$/, ''); this.token = token; } private async request(path: string, options: RequestInit = {}) { const res = await fetch(`${this.baseUrl}${path}`, { ...options, headers: { 'Content-Type': 'application/json', 'Cockpit-Token': this.token, ...options.headers, }, next: { revalidate: 3600 }, // Next.js ISR }); if (!res.ok) throw new Error(`Cockpit API error: ${res.status}`); return res.json(); } // Записи коллекции async getCollection(name: string, params: CollectionParams = {}) { const body = { limit: params.limit || 100, skip: params.skip || 0, sort: params.sort || { _created: -1 }, filter: params.filter || {}, populate: params.populate || 1, fields: params.fields, }; return this.request(`/api/collections/get/${name}`, { method: 'POST', body: JSON.stringify(body), }); } // Одна запись по ID async getCollectionItem(collection: string, id: string) { return this.request(`/api/collections/get/${collection}`, { method: 'POST', body: JSON.stringify({ filter: { _id: id }, limit: 1 }), }); } // Singleton async getSingleton(name: string) { return this.request(`/api/singletons/get/${name}`); } // Изображение с трансформацией getImageUrl(path: string, options: ImageOptions = {}) { const params = new URLSearchParams({ src: path, w: String(options.width || 800), h: String(options.height || 600), m: options.mode || 'thumbnail', q: String(options.quality || 80), o: '1', }); return `${this.baseUrl}/api/cockpit/image?${params}&token=${this.token}`; } } export const cockpit = new CockpitClient( process.env.COCKPIT_URL!, process.env.COCKPIT_API_TOKEN! ); :

query {
  posts: collectionGet(collection: "posts", limit: 10, sort: {_created: -1}) {
    entries {
      _id
      title
      slug
      image
    }
    total
  }
  homepage: singletonGet(singleton: "homepage") {
    hero_title
    hero_subtitle
    hero_image
  }
}
מדריך הגדרה שלב אחר שלב
  1. התקן את Cockpit על שרת (תיעוד: https://cockpitcms.io).
  2. צור אוסף בפאנל הניהול, הוסף שדות.
  3. צור טוקן API בהגדרות.
  4. הגדר CORS ב-// app/blog/[slug]/page.tsx export async function generateStaticParams() { const { entries } = await cockpit.getCollection('posts', { filter: { published: true }, fields: { slug: 1 }, }); return entries.map((post: any) => ({ slug: post.slug })); } export default async function PostPage({ params }) { const { entries } = await cockpit.getCollection('posts', { filter: { slug: params.slug, published: true }, limit: 1, populate: 2, }); if (!entries.length) notFound(); const post = entries[0]; return ( <article> <h1>{post.title}</h1> {post.image && ( <img src={cockpit.getImageUrl(post.image.path, { width: 1200, height: 630 })} alt={post.title} /> )} <div dangerouslySetInnerHTML={{ __html: post.description }} /> </article> ); } .
  5. יישם את הלקוח כפי שמוצג לעיל.
  6. השתמש ב-ISR ב-Next.js עבור מטמון.

השוואה בין Cockpit ל-CMS ללא ראש אחרים

קריטריון Cockpit Strapi Contentful
זמן פריסה 10 דקות 15 דקות ענן
חינם כן כן מוגבל
REST+GraphQL כן כן כן
לוקליזציה טבעית תוסף מובנית

Cockpit מנצח בפשטות: הפריסה מהירה פי 1.5 מ-Strapi, ולפרויקטים קטנים הוא חוסך עד 40% בעלויות תשתית.

תהליך העבודה

שלב משך תוצאה
ניתוח סכמת תוכן 0.5–1 יום רשימת אוספים, singletons, פעולות
הגדרת API ו-CORS 0.5 יום לקוח עובד עם אימות, פילטרים
יישום אינטגרציה 1–2 ימים קוד לקוח, דפים סטטיים, ISR
בדיקות 0.5 יום אימות כל נקודות הכניסה, מטמון
פריסה ותיעוד 0.5 יום Readme, גישה, הוראות

לוחות זמנים ומה כלול

אינטגרציה של 2–3 אוספים + singleton + תמונות דרך CDN אורכת 2 עד 4 ימים. כתוצאה מכך אתה מקבל:

  • לקוח טיפוסי ב-TypeScript
  • דפים מוכנים עם יצירה סטטית ו-ISR
  • CORS מוגדר והעברת טוקן מאובטחת
  • תיעוד על עדכוני תוכן
  • שעת ייעוץ על תפעול

שגיאות טיפוסיות

  • טוקן בלקוח: לעולם אל תעביר את הטוקן דרך async function searchPosts(query: string) { const { entries } = await cockpit.getCollection('posts', { filter: { published: true, $or: [ { title: { $regex: query, $options: 'i' } }, { description: { $regex: query, $options: 'i' } }, ], }, limit: 20, }); return entries; } או fetch בצד הלקוח — השתמש ברכיבי שרת ב-Next.js.
  • חוסר populate: אם לאוסף יש הפניות לרשומות אחרות, אל תשכח את /api/graphql, אחרת תקבל רק מזהים.
  • ביטול מטמון: כאשר התוכן משתנה ב-Cockpit, יש צורך לאפס את מטמון ה-ISR. פתרון — webhook ל-query { posts: collectionGet(collection: "posts", limit: 10, sort: {_created: -1}) { entries { _id title slug image } total } homepage: singletonGet(singleton: "homepage") { hero_title hero_subtitle hero_image } } ב-Next.js.

קבל ייעוץ על אינטגרציה של Cockpit CMS — נעריך את הפרויקט תוך יום אחד. צור קשר, יש לנו מעל 40 אינטגרציות מוצלחות ואנו מבטיחים פעולה יציבה.