进阶 docs.cloudreve.org 2026-10-17 18:46:57 · 20 阅读

第22章 自定义支付渠道(Pro 版)

自定义支付渠道 Pro 版 本节介绍 Pro 版功能。 除了 Cloudreve 已支持的支付渠道,你还可以通过实现 Cloudreve 的支付接口,自行集成或桥接其他第三方支付平台。 要实现自定义支付接口,你需要一个独立的 HTTP 服务,提供以下能力: 一个 API 端点,用于: 处理 Cloudreve 的创建支付请求,并返回支付页面 URL; 处理 Cloudreve 的订单支付状态查询请求; 在用户完成支付后,向指定 URL 发送 HTTP 请求,通知 Cloudreve 支付已完成。 实现支付接口 Implement 按照本章规范实现支付接口,部署该接口,并确保它能与 Cloudreve 通过网络正常通信。 警告 版本 3 的自定义支付 API 与版本 4 不兼容。 创建订单 POST POST /order 当新订单创建时,Cloudreve 会向你的支付接口发送请求。 请求头 Request Headers 名称 类型 说明 Authorization 字符串 使用你在后台设置的通讯密钥(Communication key)计算的签名。详见 验签。 X-Cr-Version 字符串 Cloudreve 版本号。 X-Cr-Site-Id 字符串 Cloudreve 站点 ID,可用于区分不同站点。 X-Cr-Site-Url 字符串 Cloudreve 的主站点 URL。 请求体 Request Body 请求体以 JSON 格式发送,包含以下字段: 名称 类型 说明 name 字符串 支付名称 order_no 字符串 订单号 notify_url 字符串 回调通知 URL amount 数字 支付金额,使用货币最小单位 currency 字符串 货币的 ISO 4217 代码 请求示例 Request Example httpPOST /order Host: examplepayment.com Authorization: Bearer Vep6hl1x8fiQLasEauMEUqxFKyEqSXb9D_BBQpOiTd8=:1676027218 X-Cr-Site-Url: https://demo.cloudreve.org X-Cr-Site-Id: b7de8bba-8f86-40fe-8171-c2625b6c4a61 X-Cr-Version: 4.0.0

{ "name": "Unlimited Storage", "order_no": "20230209190648343421", "notify_url": "http://demo.cloudreve.org/api/v4/callback/custom/20230209190648343421", "amount": 8900, "currency": "CNY" }期望响应 Expected Response 无论订单创建是否成功,HTTP 响应码均应为 200,成功或失败由响应体中的 code 字段判定。 httpHTTP/1.1 200 OK

