wechat

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package wechat 为 payment 包提供微信支付 V3 实现。

功能特性

  • Native 支付(扫码 code_url)
  • JSAPI 预支付与前端调起参数
  • 公众号 OAuth(snsapi_base)换取 openid
  • 订单查询、退款、关单
  • 支付与退款异步通知验签、解密与解析
  • 微信支付公钥 / 平台证书两种身份验签方式

快速开始

验签方式须与商户平台「验证微信支付身份」当前启用项一致(二选一)。

微信支付公钥模式:

client, err := wechat.New(wechat.Config{
	AppID:                "wx_app_id",
	OAuthAppSecret:       "app_secret", // JSAPI OAuth 需要
	MchID:                "1600000000",
	MerchantSerialNo:     "merchant_api_cert_serial",
	MerchantPrivateKey:   merchantPrivateKeyPEM,
	APIV3Key:             "32-byte-api-v3-key................",
	VerifyMode:           wechat.VerifyModePublicKey, // 可选,有公钥材料时可推断
	WechatPayPublicKey:   wechatPayPublicKeyPEM,
	WechatPayPublicKeyID: "PUB_KEY_ID_xxxxxxxx", // 保留 PUB_KEY_ID_ 前缀
})

平台证书自动模式(须显式 VerifyMode;服务可访问微信 API):

// 启动拉取全量有效平台证书;默认定时刷新(后台 goroutine,与 client 同生命周期、无法停止)。
// 短生命周期/测试请设 PlatformCertAutoRefresh=false。
// 回调未知 serial 会受控补拉:并发合流、冷却约 60s、miss 负向缓存约 5min。
autoRefresh := false // 测试示例
client, err := wechat.New(wechat.Config{
	AppID:                   "wx_app_id",
	MchID:                   "1600000000",
	MerchantSerialNo:        "merchant_api_cert_serial",
	MerchantPrivateKey:      merchantPrivateKeyPEM,
	APIV3Key:                "32-byte-api-v3-key................",
	VerifyMode:              wechat.VerifyModePlatformCertAuto,
	PlatformCertAutoRefresh: &autoRefresh,
})

平台证书静态模式(离线或可手动更换的固定证书):

// 仅登记单张序列号;CERTIFICATE PEM 会与配置序列号交叉校验。
// 轮换窗口请改用自动模式。
client, err := wechat.New(wechat.Config{
	AppID:                "wx_app_id",
	MchID:                "1600000000",
	MerchantSerialNo:     "merchant_api_cert_serial",
	MerchantPrivateKey:   merchantPrivateKeyPEM,
	APIV3Key:             "32-byte-api-v3-key................",
	VerifyMode:           wechat.VerifyModePlatformCertStatic,
	PlatformCert:         platformCertPEM,
	PlatformCertSerialNo: "platform_cert_serial",
})

验签模式

商户平台「验证微信支付身份」两种方式只能使用一种:

  1. 微信支付公钥:WechatPayPublicKey + WechatPayPublicKeyID
  2. 平台证书: - 自动:须 VerifyModePlatformCertAuto(拉取全量证书;回调 serial miss 会补拉一次) - 静态:PlatformCert + PlatformCertSerialNo

VerifyMode 为空时:公钥齐全 → public_key,静态证书齐全 → platform_cert_static; 材料皆空返回配置错误(fail-closed),不会静默自动拉证。

公钥与平台证书材料不可同时完整配置。只配置某一模式的一半字段会返回配置错误。 PlatformCertAutoRefresh 仅平台证书自动模式合法(默认开启定时刷新)。

错误分类

  • payment.ErrInvalidConfig:缺字段、模式与材料不匹配、PEM/序列号校验失败、 自动拉证中可识别的配置/权限类失败等
  • payment.ErrGateway:平台证书自动拉取的网络/网关类失败

自动拉证错误类型依赖 gopay 错误文本启发式分类;若对 ErrGateway 重试, 仍应排查 APIv3Key、商户平台证书权限与出网,而非仅当瞬时抖动。

回调

