@emdash-cms/x402 包为 Cloudflare 上的任何 Astro 站点添加 x402 支付协议支持。它作为独立的 Astro 集成运行,在使用 EmDash 时可以与 EmDash 的 CMS 字段配合实现按页定价。
x402 是一个 HTTP 原生支付协议。当客户端请求付费资源而未付款时,服务器会返回 402 Payment Required 响应和机器可读的支付指令。理解 x402 的代理和浏览器可以自动完成支付并重试请求。
何时使用
最常见的使用场景是仅针对机器人模式:向 AI 代理和爬虫收取内容访问费用,同时让人类访客免费阅读。这使用 Cloudflare Bot Management 来区分机器人和人类。
你也可以对所有访客强制收费,或在不强制的情况下检查支付头(条件渲染)。
安装
使用你的包管理器安装此包:
pnpm
pnpm add @emdash-cms/x402 npm
npm install @emdash-cms/x402 yarn
yarn add @emdash-cms/x402 配置
将集成添加到你的 Astro 配置中:
import { defineConfig } from "astro/config";
import { x402 } from "@emdash-cms/x402";
export default defineConfig({
integrations: [
x402({
payTo: "0xYourWalletAddress",
network: "eip155:8453", // Base mainnet
defaultPrice: "$0.01",
botOnly: true,
botScoreThreshold: 30,
}),
],
});
添加类型引用,让 TypeScript 知道 Astro.locals.x402:
/// <reference types="@emdash-cms/x402/locals" />
基本用法
集成在 Astro.locals.x402 上放置了一个强制器。在页面前置代码中调用 enforce() 来保护付费内容:
---
const { x402 } = Astro.locals;
const result = await x402.enforce(Astro.request, {
price: "$0.05",
description: "Premium article",
});
// If the request has no valid payment, enforce() returns a 402 Response.
// Return it directly to send payment instructions to the client.
if (result instanceof Response) return result;
// Payment verified (or skipped in botOnly mode). Apply response headers
// so the client gets settlement proof.
x402.applyHeaders(result, Astro.response);
---
<article>
<h1>Premium content</h1>
</article>
enforce() 方法返回以下之一:
Response(402) — 客户端需要付款。直接返回它。EnforceResult— 请求应该继续。内容已付费,或强制被跳过(botOnly 模式下的人类)。
仅针对机器人模式
当 botOnly 为 true 时,集成会读取 request.cf.botManagement.score 来分类请求:
- 分数低于阈值(默认 30)-> 被视为机器人,强制付款
- 分数达到或高于阈值 -> 被视为人类,跳过强制
- 无机器人管理数据(本地开发、非 CF 部署)-> 被视为人类
EnforceResult 包含一个 skipped 标志,让你可以区分”不需要付款”和”已付款”:
---
const result = await x402.enforce(Astro.request, { price: "$0.01" });
if (result instanceof Response) return result;
x402.applyHeaders(result, Astro.response);
// result.paid — true if payment was verified
// result.skipped — true if enforcement was skipped (human in botOnly mode)
// result.payer — wallet address of payer (if paid)
---
使用 EmDash 实现按页定价
使用 EmDash 时,向集合添加一个常规的 number 字段用于按页定价,并在请求时读取它:
---
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { entry } = await getEmDashEntry("posts", slug);
if (!entry) return Astro.redirect("/404");
const { x402 } = Astro.locals;
// Use the price from the CMS, falling back to a default
const result = await x402.enforce(Astro.request, {
price: entry.data.price || "$0.01",
description: entry.data.title,
});
if (result instanceof Response) return result;
x402.applyHeaders(result, Astro.response);
---
<article>
<h1>{entry.data.title}</h1>
</article>
检查支付而不强制
使用 hasPayment() 在不验证或强制的情况下检查请求是否包含支付头。这对条件渲染很有用 — 向付费和未付费访客展示不同内容:
---
const { x402 } = Astro.locals;
const hasPaid = x402.hasPayment(Astro.request);
---
{hasPaid ? (
<p>Full premium content here.</p>
) : (
<p>Subscribe for the full article.</p>
)}
配置参考
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
payTo | string | 必需 | 目标钱包地址 |
network | string | 必需 | CAIP-2 网络标识符(例如 eip155:8453) |
defaultPrice | Price | — | 默认价格,可按页覆盖 |
facilitatorUrl | string | https://x402.org/facilitator | 支付促进器 URL |
scheme | string | "exact" | 支付方案 |
maxTimeoutSeconds | number | 60 | 支付签名的最大超时时间 |
evm | boolean | true | 启用 EVM 链支持 |
svm | boolean | false | 启用 Solana 链支持(需要 @x402/svm) |
botOnly | boolean | false | 仅对机器人强制收费 |
botScoreThreshold | number | 30 | 机器人分数阈值(1-99,越低越可能是机器人) |
价格格式
价格可以用多种格式指定:
- 美元字符串 —
"$0.10"($前缀被去除,值按原样传递) - 数字字符串 —
"0.10" - 数字 —
0.10 - 对象 —
{ amount: "100000", asset: "0x...", extra: {} }用于显式资产/金额
网络标识符
网络使用 CAIP-2 格式:
| 网络 | 标识符 |
|---|---|
| Base mainnet | eip155:8453 |
| Base Sepolia | eip155:84532 |
| Ethereum | eip155:1 |
| Solana | solana:mainnet |
Enforce 选项
覆盖特定页面的配置默认值:
await x402.enforce(Astro.request, {
price: "$0.25", // Override price
payTo: "0xDifferentWallet", // Override wallet
network: "eip155:1", // Override network
description: "Article: How x402 Works", // Resource description
mimeType: "text/html", // MIME type hint
});
Solana 支持
Solana 是可选的。安装 @x402/svm 并在配置中启用它:
pnpm add @x402/svm
将网络设置为 Solana 标识符,如果只使用 Solana 则禁用 EVM:
x402({
payTo: "YourSolanaAddress",
network: "solana:mainnet",
svm: true,
evm: false, // Disable EVM if only using Solana
});
工作原理
x402()集成注册中间件,创建强制器并将其放置在Astro.locals.x402上- 配置通过 Vite 虚拟模块(
virtual:x402/config)传递给中间件 - 当调用
enforce()时,它检查请求上的payment-signature头 - 如果不存在支付头,则返回
402 Payment Required响应,在PAYMENT-REQUIRED头中包含支付指令 - 如果存在支付头,则通过促进器服务进行验证和结算
- 结算后,通过
applyHeaders()在响应上设置PAYMENT-RESPONSE头
资源服务器在第一次请求时延迟初始化,并在 worker 生命周期内缓存。