Kanorio

开始使用

Astro

使用 Kanorio 内容构建快速的 Astro 网站,支持静态或服务器渲染、发布时重新构建、SEO 文件与边缘重定向。

Astro 默认不加载 JavaScript,非常适合品牌网站和博客。您可以在组件的 frontmatter 中使用 fetch 读取 Kanorio 内容,通过静态网站的构建时期读取,或使用服务器适配器在每次请求时读取。

1. 环境变量

# .env
PUBLIC_KANORIO_SITE_URL="https://s-xxxxxxxxxxxx.kanorio.com"

请使用来自 网站设置 › 开发者 的永久系统域名。

2. 列出集合

---
// src/pages/projects.astro
const SITE_URL = import.meta.env.PUBLIC_KANORIO_SITE_URL;
const res = await fetch(`${SITE_URL}/api/v1/collections/projects/items?sort=-publishedAt&limit=20`);
const { data, assets } = await res.json();
---

<section>
  <h1>Projects</h1>
  {data.map((item) => {
    const cover = assets[item.fieldData.cover];
    return (
      <article>
        {cover && <img src={cover.url} alt={cover.alt ?? ""} width={cover.width} height={cover.height} loading="lazy" />}
        <h2>{item.fieldData.title}</h2>
        <p>{item.fieldData.summary}</p>
      </article>
    );
  })}
</section>

3. 博客文章

对于静态构建,getStaticPaths 会使用 nextCursor 遍历博客的每一页:

---
// src/pages/blog/[slug].astro
const SITE_URL = import.meta.env.PUBLIC_KANORIO_SITE_URL;

export async function getStaticPaths() {
  const siteUrl = import.meta.env.PUBLIC_KANORIO_SITE_URL;
  const slugs = [];
  let cursor = null;
  do {
    const url = new URL(`${siteUrl}/api/v1/collections/blog/items`);
    url.searchParams.set("fields", "title");
    url.searchParams.set("limit", "100");
    if (cursor) url.searchParams.set("cursor", cursor);
    const page = await (await fetch(url)).json();
    slugs.push(...page.data.map((post) => post.slug));
    cursor = page.hasMore ? page.nextCursor : null;
  } while (cursor);
  return slugs.map((slug) => ({ params: { slug } }));
}

const { slug } = Astro.params;
const res = await fetch(`${SITE_URL}/api/v1/collections/blog/items/${encodeURIComponent(slug)}?expand=authors,categories&formats=html`);
if (!res.ok) return Astro.redirect("/404");
const { item, assets } = await res.json();
const cover = item.fieldData.cover_image ? assets[item.fieldData.cover_image] : null;
---

<article>
  <h1>{item.fieldData.title}</h1>
  {cover && <img src={cover.url} alt={cover.alt ?? ""} />}
  {item.toc?.length > 0 && (
    <nav aria-label="Contents">
      <ul>{item.toc.map((h) => <li data-level={h.level}><a href={`#${h.id}`}>{h.label}</a></li>)}</ul>
    </nav>
  )}
  <div class="prose" set:html={item.contentHtml} />
</article>

4. 表单与更新

  • 表单: 使用 Elements 中的 <kanorio-form>,或是 表单 中描述的挑战与提交端点。将您的域名添加到允许的来源。
  • 静态构建: 在您的主机上创建部署钩子 (deploy hook),并将其添加到 网站设置 › Webhooks 下的 Webhook,订阅集合与页面事件。每次发布都会触发重新构建。
  • 服务器渲染: 使用 @astrojs/cloudflare 或 @astrojs/node,在每次请求时读取并透过 X-Kanorio-Cache-Tags 响应头进行缓存;使用 createRevalidateHandler 创建的 Webhook 处理程序会清除 data.cacheTags 中的标签(词汇相同,请参阅 Webhooks)。

5. SEO 文件

Astro 没有代理重写功能,且重定向会将爬虫程序导向至其他域名。请改为从端点提供文件。seoRewrites 会返回每个路径的来源域名:

// src/lib/kanorio-seo.ts
import { seoRewrites } from "@kanorio/sdk";

const targets = seoRewrites({ siteUrl: import.meta.env.PUBLIC_KANORIO_SITE_URL, framework: "astro" });

export async function proxySeoFile(path: string): Promise<Response> {
  const res = await fetch(targets[path]);
  return new Response(res.body, {
    status: res.status,
    headers: { "Content-Type": res.headers.get("Content-Type") ?? "text/plain; charset=utf-8" },
  });
}
// src/pages/robots.txt.ts, and the same for sitemap.xml, llms.txt, llms-full.txt and feed.xml
import { proxySeoFile } from "../lib/kanorio-seo";

export const GET = () => proxySeoFile("/robots.txt");

使用 fetchDeliveryJsonLd 将 JSON-LD 添加到每个页面:

---
import { fetchDeliveryJsonLd } from "@kanorio/sdk";

const jsonLd = await fetchDeliveryJsonLd({ siteUrl: import.meta.env.PUBLIC_KANORIO_SITE_URL, path: Astro.url.pathname });
---
{jsonLd && <script type="application/ld+json" set:html={jsonLd.scriptJson} />}

6. 重定向与爬虫规则

使用服务器适配器时,请在 middleware 中应用后台的重定向与 AI 爬虫规则,并提供 IndexNow 密钥文件:

// src/middleware.ts
import { defineMiddleware } from "astro:middleware";
import { createKanorioMiddleware } from "@kanorio/sdk/edge";

const kanorioEdge = createKanorioMiddleware({ siteUrl: import.meta.env.PUBLIC_KANORIO_SITE_URL });

export const onRequest = defineMiddleware(async (context, next) => {
  const ctx = context.locals.runtime?.ctx; // Cloudflare adapter only
  const response = await kanorioEdge.handleRequest(context.request, {
    waitUntil: ctx ? (promise) => ctx.waitUntil(promise) : undefined,
  });
  return response ?? next();
});

静态构建无法执行 middleware。请在您的主机上设置重定向,并将 /{key}.txt 转发至 https://{site}/api/v1/seo/indexnow-key.txt。Middleware 仅匹配完整路径;请将通配符重定向添加到 astro.config 中的 redirects。

7. 分析

在您的布局中加载一次 Elements 脚本,并添加分析组件:

<script type="module" src="https://cdn.kanorio.com/elements/v1/kanorio-elements.js"></script>
<kanorio-analytics site-url="https://s-xxxxxxxxxxxx.kanorio.com"></kanorio-analytics>

页面浏览量、引用链接、营销活动参数以及来自 AI 助手的访问将出现在后台的分析中。