ParsePaymentNotification / ParseRefundNotification 会用已加载的公钥/平台证书验签, 再用 APIV3Key 解密 resource,并校验 appid / mchid。 自动模式下未知 Wechatpay-Serial 会补拉平台证书再验签(与 gopay 同步验签行为对齐): 并发请求合流为一次全量拉取,成功刷新后全局冷却约 60s; 刷新后仍无目标 serial 则负向缓存约 5min,降低伪造 serial 的出站放大。 序列号已存在仍失败则不再补拉。补拉失败时错误同时可 errors.Is 到 ErrInvalidSignature 与 ErrGateway/ErrInvalidConfig。 业务侧仍须在事务内核对订单、金额、状态并幂等入账;仅在业务成功后返回 SuccessResponse。 回调 URL 仍建议在网关层做 IP/频率限制。

注意事项

  • 金额在 payment.Order 中使用分(int64)
  • 证书/密钥内容以 PEM 字符串传入,由调用方负责从文件或密钥管理服务读取
  • 平台证书自动模式在 New 时会请求微信证书接口,需保证出网可达
  • 默认定时刷新 goroutine 无法停止;进程内反复 New 可能叠加刷新任务,生产宜单例
  • 公钥 ID / 证书序列号须与商户平台展示一致(公钥 ID 勿删 PUB_KEY_ID_ 前缀)
Example (JsapiForOnepay)

Example_jsapiForOnepay 演示一码付微信链路需要的 OAuth + JSAPI。

package main

import (
	"fmt"

	"github.com/f2xme/gox/payment"
)

func main() {
	_ = payment.ProviderWechat
	fmt.Println("1. url, err := client.OAuthURL(redirectURL, state)")
	fmt.Println("2. openID, err := client.ExchangeOAuthCode(ctx, code)")
	fmt.Println("3. jsapi, err := client.JSAPIPay(ctx, order, openID)")
}
Output:
1. url, err := client.OAuthURL(redirectURL, state)
2. openID, err := client.ExchangeOAuthCode(ctx, code)
3. jsapi, err := client.JSAPIPay(ctx, order, openID)
Example (NotifyHTTPHandler)

Example_notifyHTTPHandler 演示把支付与退款回调接到标准库 HTTP。 支付侧可运行 handler 见 payment.Example_paymentNotifyHandler;退款侧同理注入 RefundNotifier。

package main

import (
	"fmt"
)

func main() {
	fmt.Println("POST /payment/wechat/notify → ParsePayment → ledger(success only) → SuccessResponse")
	fmt.Println("POST /payment/wechat/refund-notify → ParseRefund → refund ledger → SuccessResponse")
}
Output:
POST /payment/wechat/notify → ParsePayment → ledger(success only) → SuccessResponse
POST /payment/wechat/refund-notify → ParseRefund → refund ledger → SuccessResponse
Example (PayAndNotify)

Example_payAndNotify 演示 Native 下单与支付/退款回调步骤。 可运行的通用支付回调形态见 payment.Example_paymentNotifyHandler。

package main

import (
	"fmt"
)

