lameleg

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

  •  1
     
  •   lameleg · Aug 18, 2022 · 3311 views
    This topic created in 1372 days ago, the information mentioned may be changed or developed.

    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 replies    2022-08-19 19:46:10 +08:00
    singerll
        1
    singerll  
       Aug 18, 2022 via Android   ❤️ 1
    那么问题来了,这个码是不是还要用 gui 去扫。。。
    lameleg
        2
    lameleg  
    OP
       Aug 18, 2022
    @singerll 这锅只能甩给微信团队了 哈哈。 要是加密货币就完全脱离 GUI 了
    snoopyhai
        3
    snoopyhai  
       Aug 18, 2022
    二维码为什么是图片. 不应该是用字符矩阵一个么
    lameleg
        4
    lameleg  
    OP
       Aug 18, 2022
    @snoopyhai 这可不是图片,字符拼起来的
    lameleg
        5
    lameleg  
    OP
       Aug 18, 2022   ❤️ 1
    @snoopyhai ASCII 'half blocks'
    fxzx
        6
    fxzx  
       Aug 19, 2022 via Android
    HICA 就是这样收款的😂
    my3157
        7
    my3157  
       Aug 19, 2022 via Android
    首先得有个女朋友
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5694 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 74ms · UTC 02:30 · PVG 10:30 · LAX 19:30 · JFK 22:30
    ♥ Do have faith in what you're doing.