بدء سريع — إنشاء أول صورة OG لك
يُمكّنك هذا الدليل السريع من FastOG من نشر أول صورة Open Graph ديناميكية لك خلال دقائق. التسجيل مجاني — ثم اختر خطة Dynamic API للحصول على حصة العرض. يمكنك إنشاء مفتاح API وسر HMAC عند الحاجة من لوحة التحكم. كل عرض يكون نظيفًا — بدون علامة مائية على أي خطة، بما في ذلك الاختبار المجاني. جرّب أداة اختبار صورة OG المجانية لرؤية خط الإنتاج عمليًا، ثم وقّع روابطك الخاصة باستخدام الخطوات أدناه.
كيف يعمل — البنية المعمارية
صُمم FastOG لإنشاء صور OG عند الطلب: يوقّع موقعك الإلكتروني رابطًا في وقت عرض الصفحة، ثم يجلبها الزاحف، ويقوم FastOG بإنشاء صورة PNG مرة واحدة، وتخزّنها Cloudflare في الذاكرة المؤقتة بحيث يكون كل جلب لاحق فوريًا ومجانيًا.
sequenceDiagram
participant You as You share a link
participant Crawler as Social crawler
participant Site as Your website
participant FastOG as FastOG API
participant Edge as Edge cache
You->>Crawler: share a link to your post
Crawler->>Site: GET the page without JavaScript
Site->>Site: sign the og:image URL at render time
Site-->>Crawler: HTML with signed og:image URL
Crawler->>Edge: fetch the og:image URL
Edge->>FastOG: cache miss, first time
FastOG->>FastOG: verify the HMAC covers the exact params
FastOG-->>Edge: render PNG, counts 1 toward monthly quota, cached for 1 year
Edge-->>Crawler: PNG
Crawler-->>You: image shown in the post preview
Note over Edge, Crawler: identical params and URL mean a cache hit with no render
القواعد الثلاث التي تجعله "يعمل بسلاسة"
- وقّع على المحتوى، لا على الوقت. تغطي التوقيعات كل المعاملات (العنوان، القالب، …). المعاملات المتطابقة تنتج دائمًا رابطًا متطابقًا — وهذا ما يجعل ذاكرة الحافة (edge cache) تعمل: نفس المحتوى → نفس الرابط → إصابة ذاكرة مؤقتة دائمة.
- الصورة دائمة بعد أول عرض. يتحكم التوقيع فقط في أول عرض. بمجرد إنشاء الصورة، تحتفظ بها حافة FastOG لمدة عام مرتبطة بمعاملات المحتوى — الطلبات اللاحقة بنفس المعاملات تُقدَّم من الحافة ولا تصل أبدًا إلى محرك العرض (ولا تُحتسب ضمن حصتك). التوقيع غير الصحيح على محتوى مخزّن لا يزال يُرجع صورة PNG المخزنة (يُبلغ الاستجابة عن الطبقة التي أجابت:
X-FastOG-Worker-Cache: HITأوR2)؛ فقط خطأ الذاكرة المؤقتة (cache miss) يُرجع خطأ 401. - نمط الفشل الوحيد. الرابط المُعدَّل (شخص يغيّر
title/template) يحصل على 401 من FastOG عند خطأ الذاكرة المؤقتة — لذا لا يمكن استخدامه أبدًا لاستنزاف حصتك. الروابط الشرعية لا تنتهي صلاحيتها أبدًا: تبقى صالحة حتى تقوم بتدوير سر HMAC للمفتاح.
1. احصل على مفتاح API الخاص بك وسر HMAC
-
انتقل إلى لوحة تحكم FastOG ← مفاتيح API
-
انقر على "إنشاء مفتاح API جديد"
-
قم بتسميته (مثلًا: "موقع الإنتاج")
-
انسخ القيمتين (تظهر مرة واحدة فقط!):
- مفتاح API:
sk_...(32 حرفًا بعد البادئة) - سر HMAC: سلسلة سداسية عشرية مكونة من 64 حرفًا
- مفتاح API:
-
قم بتخزينهما في بيئتك:
# Your website backend .env
FASTOG_API_KEY=sk_your_full_api_key
FASTOG_HMAC_SECRET=a1b2c3d4e5f6... # 64 chars
FASTOG_API_URL=https://fastog.com/api/v1/og
2. تنفيذ دالة توقيع الروابط (URL Signing Function)
للدروس الكاملة التي تغطي أطر عمل وأنماط متعددة، راجع:
- Next.js App Router
- Next.js Pages Router
- React
- SvelteKit
- Vue / Nuxt
- Astro
- Express
- Vanilla Node.js
- JavaScript
- PHP / Laravel
- Python
- Ruby / Rails
Node.js / Next.js
// lib/fastog-signer.js
import crypto from "crypto";
// RFC-3986 encode (encodeURIComponent leaves !'()* unencoded).
const enc = (s) =>
encodeURIComponent(s).replace(
/[!'()*]/g,
(c) => "%" + c.charCodeAt(0).toString(16).toUpperCase(),
);
export function generateOgImageUrl(params) {
const baseUrl = process.env.FASTOG_API_URL;
const apiKey = process.env.FASTOG_API_KEY;
const hmacSecret = process.env.FASTOG_HMAC_SECRET;
const all = { ...params, key: apiKey };
// Canonical: every param (except s), sorted, RFC-3986 encoded, joined with "&".
const pairs = [];
for (const [k, v] of Object.entries(all)) {
for (const vv of Array.isArray(v) ? v : [v])
pairs.push(`${enc(k)}=${enc(vv)}`);
}
pairs.sort();
const canonical = pairs.join("&");
// Content-signed: message = path + canonical query. No timestamp.
const signature = crypto
.createHmac("sha256", hmacSecret)
.update(`GET/api/v1/og\n${canonical}`)
.digest("hex");
const url = new URL(baseUrl);
for (const [k, v] of Object.entries(all)) {
for (const vv of Array.isArray(v) ? v : [v])
url.searchParams.append(k, vv);
}
url.searchParams.set("s", signature);
return url.toString();
}
PHP (Laravel)
// app/Services/QuickogSigner.php
function generateOgImageUrl(array $params): string
{
$baseUrl = config('services.fastog.api_url', 'https://fastog.com/api/v1/og');
$apiKey = config('services.fastog.api_key');
$hmacSecret = config('services.fastog.hmac_secret');
$all = array_merge($params, ['key' => $apiKey]);
// Canonical: every param except s, keys sorted (array values sorted too),
// RFC-3986 encoded, joined with '&'. Content-signed — no timestamp.
$pairs = [];
foreach ($all as $k => $v) {
$values = is_array($v) ? $v : [$v];
sort($values, SORT_STRING);
foreach ($values as $vv) {
$pairs[] = rawurlencode((string) $k) . '=' . rawurlencode((string) $vv);
}
}
sort($pairs, SORT_STRING);
$canonical = implode('&', $pairs);
$signature = hash_hmac('sha256', 'GET/api/v1/og' . "\n" . $canonical, $hmacSecret);
return $baseUrl . '?' . http_build_query(array_merge($all, ['s' => $signature]));
}
Python (Django/FastAPI)
# utils/fastog.py
import hmac
import hashlib
import os
from urllib.parse import quote, urlencode
def _enc(s):
return quote(str(s), safe='-._~') # RFC-3986: only unreserved chars
def generate_og_image_url(params: dict) -> str:
base_url = os.environ['FASTOG_API_URL']
api_key = os.environ['FASTOG_API_KEY']
hmac_secret = os.environ['FASTOG_HMAC_SECRET']
all_params = {**params, 'key': api_key}
# Canonical: every param except s, sorted, RFC-3986 encoded, joined with '&'.
pairs = []
for k, v in all_params.items():
for vv in sorted(v if isinstance(v, list) else [v]):
pairs.append(f"{_enc(k)}={_enc(vv)}")
canonical = '&'.join(sorted(pairs))
# Content-signed: message = path + canonical query. No timestamp.
signature = hmac.new(
hmac_secret.encode(),
f"GET/api/v1/og\n{canonical}".encode(),
hashlib.sha256,
).hexdigest()
return f"{base_url}?{urlencode({**all_params, 's': signature})}"
3. الاستخدام في مدونتك/موقعك الإلكتروني
Next.js App Router
// app/blog/[slug]/page.tsx
import { generateOgImageUrl } from "@/lib/fastog-signer";
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
const ogImageUrl = generateOgImageUrl({
template: "blog",
title: post.title,
subtitle: post.excerpt,
author: post.author.name,
});
return {
title: post.title,
description: post.excerpt,
openGraph: {
images: [ogImageUrl],
},
};
}
Laravel Blade
{{-- resources/views/blog/show.blade.php --}}
@php
$ogImageUrl = generateOgImageUrl([
'template' => 'blog',
'title' => $post->title,
'subtitle' => $post->excerpt,
'author' => $post->author->name,
]);
@endphp
<head>
<meta property="og:image" content="{{ $ogImageUrl }}" />
<meta property="og:title" content="{{ $post->title }}" />
<meta property="og:description" content="{{ $post->excerpt }}" />
</head>
قالب Django
{# blog/post_detail.html #}
{% load fastog_tags %}
<head>
<meta property="og:image" content="{% generate_og_image_url post %}" />
<meta property="og:title" content="{{ post.title }}" />
<meta property="og:description" content="{{ post.excerpt }}" />
</head>
4. اختبر تنفيذك
# Generate a test URL
node -e "
const { generateOgImageUrl } = require('./lib/fastog-signer');
console.log(generateOgImageUrl({ title: 'Test', template: 'default' }));
"
# Test with curl
curl "https://fastog.com/api/v1/og?title=Test&key=sk_quick_123abc&s=<sig>"
المتوقع:
- ✅ توقيع صالح → يُرجع صورة OG
- ❌ معامل معدَّل (مثل
titleتم تغييره) →{"code": "invalid_signature"} - ❌ توقيع غير صالح →
{"code": "invalid_signature"}
5. قائمة التحقق الأمنية
- [ ] تخزين سر HMAC في متغيرات البيئة (وليس في الكود)
- [ ] استخدام HTTPS لجميع الطلبات
- [ ] عدم كشف السر أبدًا في JavaScript من جانب العميل
- [ ] مراقبة محاولات التوقيع الفاشلة
6. معالجة الأخطاء
if (response.status === 401) {
const error = await response.json();
switch (error.code) {
case "missing_signature":
// URL is missing `key` or `s` — re-generate it with your signer.
break;
case "invalid_signature":
// A param changed after signing, or the secret doesn't match.
// Re-sign the URL after any content change; verify the secret on both sides.
break;
}
}
الخطوات التالية
- تنفيذ التوقيع في الواجهة الخلفية لموقعك (انظر الدروس التعليمية)
- الاختبار باستخدام FastOG API
- مراقبة السجلات لمحاولات التوقيع الفاشلة
- إعداد التنبيهات لحالات الفشل المتكررة
للحصول على الوثائق الكاملة، راجع دليل توقيع HMAC.