หัวข้อ

เริ่มต้นใช้งานด่วน — สร้าง OG Image แรกของคุณ

คู่มือเริ่มต้นใช้งานด่วนของ FastOG นี้จะช่วยให้คุณสร้าง Open Graph image แบบไดนามิกชิ้นแรกได้ภายในไม่กี่นาที การสมัครใช้งานไม่มีค่าใช้จ่าย — จากนั้นเลือกแผน Dynamic API เพื่อรับโควตาการเรนเดอร์ (render quota) คุณสามารถสร้าง API key และ HMAC secret ได้ตามต้องการจากแดชบอร์ด (dashboard) ทุกการเรนเดอร์สะอาดหมดจด — ไม่มีลายน้ำบนทุกแผน รวมถึงบัญชีทดลองใช้งานฟรี ลองใช้เครื่องมือทดสอบ OG Image ฟรี (Free OG Image Tester) เพื่อดูการทำงานของไปป์ไลน์ (pipeline) จากนั้นเซ็น URL ของคุณเองตามขั้นตอนด้านล่าง

หลักการทำงาน — สถาปัตยกรรม

FastOG ถูกสร้างขึ้นสำหรับ OG image แบบ on-demand: เว็บไซต์ของคุณลงนาม (sign) ใน URL ในขณะที่เรนเดอร์หน้าเว็บ ครอว์เลอร์จะดึงข้อมูลนั้นมา 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

กฎสามข้อที่ทำให้มัน "ทำงานได้ทันที"

  1. ลงนามที่เนื้อหา ไม่ใช่เวลา ลายเซ็นครอบคลุมทุกพารามิเตอร์ (title, template, …) พารามิเตอร์ที่เหมือนกันจะสร้าง URL ที่เหมือนกันเสมอ — นี่คือสิ่งที่ทำให้ edge cache ทำงานได้: เนื้อหาเดียวกัน → URL เดียวกัน → cache hit ตลอดไป
  2. รูปภาพจะคงอยู่ถาวรหลังจากการเรนเดอร์ครั้งแรก ลายเซ็นใช้ตรวจสอบเฉพาะการเรนเดอร์ ครั้งแรก เท่านั้น เมื่อรูปภาพถูกเรนเดอร์แล้ว edge ของ FastOG จะเก็บรูปภาพไว้เป็นเวลาหนึ่งปีโดยใช้คีย์จากพารามิเตอร์เนื้อหา — คำขอครั้งหลังที่มีพารามิเตอร์เดียวกันจะถูกเสิร์ฟจาก edge และ ไม่เข้าถึงตัวเรนเดอร์เลย (ไม่นับรวมในโควตาของคุณ) ลายเซ็นที่ไม่ถูกต้องบนเนื้อหาที่ถูกแคชไว้แล้วจะยังคงคืนค่า PNG ที่ถูกแคชไว้ (การตอบสนองจะรายงานว่า tier ใดตอบสนอง: X-FastOG-Worker-Cache: HIT หรือ R2); เฉพาะ cache miss เท่านั้นที่จะได้รับ 401
  3. โหมดความล้มเหลวเพียงอย่างเดียว URL ที่ถูกแก้ไข (มีคนเปลี่ยน title/template) จะได้รับ 401 จาก FastOG เมื่อเกิด cache miss — ดังนั้นจึงไม่สามารถใช้เพื่อใช้โควตาของคุณได้ URL ที่ถูกต้องจะไม่มีวันหมดอายุ: ยังคงใช้ได้จนกว่าคุณจะหมุน HMAC secret ของคีย์

1. รับ API Key และ HMAC Secret ของคุณ

  1. ไปที่ FastOG Dashboard → API Keys

  2. คลิก "Create New API Key"

  3. ตั้งชื่อให้กับคีย์ (เช่น "Production Website")

  4. คัดลอกทั้งสองค่า (แสดงเพียงครั้งเดียวเท่านั้น!):

    • API Key: sk_... (32 ตัวอักษรหลัง prefix)
    • HMAC Secret: สตริงเลขฐานสิบหก 64 ตัวอักษร
  5. เก็บไว้ใน environment ของคุณ:

env
# 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

สำหรับบทช่วยสอนฉบับสมบูรณ์ที่มีหลายเฟรมเวิร์กและรูปแบบการใช้งาน ดูได้ที่:

Node.js / Next.js

javascript
// 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)

php
// 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)

python
# 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

tsx
// 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

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 Template

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. ทดสอบการใช้งานของคุณ

bash
# 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 secret ไว้ใน environment variables (ไม่เก็บในโค้ด)
  • [ ] ใช้ HTTPS สำหรับคำขอทั้งหมด
  • [ ] ไม่เปิดเผย secret ใน JavaScript ฝั่ง client
  • [ ] ติดตามความพยายามลงนามที่ล้มเหลว

6. การจัดการข้อผิดพลาด

javascript
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;
    }
}

ขั้นตอนถัดไป

  1. เริ่มใช้การลงนาม (signing) ในแบ็กเอนด์ของเว็บไซต์ของคุณ (ดูบทช่วยสอน)
  2. ทดสอบกับ FastOG API
  3. ตรวจสอบบันทึก (logs) สำหรับความพยายามลงนามที่ล้มเหลว
  4. ตั้งค่าการแจ้งเตือนสำหรับความล้มเหลวที่เกิดขึ้นซ้ำๆ

สำหรับเอกสารฉบับเต็ม ดู คู่มือลายเซ็น HMAC

เอกสารอ้างอิง API ฉบับสมบูรณ์

ลองใช้ฟรี — ไม่ต้องสมัครสมาชิก

ดูตัวอย่างและทดสอบภาพ OG แบบไดนามิกได้ในไม่กี่วินาที

เปิดตัวทดสอบภาพ OG ฟรี

A BeCaSimulations site