OG obrázky z Express serveru
Generujte OG obrázky v Expressu pomocí předplatného Dynamic API od FastOG — s předplatným Dynamic API (vytvořte si svůj API klíč v dashboardu). Náhled libovolné šablony si můžete prohlédnout v bezplatném testeru OG obrázků a poté obsluhujte dynamické Open Graph obrázky ze svého Express serveru pomocí URL podepsaných HMAC.
Nastavení
bash
npm install express
Implementace
javascript
// app.js
import express from "express";
import crypto from "crypto";
import { URL } from "url";
const app = express();
function generateSignedOgUrl(params, options = {}) {
const {
baseUrl = "https://fastog.com/api/v1/og",
apiKey = process.env.FASTOG_API_KEY,
hmacSecret = process.env.FASTOG_HMAC_SECRET,
} = options;
// RFC-3986 percent-encoding: keep A-Za-z0-9-._~
const enc = (s) =>
encodeURIComponent(s).replace(
/[!'()*]/g,
(c) => "%" + c.charCodeAt(0).toString(16).toUpperCase(),
);
// Every query param except the signature, INCLUDING key
const all = { ...params, key: apiKey };
// Canonical query: sorted enc(key)=enc(value) pairs 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("&");
// Sign the exact bytes the server will verify
const signature = crypto
.createHmac("sha256", hmacSecret)
.update(`GET/api/v1/og\n${canonical}`)
.digest("hex");
// Build the URL from the same pairs so bytes match the canonical form
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(Array.isArray(v) ? `${k}[]` : k, vv);
}
}
url.searchParams.set("s", signature);
return url.toString();
}
// Blog post route
app.get("/blog/:slug", async (req, res) => {
const post = await getPost(req.params.slug);
const ogImageUrl = generateSignedOgUrl({
template: "blog",
title: post.title,
subtitle: post.excerpt,
});
res.render("blog/post", {
post,
ogImageUrl,
});
});
// API endpoint for dynamic OG images
app.get("/api/og", (req, res) => {
const { title, template = "default" } = req.query;
if (!title) {
return res.status(400).json({ error: "Missing title" });
}
const ogImageUrl = generateSignedOgUrl({
template,
title,
});
res.json({ ogImageUrl });
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
EJS šablona
ejs
<!-- views/blog/post.ejs -->
<!DOCTYPE html>
<html>
<head>
<meta property="og:image" content="<%= ogImageUrl %>" />
<meta property="og:title" content="<%= post.title %>" />
<meta property="og:description" content="<%= post.excerpt %>" />
</head>
<body>
<h1><%= post.title %></h1>
</body>
</html>
Pug šablona
pug
// views/blog/post.pug
doctype html
html
head
meta(property="og:image" content=ogImageUrl)
meta(property="og:title" content=post.title)
meta(property="og:description" content=post.excerpt)
body
h1= post.title
Middleware přístup
Tento postup předpokládá, že jste přesunuli funkci generateSignedOgUrl z app.js do lib/og-image-signer.js a exportovali ji.
javascript
// middleware/og-image.js
import { generateSignedOgUrl } from "../lib/og-image-signer.js";
export function injectOgImage(template, titleFn) {
return (req, res, next) => {
const originalRender = res.render.bind(res);
res.render = function (view, locals) {
const title = titleFn(locals);
locals.ogImageUrl = generateSignedOgUrl({
template,
title,
});
return originalRender(view, locals);
};
next();
};
}
// Usage
app.get(
"/blog/:slug",
injectOgImage("blog", (locals) => locals.post.title),
async (req, res) => {
const post = await getPost(req.params.slug);
res.render("blog/post", { post });
},
);
Proměnné prostředí
bash
# .env
FASTOG_API_KEY=sk_your_full_api_key_here
FASTOG_HMAC_SECRET=your_64_char_hex_secret_here