前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8767
  • 用评估矩阵和回归门替代 prompt 凭感觉调优
  • 用 pass-all-k 而非准确率衡量AI系统可靠性
  • OpenAI因安全顾虑暂停Astra模型发布
  • 我停止让GPT-5管理邮箱:工作流反而更便宜更好
  • AI Agent 治理失败实录:策略门控为何沦为空文
  • LLM 应用七大攻击面与防御层
  • 大规模 AI 编程成本控制实战指南
  • 自学AI三年成为AI与系统开发总监
  • Copilot 使用量 API 新增 Agent 应用活动追踪
  • Meta推出编程Agent Muse Code:成本低但数据安全存疑
  • Coinbase、Shopify、Ramp自建编程Agent为何仍付费给Anthropic
  • AMD收购Taalas将AI模型直接刻入芯片
  • 我们如何用MCP协议让AI助手直接预订餐厅
  • DGX Spark六个月实测:营销数字在骗人,真实性能这样算
  • Agentic Coding未来五年将重塑软件工程
  • EU AI Act第50条内容溯源规范落地:实际可用的双层方案
  • MCP工具返回值格式实测:72次试验对比摘要行与原始时序数据
  • Oracle禁止在OpenJDK中使用AI生成代码
  • 人机交互场景下LLM低延迟推理工程实践
  • Anthropic Agent Skills 设计反思:Skill 不是 Capability
  • x402 协议实现可靠 Agent 支付的工程实践
  • DeepSeek涨价Claude Code烧钱:Dev成本控制三招
  • 2026年多AI编程智能体运行工具横评
  • AI智能体越界真相:一次34小时的真实攻击链复盘
  • Cohere Health基于Bedrock AgentCore的临床政策数字化实践
  • 生产级MCP服务器测试与调试指南
  • claude-crew:持久化多终端Claude Code智能体架构详解
  • TReNDS用Bedrock将根因分析从30分钟压缩到60秒
  • AI Agent访问控制架构:如何防止数据库被恶意篡改
  • AWS用约束规划自动计算NHL季后赛锁定条件,经验证四个赛季
  • AI Agent自动化开发者工作流:41%发布周期压缩实战
  • Token末日:Accenture 数据显示非工程师才是 token 消耗大户
  • Cloudflare 推出面向 AI Agent 的浏览器 Kitesurf
  • AI独立生成50次测试用例:49次精准覆盖所有边界条件
  • AI Agent支付基础设施一周内集体企业级化
  • AI Agent 故障隔离实战: blast radius 与三级 kill switch 设计
  • OpenAI发布Astra模型网络安全初步评估报告
  • Claude Code 高级编排:子 Agent 模式与防耗尽策略
  • 用 Spring Boot 搭建自托管 AI 客服组件,零 SaaS 订阅
  • 给 AI 写指令本质是写警告标签
  • Meta 认为编程代理的未来在于持久记忆而非更强模型
  • GitHub Code Quality 不再自动为 PR 添加 Copilot 审阅者
  • 别再往ChatGPT扔错误堆栈了
  • Claude Fable 5单次会话从推文构建可玩3D游戏
  • 让AI Agent拥有支付能力:x402协议实战
  • AI Agent工具优化:让Agent能安全调用你的工具
  • 用 Python + AI 自动化播客元数据流水线
  • AWS上Agentic AI实际成本拆解:单元经济学分析
  • open-connector:让AI Agent永远不接触用户凭证
  • npm脚本骗过多数用户:Agent权限提示研究
  • 警惕:MCP服务器正重蹈npm安全覆辙
  • 已加载 51 / 8767
8.0
热点
AI SCORE
技术实践2026-08-08 01:04

x402 协议实现可靠 Agent 支付的工程实践

dev.to · AI#x402#智能合约#Agent支付
Editor brief · 编辑速览

详解基于以太坊 Base L2 的 x402 支付协议如何通过收据幂等、支付超时处理和重复响应防护避免双重扣费,含失败表设计和具体代码模式。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

一位读者在我之前的 x402 教程中提出了一系列问题,这些问题是每个基于 Agent 支付协议构建的工程师迟早都会遇到的:

"将每个支付凭证绑定到请求方法、路径、金额和一个短期过期时间,然后拒绝被重用的收据。一个用于支付后超时和重复响应后重试的小型失败表,可以帮助说明 Agent 如何避免重复扣款。"

这些不是边缘情况。它们是支付流程在演示中能用和你敢让自主 Agent 无人监管地使用之间的差别。让我们逐一讨论每个问题及其解决模式。

核心问题:Agent 支付是最终一致的

x402 支付分为三个阶段:

Request — 买方 Agent 发送 HTTP 请求,收到 402 Payment Required 以及支付详情

Pay — 买方提交链上 USDC(Base L2,gas 约 $0.003)

Deliver — 买方重新发送带 x402-receipt 头的请求,卖方验证链上确认后返回结果

每个阶段都可能独立失败。阶段 2 可能链上成功但阶段 3 永远不完成。阶段 3 可以用相同凭证重放。卖方可能在确认支付后、返回结果前崩溃。Agent 需要处理所有这些情况,且没有人工监控。

模式 1:凭证绑定 — 凭证应该证明什么?

x402 凭证标准绑定到:

{
  "request_body_hash": "sha256(...)",
  "timestamp": "2026-08-07T17:00:00Z",
  "signature": "0x..."
}

这证明了:"有人在此时为这个确切的请求体付了款。"

但它没有证明这个支付是针对哪个端点的。来自 GET /search?q=cats 的凭证在技术上当两个请求体都为空时,对 GET /search?q=dogs 仍然有效——因为请求体哈希匹配。

修复方案:请求上下文绑定

在凭证中添加 request_context 扩展:

{
  "request_body_hash": "sha256(...)",
  "timestamp": "2026-08-07T17:00:00Z",
  "signature": "0x...",
  "extensions": {
    "request_context": {
      "method": "GET",
      "path": "/search",
      "query_params_hash": "sha256(q=cats)",
      "amount_cents": 10
    }
  }
}

现在凭证绑定到了特定操作,而不仅仅是一个请求体。卖方可以拒绝与当前请求的方法、路径或金额不匹配的凭证。

实现(卖方中间件,Go):

func verifyReceiptContext(receipt x402.Receipt, r *http.Request, expectedAmount int) error {
    ctx, ok := receipt.Extensions["request_context"]
    if !ok {
        return errors.New("missing request_context extension")
    }
    if ctx.Method != r.Method {
        return fmt.Errorf("method mismatch: receipt=%s request=%s", ctx.Method, r.Method)
    }
    if ctx.Path != r.URL.Path {
        return fmt.Errorf("path mismatch")
    }
    expectedQuery := sha256Hash(r.URL.RawQuery)
    if ctx.QueryParamsHash != expectedQuery {
        return fmt.Errorf("query params mismatch")
    }
    if ctx.AmountCents != expectedAmount {
        return fmt.Errorf("amount mismatch")
    }
    return nil
}

模式 2:凭证重放保护 — 幂等性缓存

一旦凭证有效,攻击者(或有 Bug 的 Agent)可以重放它。没有保护的情况下,卖方会执行相同的付费操作两次,买方被扣款一次但得到两份结果。

修复方案:凭证 Nonce 缓存

卖方存储 sha256(receipt_signature),TTL 与凭证的过期窗口匹配:

type ReceiptCache struct {
    mu    sync.RWMutex
    store map[string]CachedResult
}

type CachedResult struct {
    Response   []byte
    StatusCode int
    ExpiresAt  time.Time
}

func (rc *ReceiptCache) CheckOrStore(sigHash string, ttl time.Duration) (*CachedResult, error) {
    rc.mu.Lock()
    defer rc.mu.Unlock()

    if cached, exists := rc.store[sigHash]; exists {
        if time.Now().Before(cached.ExpiresAt) {
            return &cached, ErrDuplicateReceipt // 409 Conflict
        }
        delete(rc.store, sigHash) // expired
    }
    return nil, nil // new receipt, proceed
}

func (rc *ReceiptCache) Store(sigHash string, result CachedResult) {
    rc.mu.Lock()
    defer rc.mu.Unlock()
    rc.store[sigHash] = result
}

关键洞察:重放的凭证返回 409 Conflict 以及原始响应。买方得到了他们付费的结果;卖方不会重新执行。没有重复扣款,没有重复执行。

模式 3:支付后超时 — 最难处理的情况

买方链上支付 ✅

买方发送带凭证的请求 → 卖方开始处理

网络超时 — 卖方的响应从未到达

买方不知道:到底成功了还是没成功?

修复方案:基于凭证的幂等重试

买方用相同凭证重试。卖方因为已经缓存了结果,从缓存中返回(模式 2 处理这个)。如果卖方从未完成处理(中途崩溃),凭证签名还不在缓存中,所以卖方会重新执行。

但这里有个微妙之处:副作用操作。如果端点发送了邮件或提交了交易,重新执行是危险的。

解决方案是一个显式的 idempotency_key:

type x402Request struct {
    IdempotencyKey string          `json:"idempotency_key,omitempty"`
    Payload        json.RawMessage `json:"payload"`
}

对于幂等操作(GET、纯计算):凭证签名就是幂等键。对于有副作用的操作(带外部影响的 POST/PUT):买方在支付流程前生成一个唯一的 idempotency_key,将其包含在请求体哈希中,卖方用它来去重。

模式 4:失败表

读者要求"一个用于支付后超时和重复响应后重试的小型失败表"。如下:

最后一行是链上验证问题,不是协议问题——卖方只接受那些有链上确认(证明支付已到达他们地址)的凭证。

实现:一个完整的卖方中间件

把以上所有内容整合起来,这是卖方侧的中间件:

func x402Middleware(next http.Handler) http.Handler {
    cache := NewReceiptCache()

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        receiptHex := r.Header.Get("x402-receipt")
        if receiptHex == "" {
            // No receipt → return 402 with payment details
            w.Header().Set("x402-payment", buildPaymentDetails(r))
            http.Error(w, "Payment Required", 402)
            return
        }

        receipt, err := verifyReceipt(receiptHex, r)
        if err != nil {
            http.Error(w, "Invalid receipt: "+err.Error(), 403)
            return
        }

        sigHash := sha256Hash(receipt.Signature)
        cached, err := cache.CheckOrStore(sigHash, 5*time.Minute)
        if err == ErrDuplicateReceipt {
            w.Header().Set("x402-idempotent", "true")
            w.WriteHeader(cached.StatusCode)
            w.Write(cached.Response)
            return
        }

        // Execute the actual handler
        rw := &responseRecorder{ResponseWriter: w}
        next.ServeHTTP(rw, r)

        // Cache the result
        cache.Store(sigHash, CachedResult{
            Response:   rw.body,
            StatusCode: rw.statusCode,
            ExpiresAt:  time.Now().Add(5 * time.Minute),
        })
    })
}

这对 Agent 自主性意味着什么

一个 Agent 现在可以可靠地处理支付:

1. POST /classify → 402 Payment Required
2. Pay $0.10 USDC on Base → tx confirmed
3. POST /classify + x402-receipt → 200 OK { "label": "spam" }
4. [Same POST + same receipt] → 409 Conflict { "label": "spam" }  ← no double charge
5. [POST + receipt, network timeout] → retry with same receipt → 409 + cached result

没有人监控这个循环。没有重复扣款。没有丢单。Agent 只为它实际使用的部分付费。

这些模式是我们在线上 minia2a 运行的。凭证 nonce 缓存处理了约 387K 个请求,没有发生重复扣款事件。request_context 扩展在我们的规范愿望清单上——它是凭证绑定的下一步。如果你正在基于 x402 构建并遇到这些相同的问题,幂等性缓存是你能做的杠杆最高的改动。

感谢 Swapnoneel Saha 提出的问题促成了这篇文章。好的工程问题能带来更好的文档。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
Anthropic Agent Skills 设计反思:Skill 不是 Capability
下一篇
DeepSeek涨价Claude Code烧钱:Dev成本控制三招