V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lameleg
V2EX  ›  开源软件

有没有见过在 terminal 里用微信支付?

  •  1
     
  •   lameleg · 2022-08-18 11:24:53 +08:00 · 2075 次点击
    这是一个创建于 826 天前的主题,其中的信息可能已经有所发展或是发生改变。

    sealos 是一款云操作系统发行版,可以非常简单的管理 kubernetes 的生命周期,以及像使用 win11 一样使用云,最近写 sealos cloud 的支付模块,发现可以通过命令行做微信支付,非常有意思,现在和大家分享一下如何做到的。

    输入一条命令,终端会输出二维码,直接微信扫一扫就可以付钱,这对于极客来说真是福音,对于一个藐视使用 GUI 的人来说岂不是很香?为了站在鄙视链顶端( API 鄙视 as code 鄙视 CLI 鄙视 GUI )岂能不支持这么酷的特性~

    使用场景:

    • 想想你充爱奇艺会员的时候咔敲个命令,扫一扫搞定,女朋友在旁边不得亚麻呆住?

    • 想想现在很多屎山一样的前端页面,半天都找不到按钮在哪,一条命令充值岂不是很酸爽?

    • 想想你执行一个命令突然提示欠费蹦出个二维码让你充值执行

    • 想想数据库备份日志显示一个二维码,扫码继续备份

    下面开始教程:

    使用微信 native 支付方式

    native 支付会向微信支付服务发送一条请求,微信支付会返回一个 codeurl, 直接把这个 codeurl 转化成二维码,即可用微信扫描支付。

    我们自己服务端写一个获取 code-url 的接口:

    ws.Route(ws.GET("/wechat/code-url").To(u.getCodeURL)
    func (u Payment) getCodeURL(request *restful.Request, response *restful.Response) {
    amount := request.QueryParameter("amount")
       user := request.QueryParameter("user")
       a, err := strconv.Atoi(amount)
       codeURL, err := WechatPay(int64(a), user, "", "", os.Getenv(CallbackURL))
       _, err = response.Write([]byte(codeURL))
    }
    

    这里获取谁( user )充值多少 (amout) 钱, (省去了非核心逻辑)

    支付请求实现:

    func WechatPay(amount int64, user, tradeNO, describe, callback string) (string, error) {
       mchID := os.Getenv(MchID)                                           // 商户号
       mchCertificateSerialNumber := os.Getenv(MchCertificateSerialNumber) // 商户证书序列号
       mchAPIv3Key := os.Getenv(MchAPIv3Key)                               // 商户 APIv3 密钥
       mchPrivateKey, err := utils.LoadPrivateKey(os.Getenv(WechatPrivateKey))
    
       ctx := context.Background()
       opts := []core.ClientOption{
          option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
       }
       client, err := core.NewClient(ctx, opts...)
    
       svc := native.NativeApiService{Client: client}
       resp, _, err := svc.Prepay(ctx,
          native.PrepayRequest{
             Appid:         core.String(os.Getenv(AppID)),
             Mchid:         core.String(os.Getenv(MchID)),
             Description:   core.String(describe),
             OutTradeNo:    core.String(tradeNO),
             TimeExpire:    core.Time(time.Now()),
             Attach:        core.String(user),
             NotifyUrl:     core.String(callback),
             GoodsTag:      core.String("sealos recharge"),
             SupportFapiao: core.Bool(false),
             Amount: &native.Amount{
                Currency: core.String("CNY"),
                Total:    core.Int64(amount),
             },
             Detail: &native.Detail{
                CostPrice: core.Int64(608800),
                GoodsDetail: []native.GoodsDetail{
                   {
                      GoodsName:        core.String("sealos cloud recharge"),
                      MerchantGoodsId:  core.String("ABC"),
                      Quantity:         core.Int64(1),
                      UnitPrice:        core.Int64(828800),
                      WechatpayGoodsId: core.String("1001"),
                   }},
             },
             SettleInfo: &native.SettleInfo{
                ProfitSharing: core.Bool(false),
             },
          },
       )
    
       return *resp.CodeUrl, nil
    }
    

    此接口会返回这样的一个字符串,也就是我们需要转化成二维码的:

    weixin://wxpay/bizpayurl?pr=aIQrOYOzz
    

    命令行客户端实现

    以上实现了服务端代码,现在在命令行实现一下客户端代码即可,客户端无非是个 http 请求然后把返回结果用命令行二维码库转化一下即可。

    RunE: func(cmd *cobra.Command, args []string) error {
       fmt.Printf("Use WeChat to scan the QR code below to recharge, please make sure the username and amount are correct\n")
       fmt.Printf("User: %s\n", config.User)
       fmt.Printf("Amount: %d\n", config.Amount)
    
    return api.QRTerminalPay(config.User, config.Amount*100, "")
    }
    

    实现:

    func QRTerminalPay(user string, amount int64, domain string) error {
    if domain == "" {
          domain = "http://localhost:8071"
       }
    
       url := fmt.Sprintf("%s/payment/wechat/code-url?amount=%d&user=%s", domain, amount, user)
       resp, err := http.Get(url)
    defer resp.Body.Close()
       b, err := io.ReadAll(resp.Body)
    
       qrterminal.Generate(string(b), qrterminal.L, os.Stdout)
    return nil
    }
    

    效果:

    直接执行命令:

    sealos recharge --user fanux --amount 1
    

    终端就会输出二维码

    手机微信扫一扫:

    大功告成~

    完整代码在 sealos 中,有需要的可以去 copy~

    7 条回复    2022-08-19 19:46:10 +08:00
    singerll
        1
    singerll  
       2022-08-18 11:28:36 +08:00 via Android   ❤️ 1
    那么问题来了,这个码是不是还要用 gui 去扫。。。
    lameleg
        2
    lameleg  
    OP
       2022-08-18 11:35:38 +08:00
    @singerll 这锅只能甩给微信团队了 哈哈。 要是加密货币就完全脱离 GUI 了
    snoopyhai
        3
    snoopyhai  
       2022-08-18 14:56:19 +08:00
    二维码为什么是图片. 不应该是用字符矩阵一个么
    lameleg
        4
    lameleg  
    OP
       2022-08-18 17:30:53 +08:00
    @snoopyhai 这可不是图片,字符拼起来的
    lameleg
        5
    lameleg  
    OP
       2022-08-18 19:17:39 +08:00   ❤️ 1
    @snoopyhai ASCII 'half blocks'
    fxzx
        6
    fxzx  
       2022-08-19 18:14:24 +08:00 via Android
    HICA 就是这样收款的😂
    my3157
        7
    my3157  
       2022-08-19 19:46:10 +08:00 via Android
    首先得有个女朋友
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1064 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 19:25 · PVG 03:25 · LAX 11:25 · JFK 14:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.