创建x402 HTTP客户端(Fetch和Axios)
构建能够自动检测402 Payment Required响应、签名Algorand交易并使用支付凭证重试请求的HTTP客户端——所有操作均透明进行。
先决条件
在使用此技能之前,请确保:
- Node.js或浏览器环境支持TypeScript
- Algorand钱包或私钥用于签名支付交易
- USDC余额在目标网络(测试网或主网)上的付款人账户中
核心工作流程:402支付流程
关键洞见是wrapFetchWithPayment和wrapAxiosWithPayment截获402响应,签名交易组,并使用支付头重试原始请求——全部自动完成:
客户端请求(GET /api/premium)
|
v
服务器响应
|
+-- 状态 != 402 --> 原样返回响应
|
+-- 状态 == 402 -->
|
+-- 解析PaymentRequired(头部V2/体V1)
+-- 通过注册的x402Client选择方案
+-- 构建原子交易组
+-- 使用ClientAvmSigner(钱包或私钥)签名
+-- 编码PAYMENT-SIGNATURE头
+-- 用支付头重试原始请求
|
v
返回重试响应
如何进行
第1步:安装依赖项
对于基于Fetch的客户端:
npm install @x402-avm/fetch @x402-avm/avm algosdk
对于基于Axios的客户端:
npm install @x402-avm/axios @x402-avm/avm algosdk axios
第2步:实现ClientAvmSigner
ClientAvmSigner接口是将您的钱包或私钥连接到x402支付系统的桥梁。
接口:
interface ClientAvmSigner {
address: string;
signTransactions(
txns: Uint8Array[],
indexesToSign?: number[],
): Promise<(Uint8Array | null)[]>;
}
对于Node.js(私钥):
import algosdk from "algosdk";
const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
const address = algosdk.encodeAddress(secretKey.slice(32));
const signer = {
address,
signTransactions: async (txns: Uint8Array[], indexesToSign?: number[]) => {
return txns.map((txn, i) => {
if (indexesToSign && !indexesToSign.includes(i)) return null;
const decoded = algosdk.decodeUnsignedTransaction(txn);
const signed = algosdk.signTransaction(decoded, secretKey);
return signed.blob;
});
},
};
对于浏览器(@txnlab/use-wallet):
import { useWallet } from "@txnlab/use-wallet-react";
import type { ClientAvmSigner } from "@x402-avm/avm";
function useAvmSigner(): ClientAvmSigner | null {
const { activeAccount, signTransactions } = useWallet();
if (!activeAccount) return null;
return {
address: activeAccount.address,
signTransactions: async (txns: Uint8Array[], indexesToSign?: number[]) => {
return signTransactions(txns, indexesToSign);
},
};
}
第3步:创建和配置x402Client
import { x402Client } from "@x402-avm/fetch"; // 或 "@x402-avm/axios"
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
const client = new x402Client();
registerExactAvmScheme(client, { signer });
第4步:包装Fetch或Axios
Fetch:
import { wrapFetchWithPayment } from "@x402-avm/fetch";
const fetchWithPay = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPay("https://api.example.com/premium-data");
Axios:
import axios from "axios";
import { wrapAxiosWithPayment } from "@x402-avm/axios";
const api = wrapAxiosWithPayment(axios.create(), client);
const response = await api.get("https://api.example.com/premium-data");
第5步:添加支付策略(可选)
策略在选择之前过滤支付要求。它们按顺序应用:
import type { PaymentPolicy } from "@x402-avm/fetch";
const maxAmount: PaymentPolicy = (version, reqs) => {
return reqs.filter((r) => BigInt(r.amount ?? "0") <= BigInt("5000000"));
};
const preferAlgorand: PaymentPolicy = (version, reqs) => {
const algoReqs = reqs.filter((r) => r.network.startsWith("algorand:"));
return algoReqs.length > 0 ? algoReqs : reqs;
};
client.registerPolicy(preferAlgorand).registerPolicy(maxAmount);
第6步:添加生命周期钩子(可选)
监控和控制支付生命周期:
client.onBeforePaymentCreation(async ({ selectedRequirements }) => {
const amountUSDC = Number(selectedRequirements.amount) / 1_000_000;
console.log(`Paying $${amountUSDC.toFixed(6)} USDC`);
if (amountUSDC > 10) {
return { abort: true, reason: "Amount exceeds $10 limit" };
}
});
client.onAfterPaymentCreation(async () => {
console.log("Payment signed successfully");
});
client.onPaymentCreationFailure(async ({ error }) => {
console.error("Payment failed:", error.message);
});
重要规则/指南
- 在包装之前始终注册一个方案 –
registerExactAvmScheme(client, { signer })必须在wrapFetchWithPayment或wrapAxiosWithPayment之前调用 - AVM_PRIVATE_KEY格式 – Base64编码的64字节密钥(32字节种子+32字节公钥)
- 地址派生 – 始终使用
algosdk.encodeAddress(secretKey.slice(32)),永远不要使用前32个字节 - 单次重试 – 包装器在402之后重试一次。如果重试也返回402,错误会被传播
- Axios的拦截器顺序 – 先添加您自己的拦截器,然后最后调用
wrapAxiosWithPayment - 基于配置的替代方案 – 使用
wrapFetchWithPaymentFromConfig/wrapAxiosWithPaymentFromConfig进行声明式设置,无需手动构建x402Client - 通配符网络 – 在基于配置的设置中使用
"algorand:*"以匹配任何Algorand网络
基于配置的设置(替代方案)
而不是手动创建一个x402Client,使用基于配置的方法:
import { wrapFetchWithPaymentFromConfig, type x402ClientConfig } from "@x402-avm/fetch";
import { ExactAvmScheme } from "@x402-avm/avm";
const config: x402ClientConfig = {
schemes: [
{
network: "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
client: new ExactAvmScheme(signer),
},
],
policies: [maxAmount],
};
const fetchWithPay = wrapFetchWithPaymentFromConfig(fetch, config);
常见错误/故障排除
| 错误 | 原因 | 解决方案 |
|---|---|---|
Failed to parse payment requirements |
服务器返回的402无效体 | 检查服务器是否运行x402兼容中间件 |
Failed to create payment payload |
余额不足或错误的网络 | 确保在正确的网络上有USDC余额 |
Payment already attempted |
支付发送后服务器返回402 | 支付被拒绝;检查facilitator日志 |
No network/scheme registered |
服务器需要一个未注册的网络 | 使用registerExactAvmScheme注册所需的方案 |
Payment creation aborted |
一个beforePaymentCreation钩子返回中止 |
审查钩子逻辑;检查金额限制 |
All payment requirements were filtered out |
策略去除了所有选项 | 放宽策略或注册额外的方案 |
No client registered for x402 version: 2 |
根本没有注册方案 | 调用registerExactAvmScheme(client, { signer }) |
阅读支付收据
在成功的付费请求之后,检查响应头:
import { decodePaymentResponseHeader } from "@x402-avm/fetch";
const paymentResponseHeader = response.headers.get("PAYMENT-RESPONSE");
if (paymentResponseHeader) {
const receipt = decodePaymentResponseHeader(paymentResponseHeader);
console.log("Transaction settled:", receipt);
}
参考资料/进一步阅读
- REFERENCE.md - 详细的API参考
- EXAMPLES.md - 完整的代码示例
- x402-avm Fetch Examples
- x402-avm Documentation