func main() {
	fmt.Println("1. result, err := client.Pay(ctx, order)  // PayURL = code_url")
	fmt.Println("2. notify, err := client.ParsePaymentNotification(ctx, r)")
	fmt.Println("3. // 仅 success:事务内核对 OrderID/Amount 并幂等入账")
	fmt.Println("4. client.SuccessResponse().WriteTo(w)  // JSON SUCCESS")
	fmt.Println("5. refundNotify, err := client.ParseRefundNotification(ctx, r)")
	fmt.Println("6. // 退款流水入账(非支付成功账)")
	fmt.Println("7. client.SuccessResponse().WriteTo(w)  // 与支付回调同一回执格式")
}
Output:
1. result, err := client.Pay(ctx, order)  // PayURL = code_url
2. notify, err := client.ParsePaymentNotification(ctx, r)
3. // 仅 success:事务内核对 OrderID/Amount 并幂等入账
4. client.SuccessResponse().WriteTo(w)  // JSON SUCCESS
5. refundNotify, err := client.ParseRefundNotification(ctx, r)
6. // 退款流水入账(非支付成功账)
7. client.SuccessResponse().WriteTo(w)  // 与支付回调同一回执格式

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// AppID 是公众号或应用 ID。
	AppID string
	// OAuthAppSecret 是公众号网页授权密钥。
	OAuthAppSecret string
	// MchID 是微信支付商户号。
	MchID string
	// MerchantSerialNo 是商户 API 证书序列号。
	MerchantSerialNo string
	// MerchantPrivateKey 是商户 API 私钥 PEM 内容。
	MerchantPrivateKey string
	// APIV3Key 是 32 字节 API v3 密钥。
	APIV3Key string
	// VerifyMode 指定验签方式。
	// 为空时:公钥齐全 → public_key,静态证书齐全 → platform_cert_static;
	// 材料皆空须显式 platform_cert_auto,否则配置错误。
	// 合法值:public_key、platform_cert_static、platform_cert_auto。
	VerifyMode VerifyMode
	// WechatPayPublicKey 是微信支付公钥 PEM 内容(公钥模式)。
	// 与平台证书模式二选一。
	WechatPayPublicKey string
	// WechatPayPublicKeyID 是微信支付公钥 ID(公钥模式,含 PUB_KEY_ID_ 前缀时请保留)。
	WechatPayPublicKeyID string
	// PlatformCert 是微信平台证书 PEM 内容(平台证书静态模式)。
	// 与 PlatformCertSerialNo 配套。若 PEM 为 CERTIFICATE,初始化时会与序列号交叉校验。
	// 轮换期间微信可能并存两张有效证书;静态模式只登记单序列号,请优先自动模式。
	PlatformCert string
	// PlatformCertSerialNo 是微信平台证书序列号(平台证书静态模式)。
	// 与商户平台展示一致:十六进制大写、可带或不带冒号,比较前会规范化。
	PlatformCertSerialNo string
	// PlatformCertAutoRefresh 控制平台证书自动模式是否定时刷新。
	// 仅平台证书自动模式生效;nil 或 true 为默认开启,false 关闭。
	// 开启时 gopay 会启动后台 goroutine(约 12h),与 client 同生命周期且无法停止;
	// 短生命周期/测试场景请设为 false。在公钥或静态模式下设置会返回配置错误。
	PlatformCertAutoRefresh *bool
}

Config 定义微信支付 V3 配置。

支持两种「验证微信支付身份」方式(二选一,与商户平台一致):

  1. 微信支付公钥:WechatPayPublicKey + WechatPayPublicKeyID
  2. 平台证书: - 静态:PlatformCert + PlatformCertSerialNo(离线/固定证书,单序列号) - 自动:VerifyMode=platform_cert_auto,启动时 API 拉取并默认每 12 小时刷新

VerifyMode 为空时仅按材料推断公钥或静态证书模式;材料皆空不会静默进入自动拉证, 须显式设置 VerifyModePlatformCertAuto(fail-closed,与支付宝 adapter 一致)。

func (Config) ResolveVerifyMode added in v0.2.0

func (c Config) ResolveVerifyMode() VerifyMode

ResolveVerifyMode 返回最终生效的验签模式(含空 VerifyMode 时的字段推断)。 非法或材料不足无法推断时返回空字符串;经 New 创建时 validateConfig 会拒绝。

type Option

type Option func(*options)

Option 定义微信适配器选项。

func WithHTTPTransport

func WithHTTPTransport(transport http.RoundTripper) Option

WithHTTPTransport 设置 HTTP transport。

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger 设置结构化日志器。

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout 设置 HTTP 超时。

type VerifyMode added in v0.2.0

type VerifyMode string

VerifyMode 指定商户平台「验证微信支付身份」所用验签方式。

与商户平台两种方式对齐(只能启用一种);平台证书再细分为静态与自动拉取。

const (
	// VerifyModePublicKey 使用微信支付公钥验签。
	// 须配置 WechatPayPublicKey + WechatPayPublicKeyID。
	VerifyModePublicKey VerifyMode = "public_key"
	// VerifyModePlatformCertStatic 使用配置中的平台证书 PEM 验签。
	// 须配置 PlatformCert + PlatformCertSerialNo。
	// 仅登记单张证书序列号;证书轮换窗口请优先自动模式。
	VerifyModePlatformCertStatic VerifyMode = "platform_cert_static"
	// VerifyModePlatformCertAuto 启动时通过 API 拉取平台证书并(默认定时)刷新。
	// 须显式设置;不配置公钥与静态证书字段。
	VerifyModePlatformCertAuto VerifyMode = "platform_cert_auto"
)

