微信公众号迁移Serverless详解
Jul 17 20183月腾讯云函数计算开放测试, 看到的第一反应是这种Serverless太适合做微信公众号的后端来实现自动应答了, 尝试把我服务了3年的一个公众号迁移到腾讯云函数计算, 结果因为API gateway的一个功能缺失搁置了, 这周腾讯云API gateway终于补上了集成响应的能力, 能正常服务我的公众号, 这里记录下实现过程.
改造werobot
https://github.com/zhu327/ifwechat
ifwechat这个公众号是基于werobot实现的, 之前以WSGI的方式部署在SAE上, 而不同于WSGI, 函数计算从API gateway触发的事件是一个Python的字典, 需要从这个事件字典里面获取http request的信息来调用werobot的方法. API gateway的触发事件参考: https://cloud.tencent.com/document/product/583/13197
需要实现一个从http request事件到werobot的message的wrapper handler:
# coding: utf-8
from handlers import robot
robot.config.from_pyfile('configs.py')
def werobot_handler(event):
timestamp = event["queryString"].get("timestamp", "")
nonce = event["queryString"].get("nonce", "")
signature = event["queryString"].get("signature", "")
if not robot.check_signature(timestamp=timestamp,
nonce=nonce,
signature=signature):
return "error: wrong wechat signature"
if event["requestContext"]["httpMethod"] == "GET":
return event["queryString"].get("echostr", "")
elif event["requestContext"]["httpMethod"] == "POST":
body = event["body"].event["body"].replace('\\u003c', '<').replace('\\u003e', '>').decode('utf8')
message = robot.parse_message(
body,
timestamp=timestamp,
nonce=nonce,
msg_signature=event["queryString"].get("msg_signature", ""))
return robot.get_encrypted_reply(message)
在API gateway上创建API时需要勾选集成响应功能, 并且在函数入口返回的格式如下:
# coding: utf-8
from scf_werobot import werobot_handler
def main_handler(event, context):
if "requestContext" not in event.keys():
return "error: event is not come from api gateway"
content = werobot_handler(event)
return {
"statusCode": 200,
"headers": {"Content-Type": "application/xml"},
"body": content
}
通过cos实现werobot的session
除了计算外, ifwechat还用到了werobot的session来存微信用户与ifttt用户之间的对应关系, 在SAE上部署session数据是存在SAE的kvdb里的, 但是在腾讯云这里就没有免费的Redis或者MySQL来用了. 在研究zappa这个serverless框架的时候, 发现他们用AWS S3实现了一个NoDB的库可用用来做kvdb, 而腾讯云对标S3存储的就是cos, 把NoDB fork修改S3代码改成cos sdk调用, 就有了这个NoDB for Tencent Cloud COS
继承werobot的SessionStorage实现用NoDB来做session backend:
# coding: utf-8
from werobot.session import SessionStorage
from nodb import NoDB
class NoDBStorage(SessionStorage):
def __init__(self, secret_id, secret_key, region, bucket):
self.nodb = NoDB(secret_id, secret_key, region)
self.nodb.bucket = bucket
def get(self, id):
return self.nodb.load(id) or {}
def set(self, id, value):
self.nodb.save(value, id)
def delete(self, id):
self.nodb.delete(id)
def __getitem__(self, id):
return self.get(id)
def __setitem__(self, id, session):
self.set(id, session)
def __delitem__(self, id):
self.delete(id)
打包所有代码为zip文件, 并发布到scf就完成了这个迁移过程.
关于zappa
从迁移过程的体验来看, 功能的开发还是很简单的, 只是部署的过程不是很友好, 如果能有一个类似于zappa这样的自动化部署框架来对接到腾讯云函数计算, 相信对开发者来说会更友好.