使用 Go 构建 x402 付费 API 服务器:从 Gin 中间件到多网络结算的完整实战指南
【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402
导读
本文基于 x402 项目 go/SERVER.md 官方文档,系统讲解如何用 Go 语言构建「按 HTTP 请求收费」的支付服务器。x402 是一套构建在 HTTP 之上的互联网支付协议:服务器把路由声明为受保护资源,客户端先支付、后访问,整条链路通过 facilitator(促进器)完成签名验证与链上结算。读完本文,你将掌握路由支付配置、Gin 中间件接入、动态定价、生命周期钩子、多网络支持、错误处理与生产部署等全部实战能力,并能对照仓库源码理解每一步的底层实现。
一、x402 服务器的核心职责与支付流程
1.1 什么是 x402 服务器
一个 x402 server 是「用支付要求保护 HTTP 资源」的应用程序,其核心职责链路如下:
- 定义路由——声明哪些路由需要付费;
- 返回 402——对未付费请求返回
402 Payment Required及支付要求(payment requirements); - 验证签名——通过 facilitator 验证支付签名;
- 链上结算——通过 facilitator 完成 on-chain settlement;
- 放行资源——支付成功后返回受保护资源。
1.2 一次请求的完整生命周期
根据 go/SERVER.md 与 HTTP 层实现,一次受保护请求的完整处理流如下:
- Client Request→ 服务器收到请求;
- Route Matching→ 检查该路由是否需要支付(对应
ProcessHTTPRequest中的getRouteConfig); - Payment Check→ 从
PAYMENT-SIGNATURE头中提取支付载荷(V2 格式,Base64 编码); - Decision 分支:
- 路由无需支付 → 直接进入业务 handler;
- 未携带支付头 → 返回 402,并携带
PAYMENT-REQUIRED头与支付要求; - 携带支付但要求不匹配 → 返回 402 与 "No matching payment requirements";
- 携带支付且匹配 → 调用
VerifyPayment交给 facilitator 验证;
- Verification→ facilitator 校验签名有效性;
- Handler Execution→ 运行受保护的业务 handler(此时中间件已把
x402_payload与x402_requirements注入 Gin context); - Settlement→ 捕获响应体后调用
ProcessSettlement,提交链上结算交易; - Response→ 返回资源,并在响应头附加
PAYMENT-RESPONSE结算凭证。
在 Gin 中间件实现 中可以看到一个关键工程细节:验证通过后,中间件用一个responseCapture包装c.Writer,先缓冲响应体、延迟写出,待 settlement 成功后再把PAYMENT-RESPONSE头与响应体一并写出;若 handler 返回了>= 400的状态码则跳过结算。同时Flush()与WriteHeaderNow()被实现为空操作,避免在结算前提前提交 HTTP 头(见 middleware.go#L482-L490)。
二、快速开始:安装与最小 Gin 服务器
2.1 安装
go get github.com/x402-foundation/x402/go2.2 最小可运行示例
package main import ( "github.com/gin-gonic/gin" x402 "github.com/x402-foundation/x402/go" x402http "github.com/x402-foundation/x402/go/http" ginmw "github.com/x402-foundation/x402/go/http/gin" evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) func main() { r := gin.Default() // 1. 配置支付路由 routes := x402http.RoutesConfig{ "GET /data": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", PayTo: "0x...", Price: "$0.001", Network: "eip155:84532", }, }, Description: "Get data", MimeType: "application/json", }, } // 2. 创建 facilitator 客户端 facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://x402.org/facilitator", }) // 3. 添加支付中间件 r.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, Facilitator: facilitator, Schemes: []ginmw.SchemeConfig{ {Network: "eip155:84532", Server: evm.NewExactEvmScheme()}, }, })) // 4. 受保护端点 handler r.GET("/data", func(c *gin.Context) { c.JSON(200, gin.H{"result": "protected data"}) }) r.Run(":8080") }仓库中提供了同款完整可运行示例 examples/go/servers/gin/main.go:它同时注册了 Base Sepolia(eip155:84532)与 Solana(solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1)两个网络,并通过环境变量EVM_PAYEE_ADDRESS、SVM_PAYEE_ADDRESS、FACILITATOR_URL注入收款地址与 facilitator 地址,还附带一个无需付费的/health探活端点,非常适合作为上手模板。
三、核心概念:路由配置与模式匹配
3.1 路由支付配置
每个路由通过PaymentOption声明一种支付方式:
routes := x402http.RoutesConfig{ "GET /resource": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", // 支付方案(exact、upto 等) PayTo: "0x...", // 收款地址 Price: "$0.001", // 美元计价价格 Network: "eip155:84532", // 区块链网络(CAIP-2) }, }, Description: "Resource description", MimeType: "application/json", }, }对照源码,PaymentOption 结构体 还支持MaxTimeoutSeconds(支付超时,构建 requirements 时若未指定默认取 60 秒,见 server.go 的 BuildPaymentRequirements)与Extra(额外元数据);RouteConfig 还包含Resource(资源 URL,缺省时取请求 URL)、CustomPaywallHTML(自定义支付墙 HTML)与UnpaidResponseBody(未付费 API 请求的自定义 402 响应体回调)。V2 的PaymentRequirements结构可在 go/types/v2.go#L23-L32 查看:由scheme / network / asset / amount / payTo / maxTimeoutSeconds / extra构成。
3.2 路由模式匹配
路由键(Route key)支持三类模式,解析逻辑见 parseRoutePattern 实现:
routes := x402http.RoutesConfig{ "GET /exact-match": {...}, // 精确路径匹配 "GET /users/*": {...}, // 通配符后缀(* 转为 .*?) "*": {...}, // 匹配所有路由 }此外路由键还支持参数占位:[param](Next.js 风格)与:param(Express 风格)都会被编译为[^/]+正则片段。路径匹配前会经过normalizePath(server.go#L1120-L1144):去掉 query/fragment、URL 解码、\转/、合并多斜杠、去掉尾部斜杠。注意路由键省略动词(如"/api/*")时 verb 默认为*,可匹配任意 HTTP 方法。
3.3 资源服务器核心:x402.X402ResourceServer
X402ResourceServer是支付验证与要求的核心管理器(实现见 go/server.go#L62-L84),其职责包括:维护network → scheme → SchemeNetworkServer注册表、按网络/方案分发 facilitator 客户端、缓存 facilitator 能力(SupportedCache,默认 TTL 5 分钟)以及执行六类生命周期钩子。构造与使用:
server := x402.Newx402ResourceServer( x402.WithFacilitatorClient(facilitator), x402.WithSchemeServer(network, schemeServer), ) // 为资源构建支付要求 requirements, _ := server.BuildPaymentRequirements(ctx, config) // 验证支付 verifyResult, _ := server.VerifyPayment(ctx, payload, requirements) // 结算支付 settleResult, _ := server.SettlePayment(ctx, payload, requirements)一个值得关注的实现细节:WithFacilitatorClient只做临时登记,真正按network/scheme建立索引发生在Initialize——它会调用 facilitator 的/supported端点,把返回的 kinds(含x402Version)映射进facilitatorClients映射表(server.go#L176-L208)。这意味着先 Initialize、后处理请求是正确工作的前提,中间件的SyncFacilitatorOnStart选项正是为此设计。
3.4 HTTP 集成层
x402http.Newx402HTTPResourceServer在核心服务器之上叠加请求/响应处理:
httpServer := x402http.Newx402HTTPResourceServer( routes, x402.WithFacilitatorClient(facilitator), x402.WithSchemeServer(network, schemeServer), ) // 处理 HTTP 请求 result := httpServer.ProcessHTTPRequest(ctx, reqCtx, nil) // 携带传输上下文处理结算 settleResult := httpServer.ProcessSettlement(ctx, payload, requirements, nil, &x402http.HTTPTransportContext{ Request: &reqCtx, ResponseBody: responseBody, ResponseHeaders: responseHeaders, })HTTP 层还提供了框架无关的适配器抽象HTTPAdapter(server.go#L32-L41):只需实现GetHeader / GetMethod / GetPath / GetURL / GetAcceptHeader / GetUserAgent六个方法,即可把支付能力嫁接到任意 Web 框架。仓库中GinAdapter(gin/middleware.go#L27-L73)就是标准范例,Echo 与 net/http 的适配器分别见 go/http/echo 与 go/http/nethttp。
另外Initialize在填充 facilitator 映射后还会执行validateRouteConfiguration(server.go#L317-L365),对每条路由做两类校验:方案是否已注册(missing_scheme)与facilitator 是否支持该网络/方案组合(missing_facilitator),任何不匹配都会以聚合的RouteConfigurationError在启动阶段暴露,避免把错误留到线上。
3.5 Facilitator 客户端
服务器通过 facilitator 客户端完成验证与结算:
facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://x402.org/facilitator", }) // 验证支付(由中间件调用) verifyResp, err := facilitator.Verify(ctx, payloadBytes, requirementsBytes) // 结算支付(由中间件调用) settleResp, err := facilitator.Settle(ctx, payloadBytes, requirementsBytes)对照 facilitator_client.go,FacilitatorConfig还支持:HTTPClient(自定义 HTTP 客户端)、AuthProvider(为 verify/settle/supported 各端点注入鉴权头)、Timeout(默认 30 秒)、Identifier(缺省为 URL)。客户端请求{url}/verify、{url}/settle、{url}/supported三个端点,其中GetSupported对 429 限流做最多 3 次指数退避重试(facilitator_client.go#L289-L352)。
四、中间件:Gin 一键接入与自定义实现
4.1 Gin 中间件
import ginmw "github.com/x402-foundation/x402/go/http/gin" r.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, Facilitator: facilitator, Schemes: schemes, Timeout: 30 * time.Second, }))ginmw.Config的完整字段(builder.go#L13-L44)与说明如下:
| 字段 | 说明 |
|---|---|
Routes | 每个路由的支付要求 |
Facilitator | 单个 facilitator 客户端(与Facilitators二选一) |
Facilitators | facilitator 客户端数组,用于冗余/容灾(与Facilitator二选一) |
Schemes | 要注册的方案服务器([]ginmw.SchemeConfig,含Network与Server) |
PaywallConfig | 浏览器支付墙 UI 配置(可选) |
SyncFacilitatorOnStart | 启动时查询 facilitator 能力,默认在配置了 facilitator 时为 true |
Timeout | 支付操作的 context 超时,默认 30 秒 |
ErrorHandler | 自定义错误处理 |
SettlementHandler | 结算成功后回调 |
X402Payment内部会归一化 facilitator 列表、把SchemeConfig转为WithScheme选项,并委托给PaymentMiddlewareFromConfig复用全部逻辑(builder.go#L94-L129)。对于只想快速保护全站的最简场景,还有SimpleX402Payment(payTo, price, network, facilitatorURL)一行接入的便捷函数(builder.go#L154-L179)。
4.2 自定义中间件
不使用 Gin 时,可以直接基于 HTTP server 实现自己的中间件:
func customPaymentMiddleware(server *x402http.HTTPServer) gin.HandlerFunc { return func(c *gin.Context) { adapter := NewGinAdapter(c) reqCtx := x402http.HTTPRequestContext{ Adapter: adapter, Path: c.Request.URL.Path, Method: c.Request.Method, } result := server.ProcessHTTPRequest(ctx, reqCtx, nil) switch result.Type { case x402http.ResultNoPaymentRequired: c.Next() case x402http.ResultPaymentError: // 返回 402 及支付要求 case x402http.ResultPaymentVerified: // 继续执行并结算 } } }三种结果类型常量定义于 server.go#L185-L190:ResultNoPaymentRequired(无需支付)、ResultPaymentVerified(支付已验证)、ResultPaymentError(支付错误/未支付)。完整实现可参考 examples/go/servers/custom/ 与 examples/go/servers/nethttp/(原生 net/http 接入),更多中间件变体见 go/http/echo/builder.go 与 go/http/nethttp/builder.go。
五、高级特性:动态定价、动态收款与自定义资产
5.1 动态定价(Dynamic Pricing)
按请求上下文收取不同金额,例如按用户等级定价:
routes := x402http.RoutesConfig{ "GET /data": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", PayTo: "0x...", Network: "eip155:84532", Price: x402http.DynamicPriceFunc(func(ctx context.Context, reqCtx x402http.HTTPRequestContext) (x402.Price, error) { tier := extractTierFromRequest(reqCtx) if tier == "premium" { return "$0.005", nil } return "$0.001", nil }), }, }, }, }DynamicPriceFunc与DynamicPayToFunc的类型定义见 server.go#L55-L59,它们在BuildPaymentRequirementsFromOptions中被逐一解析:若Price是函数则调用求值,否则作为静态值使用(server.go#L399-L411)。
5.2 动态收款地址(Dynamic PayTo)
把支付路由到不同地址,典型场景是市场/平台向不同卖家分成:
routes := x402http.RoutesConfig{ "GET /marketplace/item/*": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", Price: "$10.00", Network: "eip155:84532", PayTo: x402http.DynamicPayToFunc(func(ctx context.Context, reqCtx x402http.HTTPRequestContext) (string, error) { sellerID := extractSellerFromPath(reqCtx.Path) return getSellerAddress(sellerID) }), }, }, }, }5.3 自定义货币解析器(Custom Money Parser)
默认价格解析为 USDC,可注册自定义解析器切换代币(例如大额用 DAI):
evmScheme := evm.NewExactEvmScheme().RegisterMoneyParser( func(amount float64, network x402.Network) (*x402.AssetAmount, error) { // 大额使用 DAI if amount > 100 { return &x402.AssetAmount{ Amount: fmt.Sprintf("%.0f", amount*1e18), Asset: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", // DAI Extra: map[string]interface{}{"token": "DAI"}, }, nil } return nil, nil // 小额使用默认 USDC }, )5.4 生命周期钩子(Lifecycle Hooks)
在支付处理的关键节点插入自定义逻辑:
server := x402.Newx402ResourceServer( x402.WithFacilitatorClient(facilitator), x402.WithSchemeServer(network, schemeServer), ) server.OnBeforeVerify(func(ctx x402.VerifyContext) (*x402.BeforeHookResult, error) { log.Printf("Verifying payment for %s", ctx.Requirements.Network) return nil, nil }) server.OnAfterSettle(func(ctx x402.SettleResultContext) error { log.Printf("Payment settled: %s", ctx.Result.Transaction) return nil })六个钩子均支持链式调用且线程安全(见 server.go#L257-L301 的注册实现)。钩子执行语义有明确区分:verify 钩子返回错误或Abort: true会终止请求;settle 钩子同样可中止结算(如黑名单校验);而after 类钩子的错误仅记录、不影响主流程(_ = hook(resultCtx),见 server.go#L449-L453)。失败类钩子(OnVerifyFailure/OnSettleFailure)返回Recovered: true时可接管失败结果实现降级恢复。
5.5 扩展(Extensions)
可为路由附加协议扩展,例如 Bazaar 资源发现:
import ( "github.com/x402-foundation/x402/go/extensions/bazaar" "github.com/x402-foundation/x402/go/extensions/types" ) discoveryExt, _ := bazaar.DeclareDiscoveryExtension( bazaar.MethodGET, map[string]interface{}{"city": "San Francisco"}, &types.InputConfig{...}, "", &types.OutputConfig{...}, ) routes := x402http.RoutesConfig{ "GET /weather": { Accepts: x402http.PaymentOptions{ {Scheme: "exact", PayTo: "0x...", Price: "$0.001", Network: "eip155:84532"}, }, Extensions: map[string]interface{}{ types.BAZAAR: discoveryExt, }, }, }注意 Gin 中间件默认注册了bazaar.BazaarResourceServerExtension(见 gin/middleware.go#L187),请求时扩展声明会通过EnrichExtensions用传输上下文(请求路径、方法等)补充元数据后写入 402 响应(server.go#L547-L565)。完整扩展实现可参考 go/extensions/bazaar/ 与 examples/go/servers/bazaar/。
六、API 参考
6.1 x402.X402ResourceServer
// 构造 func Newx402ResourceServer(opts ...ResourceServerOption) *X402ResourceServer // 选项 func WithFacilitatorClient(client FacilitatorClient) ResourceServerOption func WithSchemeServer(network Network, server SchemeNetworkServer) ResourceServerOption // 钩子方法(均返回自身,可链式调用) func (s *X402ResourceServer) OnBeforeVerify(hook BeforeVerifyHook) *X402ResourceServer func (s *X402ResourceServer) OnAfterVerify(hook AfterVerifyHook) *X402ResourceServer func (s *X402ResourceServer) OnVerifyFailure(hook OnVerifyFailureHook) *X402ResourceServer func (s *X402ResourceServer) OnBeforeSettle(hook BeforeSettleHook) *X402ResourceServer func (s *X402ResourceServer) OnAfterSettle(hook AfterSettleHook) *X402ResourceServer func (s *X402ResourceServer) OnSettleFailure(hook OnSettleFailureHook) *X402ResourceServer // 支付方法 func (s *X402ResourceServer) BuildPaymentRequirements(ctx context.Context, config ResourceConfig) ([]PaymentRequirements, error) func (s *X402ResourceServer) VerifyPayment(ctx context.Context, payload PaymentPayload, requirements PaymentRequirements) (VerifyResponse, error) func (s *X402ResourceServer) SettlePayment(ctx context.Context, payload PaymentPayload, requirements PaymentRequirements) (SettleResponse, error)6.2 x402http.RoutesConfig 与支付选项
type RoutesConfig map[string]RouteConfig type RouteConfig struct { Accepts []PaymentOption // 该路由的支付选项 Description string // 资源描述 MimeType string // 响应内容类型 Extensions map[string]interface{} // 协议扩展 } type PaymentOption struct { Scheme string // "exact" 等 PayTo interface{} // string 或 DynamicPayToFunc Price interface{} // x402.Price 或 DynamicPriceFunc Network x402.Network // "eip155:84532" 等(CAIP-2) MaxTimeoutSeconds int // 支付超时(秒) Extra map[string]interface{} }6.3 ginmw.Config
type Config struct { Routes RoutesConfig Facilitator FacilitatorClient Facilitators []FacilitatorClient Schemes []SchemeConfig PaywallConfig *x402http.PaywallConfig SyncFacilitatorOnStart bool Timeout time.Duration ErrorHandler func(*gin.Context, error) SettlementHandler func(*gin.Context, *x402.SettleResponse) }七、错误处理与结算回调
7.1 自定义错误处理器
r.Use(ginmw.X402Payment(ginmw.Config{ // ... 其他配置 ... ErrorHandler: func(c *gin.Context, err error) { log.Printf("Payment error: %v", err) c.JSON(http.StatusPaymentRequired, gin.H{ "error": "Payment failed", "details": err.Error(), }) }, }))错误处理器不仅接收验证失败,也接收结算失败(此时错误信息为"settlement failed: <原因>",见 middleware.go#L395-L414),因此它是统一兜底入口。未配置ErrorHandler时,结算失败会走内置的 402 响应(带PAYMENT-RESPONSE头)。
7.2 结算处理器
r.Use(ginmw.X402Payment(ginmw.Config{ // ... 其他配置 ... SettlementHandler: func(c *gin.Context, resp x402.SettleResponse) { log.Printf("Payment settled: tx=%s, payer=%s", resp.Transaction, resp.Payer) // 入库、上报指标等 db.RecordPayment(resp.Transaction, resp.Payer) }, }))SettleResponse的关键字段包括Success、Transaction(交易哈希)、Network、Payer、ErrorReason。结算成功时中间件还会在响应头附加PAYMENT-RESPONSE(Base64 编码的结算凭证),客户端可据此对账。
八、最佳实践
8.1 启动时同步 facilitator 能力
r.Use(ginmw.X402Payment(ginmw.Config{ SyncFacilitatorOnStart: true, // 启动时查询 /supported // ... }))该选项让服务器启动时即拉取 facilitator 支持的方案/网络并校验路由配置,尽早暴露配置错误。注意:未配置任何 facilitator 且未显式开启时,同步默认关闭(builder.go#L82-L92)。
8.2 设置合理超时
r.Use(ginmw.X402Payment(ginmw.Config{ Timeout: 30 * time.Second, // 支付操作超时 // ... }))Timeout同时作用于启动同步与每请求的支付处理 context(见 middleware.go#L301-L305),默认 30 秒。
8.3 使用描述性路由
routes := x402http.RoutesConfig{ "GET /api/weather": { Accepts: x402http.PaymentOptions{ {Scheme: "exact", PayTo: "0x...", Price: "$0.001", Network: "eip155:84532"}, }, Description: "Get current weather data for a city", MimeType: "application/json", }, }Description与MimeType会写入 402 响应的resource信息(ResourceInfo{URL, Description, MimeType},见 go/types/v2.go#L52-L57),帮助客户端理解资源并选择是否支付。
8.4 同时处理成功与失败
r.Use(ginmw.X402Payment(ginmw.Config{ ErrorHandler: func(c *gin.Context, err error) { // 记录并告警 }, SettlementHandler: func(c *gin.Context, resp x402.SettleResponse) { // 记录成功支付 }, // ... }))8.5 只保护特定路由
routes := x402http.RoutesConfig{ // 受保护 "GET /api/premium": {Accepts: x402http.PaymentOptions{{Price: "$1.00", ...}}}, "POST /api/compute": {Accepts: x402http.PaymentOptions{{Price: "$5.00", ...}}}, // /health、/docs 等保持不保护 }未在RoutesConfig中声明的路由会命中ResultNoPaymentRequired直接放行,因此路由表之外的端点天然免付费。
九、进阶模式
9.1 多网络支持
r.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, Facilitator: facilitator, Schemes: []ginmw.SchemeConfig{ {Network: "eip155:84532", Server: evm.NewExactEvmScheme()}, {Network: "eip155:8453", Server: evm.NewExactEvmScheme()}, {Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", Server: svm.NewExactSvmScheme()}, }, }))EVM 与 SVM 的 exact 方案服务器分别位于 go/mechanisms/evm/exact/server 与 go/mechanisms/svm/exact。同一路由可在Accepts中声明多条不同网络的PaymentOption(如 gin 示例中的双网络天气接口),客户端任选其一支付。
9.2 按路由差异化定价
routes := x402http.RoutesConfig{ "GET /api/basic": {Accepts: x402http.PaymentOptions{{Price: "$0.001", ...}}}, // 便宜 "GET /api/premium": {Accepts: x402http.PaymentOptions{{Price: "$0.10", ...}}}, // 中等 "POST /api/compute": {Accepts: x402http.PaymentOptions{{Price: "$1.00", ...}}}, // 昂贵 }9.3 分层定价(Tiered Pricing)
routes := x402http.RoutesConfig{ "GET /api/data": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", PayTo: "0x...", Network: "eip155:84532", Price: x402http.DynamicPriceFunc(func(ctx context.Context, reqCtx x402http.HTTPRequestContext) (x402.Price, error) { tier := getUserTier(reqCtx) switch tier { case "free": return "$0.10", nil case "premium": return "$0.01", nil case "enterprise": return "$0.001", nil default: return "$0.10", nil } }), }, }, }, }9.4 市场支付路由(Marketplace Payment Routing)
routes := x402http.RoutesConfig{ "GET /marketplace/item/*": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", Price: "$10.00", Network: "eip155:84532", PayTo: x402http.DynamicPayToFunc(func(ctx context.Context, reqCtx x402http.HTTPRequestContext) (string, error) { itemID := extractItemID(reqCtx.Path) seller, err := db.GetItemSeller(itemID) if err != nil { return "", err } return seller.WalletAddress, nil }), }, }, }, }十、生命周期钩子实战用例
10.1 数据库日志
server.OnAfterSettle(func(ctx SettleResultContext) error { return db.InsertPayment(Payment{ Transaction: ctx.Result.Transaction, Payer: ctx.Result.Payer, Network: ctx.Result.Network, Amount: ctx.Requirements.Amount, Timestamp: time.Now(), }) })10.2 指标上报
server.OnAfterVerify(func(ctx VerifyResultContext) error { metrics.IncrementCounter("payments.verified") return nil })10.3 访问控制(黑名单)
server.OnBeforeSettle(func(ctx SettleContext) (*BeforeHookResult, error) { if isBlacklisted(ctx.Payload.Payer) { return &BeforeHookResult{ Abort: true, Reason: "Payer not allowed", }, nil } return nil, nil })十一、测试
11.1 测试受保护端点
func TestProtectedEndpoint(t *testing.T) { // 创建测试服务器 r := gin.Default() // 添加 mock 中间件 r.Use(mockPaymentMiddleware()) r.GET("/protected", handler) // 携带有效支付测试 req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("PAYMENT-SIGNATURE", validPayment) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != 200 { t.Errorf("Expected 200, got %d", w.Code) } }11.2 集成测试
仓库在 go/test/integration/ 提供了面向真实 facilitator 的集成测试(含 core_test.go、http_test.go、evm_test.go 等);单元测试集中在 go/test/unit/,其中 http_test.go 覆盖了 HTTP 中间件与支付流程的核心逻辑,可作为编写自身测试的参考。Go HTTP 客户端/服务端的 mock 资金测试见 go/test/mocks/cash/。
十二、部署注意事项
12.1 生产检查清单
- 使用生产环境 facilitator URL
- 设置合理超时(建议 30 秒)
- 实现错误处理器与结算处理器
- 监控 facilitator 健康状态
- 对端点限流
- 记录支付事件日志
- 为支付失败设置告警
- 生产环境启用 HTTPS
12.2 Facilitator 选择
测试网:
facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://x402.org/facilitator", // 测试网 })主网:
facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://facilitator.coinbase.com", // 生产 })自托管:
facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://your-facilitator.example.com", })上述 URL 均为官方文档中的示例值,实际部署时应以你接入的 facilitator 服务商提供的地址为准。注意NewHTTPFacilitatorClient在URL为空时会回退到内置默认值https://x402.org/facilitator(facilitator_client.go#L62-L63),显式配置永远更稳妥。facilitator 端的构建方式见 go/FACILITATOR.md。
十三、完整示例索引
仓库 examples/go/servers/ 下提供了可直接运行的服务器示例:
- gin:基础集成,双网络(EVM+SVM)天气接口
- custom:自定义中间件接入
- advanced:动态定价、钩子、扩展的综合示例
- echo:Echo 框架接入
- nethttp:标准库 net/http 接入
- bazaar:Bazaar 扩展示例
- payment-identifier:支付标识扩展示例
- upto:upto(上不封顶)方案示例
十四、V1 迁移到 V2
14.1 路由配置变化
V1:
routes := x402gin.Routes{ "GET /data": { Network: "base-sepolia", // ... }, }V2:
routes := x402http.RoutesConfig{ "GET /data": { Network: "eip155:84532", // CAIP-2 格式 // ... }, }14.2 导入路径变化
V1:
import "github.com/x402-foundation/x402/go/middleware/gin"V2:
import ginmw "github.com/x402-foundation/x402/go/http/gin"V2 服务器只接受 V2 支付(extractPaymentV2会对非 V2 载荷直接报错,见 server.go#L795-L798),版本检测逻辑见 go/mechanisms/evm 下的工具函数。
十五、相关文档导航
- go/README.md:Go 包总览
- go/CLIENT.md:构建客户端
- go/FACILITATOR.md:构建 facilitator
- go/mechanisms/:支付方案实现(EVM/SVM 的 exact/upto)
- go/extensions/:协议扩展
- examples/go/servers/:可运行服务器示例
【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考