{ // 成功响应的 code 始终为 0 "code": 0, // 支付收银台页面的 URL,该 URL 将生成二维码供用户扫描,用户也可以直接打开此 URL "data": "https://examplepayment.com/checkout/26544743" }查询订单状态 GET GET /order?order_no=... 当 Cloudreve 需要查询订单状态时,会向你的端点发送请求。 请求头 Request Headers 名称 类型 说明 Authorization 字符串 使用你在后台设置的通讯密钥(Communication key)计算的签名。详见 验签。 X-Cr-Version 字符串 Cloudreve 版本号。 X-Cr-Site-Id 字符串 Cloudreve 站点 ID,可用于区分不同站点。 X-Cr-Site-Url 字符串 Cloudreve 的主站点 URL。 请求参数 Request Parameters 请求参数以 URL 参数形式发送,包含以下字段: 名称 类型 说明 order_no 字符串 订单号 请求示例 Request Example httpGET /order?order_no=20230209190648343421 Host: examplepayment.com Authorization: Bearer Vep6hl1x8fiQLasEauMEUqxFKyEqSXb9D_BBQpOiTd8=:1676027218 X-Cr-Site-Url: https://demo.cloudreve.org X-Cr-Site-Id: b7de8bba-8f86-40fe-8171-c2625b6c4a61 X-Cr-Version: 4.0.0期望响应 Expected Response httpHTTP/1.1 200 OK

{ "code": 0, // PAID - 已支付 // 其他值 - 未支付 "data": "PAID" }验签 Verify Signature 你可以在 Cloudreve 的支付设置中配置通讯密钥。 Cloudreve 的创建支付请求会使用此密钥进行签名,并将其放在请求中: 对于创建支付请求,签名放在 Authorization 请求头中,以 Bearer Cr 为前缀,验证时应去除该前缀(注意前缀后不应有空格); 对于查询订单状态请求,签名放在 URL 参数 sign 中。 使用以下算法验证签名: 从请求中提取签名,按 : 分割字符串,第二部分为签名过期时间戳,记为 timestamp。 验证其是否大于当前时间戳。 : 之前的部分记为 signature; go// 针对创建支付请求 authHeader := r.Header.Get("Authorization") if !strings.HasPrefix(authHeader, "Bearer Cr ") { return fmt.Errorf("invalid Authorization header format") }

signaturePart := strings.TrimPrefix(authHeader, "Bearer Cr ") parts := strings.Split(signaturePart, ":") if len(parts) != 2 { return fmt.Errorf("invalid signature format in header") } signature, timestampStr := parts[0], parts[1]

// 针对查询订单状态请求 signaturePart := r.URL.Query().Get("sign") parts := strings.Split(signaturePart, ":") if len(parts) != 2 { return fmt.Errorf("invalid signature format in URL") } signature, timestampStr := parts[0], parts[1]验证 timestamp 是否大于当前时间戳。 若小于当前时间戳,则返回错误。 gotimestamp, err := strconv.ParseInt(timestampStr, 10, 64) if err != nil { return fmt.Errorf("invalid timestamp: %w", err) }

if time.Now().Unix() > timestamp { return fmt.Errorf("signature expired") }获取待签名字符串: 对于创建支付请求: 遍历所有请求头,过滤出以 X-Cr- 开头的头,将其转换为 key=value 格式,排序后使用 & 连接,形成字符串 signedHeaderStr。 govar signedHeader []string for k, _ := range r.Header { if strings.HasPrefix(k, "X-Cr-") { signedHeader = append(signedHeader, fmt.Sprintf("%s=%s", k, r.Header.Get(k))) } } sort.Strings(signedHeader) signedHeaderStr := strings.Join(signedHeader, "&")将请求 URL 的 Path 部分、请求体以及 signedHeaderStr 编码为 JSON 字符串 signContent。 若 Path 为空,则使用 / 代替。 gotype RequestRawSign struct { Path string Header string Body string }

path := r.URL.Path if path == "" { path = "/" }

signContent, err := json.Marshal(RequestRawSign{ Path: path, Header: signedHeaderStr, Body: string(r.Body), })对于查询订单状态请求: 直接使用请求 URL 的 Path 部分(不含 Query 参数)作为 signContent。 若 Path 为空,则使用 / 代替。 gopath := r.URL.Path if path == "" { path = "/" }使用 : 连接 signContent 和 timestamp,形成字符串 signContentFinal,然后使用 HMAC 算法和通讯密钥计算 signContentFinal 的签名,记为 signActual。 签名使用 URL-safe Base64 编码。 gosignContentFinal := fmt.Sprintf("%s:%s", signContent, timestampStr) h := hmac.New(sha256.New, []byte(communicationKey)) h.Write([]byte(signContentFinal)) signActual := base64.URLEncoding.EncodeToString(h.Sum(nil))比较 signActual 与 signature,检查是否一致。 goif signActual != signature { return fmt.Errorf("invalid signature") }发送回调 Send Callback 用户完成支付后,你需要向创建支付时指定的 notify_url 发送 GET 请求,通知 Cloudreve 用户已完成支付。 若回调请求失败,除非响应明确返回错误信息和代码,否则应以指数退避方式重试。 Cloudreve 的响应示例如下: httpHTTP/1.1 200 OK

{ // 成功响应的 code 始终为 0 "code": 0 }

评论 (0)