花呗支付示例

本文将介绍如何使用EMAS Serverless调用开发一个具有花呗支付能力的小程序。

准备工作

在开始前,确保您已经完成以下准备工作:

  • 注册支付宝企业开发者账号。

    如果您尚未注册支付宝小程序账号,使用支付宝账号登录蚂蚁金服开放平台,并完成企业开发者身份注册。详细信息,请参见开发者入驻说明

  • 下载并安装支付宝小程序开发者工具。

    详细信息,请参见下载说明

  • 已安装Node.js开发环境。

步骤一:开通EMAS服务

  1. 登录阿里云控制台

  2. 鼠标悬停在左上角的图标上,然后在产品与服务中,打开产品和服务列表。

  3. 在产品列表中,选择企业服务与云通信 > 移动研发平台,进入产品介绍页。

  4. 在产品介绍页中单击立即开通

步骤二:创建项目和应用

小程序开发中创建的云资源会和服务空间进行关联。每个服务空间都有一个全局唯一的space ID。在使用云资源时,都通过这个space ID进行关联。参考以下步骤,创建服务空间并设置数据库权限:

创建服务空间

小程序开发中创建的云资源会和服务空间进行关联。每个服务空间都有一个全局唯一的space ID。在使用云资源时,都通过这个space ID进行关联。参考以下步骤,创建服务空间。

  1. 登录EMAS管理控制台

  2. 选择步骤二中已创建的项目,单击项目,进入EMAS概览页。

  3. 在顶部导航栏,选择平台服务

  4. 在左侧导航栏,单击EMAS Serverless

  5. 单击创建服务空间

  6. 创建服务空间页面,填写如下信息。

    参数名

    说明

    服务空间名称

    您可根据需要自定义服务空间名称,名称规则:

    • 只能包含字母、数字

    • 不能以数字开头

    • 长度限制在 3-15 之间

    描述

    简要描述服务空间的用途。

    支付方式

    包含套餐按量付费两种。

    说明

    当选择套餐方式时,可设置到期自动续费如果您购买的是开发者版套餐,请勿开启自动续费,开发者版只允许手动续费,自动续费将会失败。

  7. 单击创建并支付

    服务空间创建成功后,在详情页可查看以下信息:

    空间基本信息页签,可展示空间名称空间状态计费模式等信息。

    空间接入信息页签,可查看SpaceIDSecretAPI Endpoint文件上传Endpoint等信息。

设置数据库权限

  1. 在EMAS Serverless控制台页面,选择,然后在页面右上角选择已创建的服务空间。

  2. 云数据库页面,单击立即添加

    数据表

  3. 新建数据表对话框中,输入数据表名称,单击确定

  4. 单击您的数据表,然后选择权限>编辑权限

    说明

    为了保证数据安全,默认数据库访问受限。您需要根据需要设置数据库权限,更多详细信息,请参见数据权限管理

  5. 在权限管理页面,单击自定义安全规则,将write权限修改为true。权限

步骤三:开通扩展能力

  1. 登录EMAS管理控制台

  2. 查找您的项目,单击项目,进入EMAS概览页。

  3. 在顶部导航栏,选择平台服务

  4. 在左侧导航栏,选择

  5. 扩展能力页面,单击立即开通

  6. 在弹出的对话框,单击前往RAM进行授权,然后单击同意授权允许小程序访问函数计算服务。

  7. 返回扩展能力页面,查看开通状态。

步骤四:创建支付宝小程序应用

参考以下步骤,在蚂蚁金服开放平台创建支付宝小程序:

  1. 使用支付宝账号登录蚂蚁金服开放平台,单击控制台

    控制台

  2. 选择小程序应用,然后单击创建应用并根据引导创建一个小程序应用。

  3. 在左侧导航栏单击设置

  4. 单击开发设置,在开发信息下的接口加签方式区域配置支付宝公钥。

    您可以通过RSA密钥生成工具一键生成小程序密钥。接口加签方式有普通公钥和证书公钥两种,主要用于签名和验证。其中私钥由开发者保存,公钥可对外公开,私钥用于签名,公钥用于验证签名。开发者需要保存自己的私钥,通过支付宝提供的公钥进行通信来保证信息传输的完整性以及发送者身份的真实性。详细信息,请参见生成支付宝RSA密钥

    重要

    企业开发者若涉及资金类支出接口接入,必须使用公钥证书模式。

  5. 在小程序详情开发管理页面的功能列表中,单击右上角添加功能按钮,添加小程序支付

    小程序支付功能需要签约才能生效,在小程序上线后,单击功能列表右侧签约。签约完成后,需要1个工作日左右的审批时间(审批结果会以短信和邮件形式告知),审批成功后,功能状态会变为已生效

步骤五:添加支付宝小程序

在开发前,您需要将支付宝小程序信息添加到阿里云EMAS Serverless控制台。

完成以下操作,添加支付宝小程序信息:

  1. 登录EMAS管理控制台

  2. 查找您的项目,单击项目,进入EMAS概览页。

  3. 在顶部导航栏,选择平台服务

  4. 在左侧导航栏,选择设置

  5. 单击支付宝页签,然后单击添加密钥

  6. 输入您的私钥,即步骤四中生成的小程序RSA私钥。

  7. 输入支付宝公钥,支付宝公钥从蚂蚁金服开放平台->开发中心->设置->开发设置->开发信息中的接口加签方式中查看获取。

步骤六:获取模板代码

  1. 打开小程序开发工具,选择小程序开发。

  2. 选择支付宝小程序,然后小程序模板的开放能力分类中选择花呗支付模板。花呗

  3. 单击下一步,设置项目名称和项目路径,完成项目创建。

步骤七:快速体验

  1. 在小程序开发者工具中登录支付宝开发者账号,然后关联对应的小程序。

  2. client/pages/app.js中对应的如下小程序配置项改为用户自己的参数。

    appId: '2021*********', // 小程序应用标识
    spaceId: 'ca8eb10f-26c1-4bee-**********', // 服务空间标识
    clientSecret: 'Xckz2************', // 服务空间 secret key
    endpoint: 'https://api.************' // 服务空间地址,从EMAS Serverless控制台处获得     

    appId即在EMAS Serverless中设置的AppId,spaceId、clientSecret、endpoint参数请查看EMAS Serverless服务空间详情,请参考步骤二。

    保存文件后,打开IDE的真机调试,就可以在您的手机支付宝上使用小程序进行花呗支付。至此,我们已经完成了一个简单的花呗支付小程序的搭建,并将最核心的能力使用EMAS Serverless开发完成。

小程序云Serverless代码详解

  • 初始化Serverless SDK

    在使用EMAS Serverless服务前,需要您在小程序中安装EMAS Serverless客户端SDK并初始化。EMAS Serverless客户端SDK的更多信息请参见安装客户端SDK2.2版本

    // client/app.js
    import MPServerless from '@alicloud/mpserverless-sdk';
    const mpserverless = new MPServerless({
      uploadFile: my.uploadFile,
      request: my.request,
      getAuthCode: my.getAuthCode,
    }, {
      appId: ' ', // 小程序应用标识
      spaceId: ' ', // 服务空间标识
      clientSecret: ' ', // 服务空间 secret key
      endpoint: ' ' // 服务空间地址,从EMAS Serverless控制台处获得
    });    
  • 初始化云调用SDK并授权登录

    要使用EMAS Serverless提供的扩展能力,您需要先在控制台开通云调用功能,然后在小程序中安装云调用SDK并进行初始化。

    在调用EMAS Serverless服务前,需要先调用authorize接口请求授权,支付宝小程序的授权请求参数authProvider应为alipay_openapi, 更多信息请参见authorize

    // client/app.js
    import cloud from 'alipay-serverless-sdk';
    cloud.init(my.serverless);
    App({
      async onLaunch(options) {
        var res = await my.serverless.user.authorize({
          authProvider: 'alipay_openapi',
        });
      },
    });
                        
  • 创建交易

    以下代码调用payment.common.create和cloud.payment.huabei.create接口实现了创建直接付款订单和花呗分期付款交易能力,更多直接付款和花呗分期接口信息请参见payment.common.createpayment.huabei.create

    async tradeCreate() {
        let createRes
        if (this.data.checked === '1') {
          // 直接付款
          createRes = await cloud.payment.common.create('EMAS Serverless支付测试', "demo" + new Date().getTime(), '0.03', this.data.userId);
        } else {
          // 花呗分期
          var huabeiConfig = new Object({
            hbFqNum: "3",
            hbFqSellerPercent: "100"
          });
          createRes = await cloud.payment.huabei.create('EMAS Serverless支付测试', "demo" + new Date().getTime(), '0.03', this.data.userId, huabeiConfig);
        }
        this.setData({
          tradeNO: createRes.tradeNo,
          outTradeNo: createRes.outTradeNo
        })
        return createRes.tradeNo
      },
  • 付款

    以下代码调用my.tradePay支付宝开放能力API唤起支付宝收银台进行支付,更多小程序支付信息请参见小程序支付

    async onRepeatPayHandler(data) {
        my.tradePay({
          tradeNO: this.data.tradeNO,
          success: async (res) => {
            if (res.resultCode === "9000") {
              my.alert({
                title: '支付成功',
                content: res.resultCode,
              });
              const value = data.currentTarget.dataset.item
              const { key } = value
              const { paymentHistory } = this.data
              paymentHistory.map(v => {
                if (v.key === key) {
                  v.tradeStatus = 'TRADE_SUCCESS'
                }
              })
              my.serverless.db.collection('payment').updateOne({
                key
              }, {
                $set: {
                  tradeStatus: 'TRADE_SUCCESS'
                }
              })
              this.setData({
                paymentHistory
              })
            }
          },
        });
      },
  • 退款

    以下代码调用payment.common.refund云调用接口进行退款操作,更多信息请参见payment.common.refund

    async onRefundPayHandler(data) {
        const value = data.currentTarget.dataset.item
        const { outTradeNo, totalAmount, key } = value
        const rs = await cloud.payment.common.refund(outTradeNo, String(totalAmount))
        if (rs.code === "10000") {
          my.showToast({
            content: '退款成功',
          });
          const { paymentHistory } = this.data
          paymentHistory.map(v => {
            if (v.key === key) {
              v.tradeStatus = 'TRADE_CLOSED'
            }
          })
          this.setData({
            paymentHistory
          })
          my.serverless.db.collection('payment').updateOne({
            key
          }, {
            $set: {
              tradeStatus: 'TRADE_CLOSED'
            }
          })
        } else {
          my.showToast({
            content: '退款失败',
          });
        }
        console.log(rs)
      },