巧用 Serverless,轻松搭建微信公众号的智能后台服务

一般来说,想给微信公众号增加更多的功能,需要有一台服务器,来进行公众号后台服务的搭建。那么在 Serverless 架构下,是否有更简便的方法来实现这么一个公众号后台呢?我们试试?

初步搭建

Serverless 原生开发

首先我们当然要有一个微信公众号!

接下来,我们要为我们的函数计算服务申请固定 IP:

点击白名单之后,我们可以填写表单,完成固定公网出口 IP 的申请。

接下来进行代码开发。

  1. 将函数绑定到公众号后台,参考文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html 我们可以先在函数中按照文档完成一个基本的鉴定功能:
def checkSignature(param):
    '''
    文档地址:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
    :param param:
    :return:
    '''
    signature = param['signature']
    timestamp = param['timestamp']
    nonce = param["nonce"]
    tmparr = [wxtoken, timestamp, nonce]
    tmparr.sort()
    tmpstr = ''.join(tmparr)
    tmpstr = hashlib.sha1(tmpstr.encode("utf-8")).hexdigest()
    return tmpstr == signature

再定义一个基本的回复方法:

def response(body, status=200):
    return {
        "isBase64Encoded": False,
        "statusCode": status,
        "headers": {"Content-Type": "text/html"},
        "body": body
    }

然后在函数入口处:

def main_handler(event, context):    
    if 'echostr' in event['queryString']:  # 接入时的校验
        return response(event['queryString']['echostr'] if checkSignature(event['queryString']) else False)

配置我们 Yaml:

# serverless.yml
Weixin_GoServerless:
  component: "@serverless/tencent-scf"
  inputs:
    name: Weixin_GoServerless
    codeUri: ./Admin
    handler: index.main_handler
    runtime: Python3.6
    region: ap-shanghai
    description: 微信公众号后台服务器配置
    memorySize: 128
    timeout: 20
    environment:
      variables:
        wxtoken: 自定义一个字符串
        appid: 暂时不写
        secret: 暂时不写
    events:
      - apigw:
          name: Weixin_GoServerless
          parameters:
            protocols:
              - https
            environment: release
            endpoints:
              - path: /
                method: ANY
                function:
                  isIntegratedResponse: TRUE

执行代码,完成部署:

接下来在公众号后台,选择基本配置:

选择修改配置:

这里要注意:

  • URL,写我们刚才部署完成返回给我们的地址,并且在最后加一个 /

  • Token,写我们 Yaml 中的 wxtoken,两个地方要保持一样的字符串

  • EncodingAESKey,可以点击随机生成

  • 消息加密方法可以选择明文

完成之后,我们可以点击提交:

看到提交成功,就说明我们已经完成了第一步骤的绑定。接下来,我们到函数的后台:

打开固定出口 IP,看到 IP 地址之后,复制 IP 地址:

点击查看->修改,并将 IP 地址复制粘贴进来,保存。
同时我们查看开发者 ID 和密码:

并将这两个内容复制粘贴,放到我们环境变量中:

至此,我们完成了一个公众号后台服务的绑定。

为了方便之后的操作,先获取一下全局变量:

wxtoken = os.environ.get('wxtoken')
appid = os.environ.get('appid')
secret = os.environ.get('secret')
  1. 接下来对各个模块进行编辑(本文只提供部分简单基础的模块,更多功能实现可以参考微信公众号文档实现)
  • 获取 AccessToken 模块:
def getAccessToken():
    '''
    文档地址:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
    正常返回:{"access_token":"ACCESS_TOKEN","expires_in":7200}
    异常返回:{"errcode":40013,"errmsg":"invalid appid"}
    :return:
    '''
    url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s" % (appid, secret)
    accessToken = json.loads(urllib.request.urlopen(url).read().decode("utf-8"))
    print(accessToken)
    return None if "errcode" in accessToken else accessToken["access_token"]
  • 创建自定义菜单模块:
def setMenu(menu):
    '''
    文档地址:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html
    正确返回:{"errcode":0,"errmsg":"ok"}
    异常返回:{"errcode":40018,"errmsg":"invalid button name size"}
    :return:
    '''
    accessToken = getAccessToken()
    if not accessToken:
        return "Get Access Token Error"

    url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s" % accessToken
    postData = urllib.parse.urlencode(menu).encode("utf-8")
    requestAttr = urllib.request.Request(url=url, data=postData)
    responseAttr = urllib.request.urlopen(requestAttr)
    responseData = json.loads(responseAttr.read())
    return responseData['errmsg'] if "errcode" in responseData else "success"
  • 常见消息回复模块:
def textXML(body, event):
    '''
    :param body: {"msg": "test"}
        msg: 必填,回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)
    :param event:
    :return:
    '''
    return """<xml><ToUserName><![CDATA[{toUser}]]></ToUserName>
              <FromUserName><![CDATA[{fromUser}]]></FromUserName>
              <CreateTime>{time}</CreateTime>
              <MsgType><![CDATA[text]]></MsgType>
              <Content><![CDATA[{msg}]]></Content></xml>""".format(toUser=event["FromUserName"],
                                                                   fromUser=event["ToUserName"],
                                                                   time=int(time.time()),
                                                                   msg=body["msg"])


def pictureXML(body, event):
    '''
    :param body:  {"media_id": 123}
        media_id: 必填,通过素
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值