type WechatPay

type WechatPay struct {
	// contains filtered or unexported fields
}

WechatPay 实现微信 Native、JSAPI、查询、退款、关单和回调处理。

func New

func New(config Config, opts ...Option) (*WechatPay, error)

New 创建微信支付适配器。

配置须与商户平台「验证微信支付身份」当前启用方式一致:

  • 公钥:WechatPayPublicKey + WechatPayPublicKeyID(可省略 VerifyMode)
  • 平台证书静态:PlatformCert + PlatformCertSerialNo(可省略 VerifyMode)
  • 平台证书自动:须显式 VerifyModePlatformCertAuto(材料皆空时不会静默自动拉证)

平台证书自动模式在初始化时会请求微信证书接口;默认定时刷新会启动后台 goroutine。 网络类失败多为 payment.ErrGateway,PEM/参数及部分配置类失败为 payment.ErrInvalidConfig。 详见包文档与 Config 字段说明。

Example

ExampleNew 演示微信支付公钥验签模式构造(凭证请替换为真实材料)。 本示例不连接网关,仅展示推荐配置形态。

package main

import (
	"fmt"

	"github.com/f2xme/gox/payment/adapter/wechat"
)

func main() {
	_ = wechat.VerifyModePublicKey
	fmt.Println("wechat.New(wechat.Config{")
	fmt.Println("  AppID, MchID, MerchantSerialNo, MerchantPrivateKey, APIV3Key,")
	fmt.Println("  WechatPayPublicKey, WechatPayPublicKeyID,")
	fmt.Println("})")
}
Output:
wechat.New(wechat.Config{
  AppID, MchID, MerchantSerialNo, MerchantPrivateKey, APIV3Key,
  WechatPayPublicKey, WechatPayPublicKeyID,
})
Example (PlatformCertAuto)

ExampleNew_platformCertAuto 演示平台证书自动拉证模式。

package main

import (
	"fmt"

	"github.com/f2xme/gox/payment/adapter/wechat"
)

func main() {
	_ = wechat.VerifyModePlatformCertAuto
	fmt.Println("VerifyMode: wechat.VerifyModePlatformCertAuto")
	fmt.Println("New 时会请求微信证书接口;生产建议单例")
}
Output:
VerifyMode: wechat.VerifyModePlatformCertAuto
New 时会请求微信证书接口;生产建议单例

func (*WechatPay) Close

func (w *WechatPay) Close(ctx context.Context, orderID string) error

Close 关闭微信支付订单。

func (*WechatPay) ExchangeOAuthCode

func (w *WechatPay) ExchangeOAuthCode(ctx context.Context, code string) (string, error)

ExchangeOAuthCode 使用网页授权 code 换取 openid。

func (*WechatPay) JSAPIPay

func (w *WechatPay) JSAPIPay(ctx context.Context, order *payment.Order, openID string) (*payment.JSAPIResult, error)

JSAPIPay 创建 JSAPI 预支付单及前端调起参数。

func (*WechatPay) OAuthURL

func (w *WechatPay) OAuthURL(redirectURL, state string) (string, error)

OAuthURL 创建微信网页授权地址,scope 固定为 snsapi_base。

func (*WechatPay) ParsePaymentNotification

func (w *WechatPay) ParsePaymentNotification(ctx context.Context, req *http.Request) (*payment.PaymentNotification, error)

ParsePaymentNotification 验签、解密并解析微信支付通知。

func (*WechatPay) ParseRefundNotification

func (w *WechatPay) ParseRefundNotification(ctx context.Context, req *http.Request) (*payment.RefundNotification, error)

ParseRefundNotification 验签、解密并解析微信退款通知。

func (*WechatPay) Pay

func (w *WechatPay) Pay(ctx context.Context, order *payment.Order) (*payment.PaymentResult, error)

Pay 发起微信 Native 支付并返回二维码内容。

func (*WechatPay) Query

func (w *WechatPay) Query(ctx context.Context, orderID string) (*payment.QueryResult, error)

Query 查询微信支付订单。

func (*WechatPay) Refund

Refund 发起微信退款。

func (*WechatPay) SuccessResponse

func (w *WechatPay) SuccessResponse() payment.NotifyResponse

SuccessResponse 返回微信要求的成功回执。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL