Flask-WeChat 微信Flask扩展

入门

  • 如果你刚开始使用 Flask-WeChat,你可以从遵照 docs/getting_started 教程开始入门。
  • 你也可以查阅 FAQ

目录

一个最小应用

该应用首先初始化了Flask-WeChat扩展,随后注册id为demo的公众号, 当接收到id为demo的公众号的回调时,返回该公众号的配置。 在应用中,开发者通过扩展内预定义的过滤器(filters), 注册了订阅事件、所有事件、接收到以hello开头的文本事件三种事件的处理器。 当应用收到用户发送的微信消息时,将找到对应的处理事件,并根据处理事件的返回, 进行相应回复。

from flask import Flask
from flask.ext.wechat import filters, WeChat

app = Flask(__name__)

wechat = WeChat(app)

@wechat.account
def get_config(id):
    return dict(
        appid="appid",
        appsecret="appsecret",
        token="token"
    ) if id=="demo" else dict()

@wechat.handler("demo", filters.event.subscribe)
def subscribe(message):
    return message.reply_text("Thank you for subscribe!")

@wechat.handler("demo")
def all(message):
    return message.reply_text("I'm confused...")

@wechat.handler("demo", filters.message.startswith("hello"))
def hello(message):
    return message.reply_text("world")

if __name__ == "__main__":
    app.run()

入门

创建实例

from flask.ext.wechat import WeChat

wechat = WeChat(app)

你也可以延迟初始化app

from flask.ext.wechat import WeChat

wechat = WeChat()

...

wechat.init_app(app)

注册获取配置函数

你需要注册一个获取微信配置用的函数。这个函数使用 ** wechat.account ** 进行装饰。 被装饰函数接收一个参数id,使用者通过id辨别不同的公众号。 函数以字典形式返回该公众号的appid, appsecret, token。如果该id未被用户使用,则返回空字典。

如果你只使用到微信订阅号自动回复功能,你在返回的字典中可以忽略appsecret与appid, 如果你需要使用 WeChatApiClient 调用微信的API,则你需要返回全部参数。 如果你在在公众平台官网的开发者中心处设置了消息加密,则你还需要返回aeskey, 但目前消息加解密的功能还尚未实现。

@wechat.account
def get_config(id):
    return dict(
        appid="appid",
        appsecret="appsecret",
        token="token"
    ) if id=="demo" else dict()

模块默认的回调地址是/wechat/callbacks/<id>/ ,开发者需将这个地址填入微信后台的回调地址。 这个值的修改可在 配置 中进行。

注册消息处理器

你可以这样注册一个消息处理器(handler):

@wechat.handler("demo", filters.event.subscribe)
def subscribe(message):
    return message.reply_text("Thank you for subscribe!")

要处理来自微信的消息,你需要注册消息处理器。 注册消息处理器使用@wechat.handler 装饰器, 装饰器接收两个参数,第一个参数是使用者定义的公众号id, 第二个参数是用于判断请求是否符合要求的 过滤器 , 暨进入该处理器的条件。

一条消息只会进入一个处理器。

如果你要同时匹配多个过滤器,可以这样传入:

@wechat.handler("demo",
    [filters.message.startswith("hello"), filters.message.contains("world")])

被装饰函数接收一个参数 WeChatRequest 对象,返回一个 WeChatResponse 对象。

WeChatRequest对象的属性包含微信公众平台开发者文档中该微信请求的所有有效字段。 所有属性为全部小写。WeChatResponse对象同理。

警告

除 filters.all 过滤器以外,越迟定义的过滤器拥有越高优先级!

过滤器

模块自定义了一些过滤器方便用户使用。你可以通过

from flask.ext.wechat import filters

来使用他们。关于过滤器的详细说明,可以参考 :ref:`filter`章节。

拦截器

* 尚未实现 *

信号

你可以通过订阅信号的形式了解一些状态的变化,并处理一些逻辑。以下是一个简单的例子:

import logging
from flask.ext.wechat import signals

def callback(sender, identity, **kwargs):
    logging.info("{identity} sent response: {response}"\
        .format(identity=identity, response=kwargs["response"]))

signals.response_sent.connect(callback, wechat)

信号的发送者为WeChat扩展实例,信号将至少接收一个identity参数,暨访问者自定义的公众号id。 在本例中,我们注册了回复已发送的信号。该信号发送于已接收到微信请求,并且成功回复以后。 不包括微信请求异常(Bad Request)回复的状况,但包含控制器抛出未经处理的异常的状况。

注意,使用信号需要安装blinker模块。

关于信号的详细说明,可以参考 :ref:`signal`章节。

请求微信API

微信提供了很多Restful API供开发者调用。通过WeChatApiClient, 开发者可以方便地调用微信的API。

要使用WeChatApiClient,你需要在@wechat.account装饰的函数返回的字典中包含 appid与appsecret项。

并且,你需要注册一个维持公众号accesstoken的函数。

@wechat.accesstoken
def accesstoken(identity, value="", expires_in=7200):
    return "accesstoken"

这个函数使用@wechat.accesstoken 装饰, 被装饰的函数包含3个参数,用户定义的公众号id,新的accesstoken值,accesstoken过期时间。

当WeChatApiClient需要获取accesstoken时,会传入用户定义的公众号id, 你需要返回已知的该公众号accesstoken,如果未知,则返回空。

如果WeChatApiClient更新了accesstoken,会传入用户定义的公众号id, 新的accesstoken值,新accesstoken的在多久以后过期。

注解

建议用户在数据库或cache中维持这个accesstoken,避免每次请求时都对公众号重新获取授权。

WeChatApiClient 构造函数接受一个参数,用户自定义的公众号id。

from flask.ext.wechat import WeChatApiClient

client = WeChatApiClient("test")

调用接口时,用户需要传入接口的url以及其他的一些附加参数, 这些附加参数与python的requests模块一致。可以参见requests模块文档。

注解

接口url默认为 https://api.weixin.qq.com/ ,前缀/cgi_bin 。 如果你需要修改url地址,可以通过修改client的 __baseaddr__ 属性和 __prefix__ 属性来实现。

WeChatApiClient包含三个请求方法 get, get_raw, post。

resp, code = client.get("/get_current_selfmenu_info")
resp, code = client.post("/menu/create", json=dict(button=[{
    "type":"view",
    "name":"搜索",
    "url":"http://www.soso.com/"
}]))

get与post方法返回两个值,第一个值为解析为字典后的返回对象,第二个值为返回中的errcode。 如果code=0 可以认为请求成功。如果code=-2 则说明请求返回的数据异常,无法正常解析(如不是json)。

resp = client.get_raw("/get_current_selfmenu_info")

get_raw 方法直接返回requests.Response 对象。

注解

WeChatApiClient 会在用户请求的querystring上自动加上accesstoken。 当accesstoken过期或是不存在时,WeChatApiClient会尝试更新一次accesstoken。

过滤器

过滤器在@wechat.handler 装饰器中使用,作为@wechat.handler 的第二个参数传入。 亦可将多个过滤器合成一个数组(list)传入。

预定义过滤器

预定义过滤器通过

from flask.ext.wechat import filters

引入。

预定义过滤器包括:

事件过滤器
过滤事件
filters.event

直接使用(无需括号)过滤所有事件消息。

过滤指定事件
filters.event(event)

传入事件名字符串,过滤符合该事件名的消息。

过滤关注事件
filters.event.subscribe
过滤取消关注事件
filters.event.unsubscribe
过滤点击事件
filters.event.click
过滤指定点击事件
filters.event.click(key)

过滤key为字符串key的点击事件

过滤跳转事件
filters.event.view
过滤指定跳转事件
filters.event.view(url, accuracy=False, ignorecase=False)

过滤url为字符串url的跳转事件, 可选参数accuracy表示是否精准匹配,默认否, ignorecase是否区分大小写,默认否。

消息过滤器
逻辑过滤器
默认过滤器
filters.all

所有消息都会成功进入该过滤器。 该过滤器优先级最低,只有在无法匹配其他过滤器的情况下才会匹配该过滤器。

且过滤器
filters.and_(*funcs)

传入多个过滤器,只有符合所有过滤器要求的情况下,才能进入控制器。 一旦有过滤器不符合条件,不再执行funcs中的下一过滤器(与and 相同)。

或过滤器
filters.or_(*funcs)

传入多个过滤器,在符合任一过滤器的情况下,就会进入过滤器。

自定义过滤器

你可以编写自定义过滤器。过滤器接收一个 WeChatRequest 对象。 返回True代表符合条件,False代表不符合条件。

信号

在Flask-WeChat 模块中,我们预定义了一些信号,用户可以监听这些信号,来了解一些变化,并执行相应逻辑。

你可以在代码中监听信号,所有信号的发送者都是WeChat 实例。以下是一个监听信号的简单示例。

def record(sender, identity, message, **kwargs):
    logging.info(str(message))
request_deserialized.connect(record, wechat)

这段代码在wechat_granted

微信请求处理信号

处理微信请求时发出的信号,每个型号都包含一个identity参数,代表用户自定义的微信公众号id。

request_received

接收到微信请求时触发。该信号包括以下参数

  • identity

    前述公众号id

  • request

    接收到的flask请求,类型是flask.Request

request_deserialized

成功反序列化微信请求时触发,该信号包含以下参数

  • identity

    前述公众号id

  • message

    收到的微信消息,类型是flask.ext.wechat.messages.WeChatRequest

request_badrequest

微信请求异常时触发,该信号包含以下参数

  • identity

    前述公众号id

  • request

    接收到的flask请求,类型是flask.Request

  • message

    异常类型,包括 incorrect timestamp 时间戳格式错误。 incorrect args url地址上未包含完整的参数,包括signature、timestamp、nonce等。 incorrect time url上的timestamp超过服务器时间15分钟。 incorrect signature 错误的签名,url上的签名结果与服务器计算的签名结果不符。 incorrect content 无法将请求体反序列化为WeChatRequest。

request_handle_error

业务逻辑处理微信请求时发生未经捕获的错误,该型号包含以下参数

  • identity

    前述公众号id

  • request

    接收到的flask请求,类型是flask.Request

  • exception

    解析返回时捕获的异常

response_sent

送回请求时触发该信号,该信号包含以下参数

  • identity

    前述公众号id

  • request

    接收到的flask请求,类型是flask.Request

  • response

    WeChatResponse实例或字符串

微信API处理信号

所有微信API处理信号都包含一个response参数与一个identity参数, 前者的类型是requests.Response,是微信服务器返回的对象。 后者的类型是str,是用户自定义的微信公众号id。

wechat_granted

当公众号进行授权时或重新进行授权时会触发该信号。该信号包括以下参数

  • response

    前述返回对象

  • identity

    前述公众号id

  • accesstoken

    授权获得的accesstoken

  • expires_in

    授权获得的accesstoken在多久以后过期

理论上用户无需监听本信号,使用wechat.accesstoken 装饰函数即可获得同样效果。

wechat_servererror

当微信服务器处理请求异常时触发该信号,异常包括但不仅包括服务器返回错误格式的数据。 该信号包含以下参数

  • response

    前述返回对象

  • identity

    前述公众号id

  • exception

    解析返回时捕获的异常

wechat_error

当请求返回错误时触发。该错误一般为客户端错误。该信号包含以下参数

  • response

    前述返回对象

  • identity

    前述公众号id

  • code

    错误代码,可以通过错误代码在微信开发者文档中查询

配置

本模块的可配置项包括两个,你可以在Flask配置文件中配置这两个项,以修改模块的默认行为。

WECHAT_CALLBACK_PREFIX

微信回调的前缀,默认为”/wechat/callbacks”,用户在微信开发者后台配置回调为

..code-block:

WECHAT_CALLBACK_PREFIX + "/" + IDENTITY + "/"

的地址即为回调地址。其中identity 是用户定义的公众号id。

WECHAT_DEBUG

开启调试模式,默认值为False。

默认情况下,模块会自动处理模块内发出的所有异常,包括注册的处理器中的异常。 并给予微信服务器正常的返回。异常会通过一些 信号 传递给开发者。

但这样可能让开发者在开发过程中难以调试发生的异常。 将WECHAT_DEBUG值设置为True,模块会reraise 发生的异常,使用户便于调试自己的应用。

API

WeChatRequest

WeChatResponse