微信公众平台开发利器-weixin-knife(Python版)

这两天将之前基于微信公众平台的代码重构了下,基础功能以库的方式提供,提供了demo使用的是django,看着之前为赶

进度写的代码真的惨不忍睹,所以weixin-knife产生了,正如其名,提供的是必要的功能,而不是完整的应用。weixin-knife可

以很方便的处理关注,取关注事件,处理文本消息,回复用户信息,jssdk处理,oauth认证,以及微信支付。

github地址:https://github.com/Skycrab/weixin-knife

首先看看怎么用

from .weixin import handler as HD
@HD.subscribe
def subscribe(xml):
    return "welcome to brain"

@HD.unsubscribe
def subscribe(xml):
    print "leave"
    return "leave  brain"

上面处理了关注和取关事件,通过装饰器处理的还算透明。

处理文本消息,回复图文消息如下:

@HD.text
def text(xml):
    content = xml.Content
    if content == "111":
        return {"Title":"美女", "Description":"比基尼美女", "PicUrl":"http://9smv.com/static/mm/uploads/150411/2-150411115450247.jpg", "Url":"http://9smv.com/beauty/list?category=5"}
    elif content == "222":
        return [
            ["比基尼美女", "比基尼美女", "http://9smv.com/static/mm/uploads/150411/2-150411115450247.jpg", "http://9smv.com/beauty/list?category=5"],
            ["长腿美女", "长腿美女", "http://9smv.com/static/mm/uploads/150506/2-150506111A9648.jpg", "http://9smv.com/beauty/list?category=8"]
        ]
    elif content == "push":
        Helper.send_text_message(xml.FromUserName, "推送消息测试")
        return "push ok"

    return "hello world"

如何文本是111或222,我们回复图文消息,如何使push,我们使用客服接口推送消息,其它返回“hello world"

一般我们会使用oauth网页授权获取用户的openid,如果是多个链接都需要通过oauth处理,代码会很难看,通过装饰器可以很好的处理这个问题。

def sns_userinfo_callback(callback=None):
    """网页授权获取用户信息装饰器
    callback(openid, userinfo):
        return user
    """
    def wrap(func):
        @wraps(func)
        def inner(*args, **kwargs):
            request = args[0]  #django第一个参数request
            openid = request.COOKIES.get(‘openid‘)
            userinfo = None
            if not openid:
                code = request.GET.get("code")
                if not code:
                    current = "http://"+ request.get_host() + request.get_full_path()
                    return redirect(WeixinHelper.oauth2(current))
                else:
                    data = json.loads(WeixinHelper.getAccessTokenByCode(code))
                    access_token, openid, refresh_token = data["access_token"], data["openid"], data["refresh_token"]
                    #WeixinHelper.refreshAccessToken(refresh_token)
                    userinfo = json.loads(WeixinHelper.getSnsapiUserInfo(access_token, openid))
            else:
                ok, openid = Helper.check_cookie(openid)
                if not ok:
                    return redirect("/")
            request.openid = openid
            if callable(callback):
                request.user = callback(openid, userinfo)
            response = func(request)
            return response
        return inner
    return wrap

sns_userinfo = sns_userinfo_callback()

在所有需要用户openid的函数前使用sns_userinfo装饰器就可以了,callback函数接收openid,userinfo,返回用户实例,这样

就可以使用request.user获取当前用户

@sns_userinfo
def oauth(request):
    """网页授权获取用户信息"""
    resp = HttpResponse(request.openid)
    resp.set_cookie("openid", Helper.sign_cookie(request.openid))
    return resp

使用oauth需要保存cookie,不然每次用户请求都需要授权,需要走一遍完整的oauth流程,拖慢整体响应。

weixin-knife提供了微信支付支持,稍微修改我之前移植的官方PHP版本,https://github.com/Skycrab/wzhifuSDK

@sns_userinfo
def pay(request):
    response = render_to_response("pay.html")
    response.set_cookie("openid", Helper.sign_cookie(request.openid))
    return response

@sns_userinfo
@catch
def paydetail(request):
    """获取支付信息"""
    openid = request.openid
    money = request.POST.get("money") or "0.01"
    money = int(float(money)*100)

    jsApi = JsApi_pub()
    unifiedOrder = UnifiedOrder_pub()
    unifiedOrder.setParameter("openid",openid) #商品描述
    unifiedOrder.setParameter("body","充值测试") #商品描述
    timeStamp = time.time()
    out_trade_no = "{0}{1}".format(WxPayConf_pub.APPID, int(timeStamp*100))
    unifiedOrder.setParameter("out_trade_no", out_trade_no) #商户订单号
    unifiedOrder.setParameter("total_fee", str(money)) #总金额
    unifiedOrder.setParameter("notify_url", WxPayConf_pub.NOTIFY_URL) #通知地址
    unifiedOrder.setParameter("trade_type", "JSAPI") #交易类型
    unifiedOrder.setParameter("attach", "6666") #附件数据,可分辨不同商家(string(127))
    try:
        prepay_id = unifiedOrder.getPrepayId()
        jsApi.setPrepayId(prepay_id)
        jsApiParameters = jsApi.getParameters()
    except Exception as e:
        print(e)
    else:
        print jsApiParameters
        return HttpResponse(jsApiParameters)

FAIL, SUCCESS = "FAIL", "SUCCESS"
@catch
def payback(request):
    """支付回调"""
    xml = request.raw_post_data
    #使用通用通知接口
    notify = Notify_pub()
    notify.saveData(xml)
    print xml
    #验证签名,并回应微信。
    #对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
    #微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
    #尽可能提高通知的成功率,但微信不保证通知最终能成功
    if not notify.checkSign():
        notify.setReturnParameter("return_code", FAIL) #返回状态码
        notify.setReturnParameter("return_msg", "签名失败") #返回信息
    else:
        result = notify.getData()

        if result["return_code"] == FAIL:
            notify.setReturnParameter("return_code", FAIL)
            notify.setReturnParameter("return_msg", "通信错误")
        elif result["result_code"] == FAIL:
            notify.setReturnParameter("return_code", FAIL)
            notify.setReturnParameter("return_msg", result["err_code_des"])
        else:
            notify.setReturnParameter("return_code", SUCCESS)
            out_trade_no = result["out_trade_no"] #商户系统的订单号,与请求一致。
            ###检查订单号是否已存在,以及业务代码

    return  HttpResponse(notify.returnXml())

pay.html就是使用WeixinJSBridge.invode调用

   $.post("/paydetail",{
      money: $momey
      },function(data){
        if(data){
          var jsonobj = eval(‘(‘+data+‘)‘);
          WeixinJSBridge.invoke(‘getBrandWCPayRequest‘, {
                 "appId" : jsonobj.appId, //公众号名称,由商户传入
                 "timeStamp" : jsonobj.timeStamp, //时间戳
                 "nonceStr" : jsonobj.nonceStr, //随机串
                 "package" : jsonobj.package,//扩展包
                 "signType" : "MD5", //微信签名方式:1.sha1
                 "paySign" : jsonobj.paySign //微信签名
                 });
        }
      }
    );

由于access_token, jsapi_ticket需要缓存,而缓存方式又依赖于具体环境,所以提供了一个Helper类,使用了django 的cache

缓存。

class Helper(object):
    """微信具体逻辑帮组类"""

    @class_property
    def access_token(cls):
        key = "ACCESS_TOKEN"
        token = cache.get(key)
        if not token:
            data = json.loads(WeixinHelper.getAccessToken())
            token, expire = data["access_token"], data["expires_in"]
            cache.set(key, token, expire-300)
        return token

    @class_property
    def jsapi_ticket(cls):
        key = "JSAPI_TICKET"
        ticket = cache.get(key)
        if not ticket:
            data = json.loads(WeixinHelper.getJsapiTicket(cls.access_token))
            ticket, expire = data["ticket"], data["expires_in"]
            cache.set(key, ticket, expire-300)
        return ticket

class_property提供了类级别的property,当然实例也是可以用的。

class class_property(object):
    """ A property can decorator class or instance

    class Foo(object):
        @class_property
        def foo(cls):
            return 42

    print(Foo.foo)
    print(Foo().foo)

    """
    def __init__(self, func, name=None, doc=None):
        self.__name__ = name or func.__name__
        self.__module__ = func.__module__
        self.__doc__ = doc or func.__doc__
        self.func = func

    def __get__(self, obj, type=None):
        value = self.func(type)
        return value

使用weixin-knife助力公众平台开发,你完全可以稍加修改用于flask等其它web框架。

时间: 2024-08-10 14:42:42

微信公众平台开发利器-weixin-knife(Python版)的相关文章

微信公众平台开发(121) 微信二维码海报

关键字:微信公众平台 二维码 海报作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/weixin-poster.html 本文介绍微信公众平台下二维码海报的开发过程. 一.微信二维码海报介绍 微信二维码海报是指在海报中嵌入和微信用户关联的参数二维码的海报,用户分享推广之后,新用户可以被统计为被推广人员数,从而达到增加粉丝的传播效果.其使用场景如下:   二.开发流程 在微信二维码海报生成中,需要用到以下信息 1. 自定义菜单中设置一个菜单项,点击后返回二维

微信公众平台开发(76) 获取用户基本信息

本文介绍如何获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言.本文的方法将囊括订阅号和服务号以及自定义菜单各种场景,无论是否有高级接口权限,都有办法来获得用户基本信息,而无需模拟登录. 在本文中,特别要注意的是有两个不同的Access Token,他们产生的方式不一样,一种是使用AppID和AppSecret获取的access_token,一种是OAuth2.0授权中产生的access_token,方倍工作室分别称为全局Access Token和授权Access

微信公众平台开发问答 【转发】

微信公众平台开发问答 微信公众平台开发问答是一个微信知识问答区,专注于提供微信应用及开发技术知识的整理.归类和检索. 主题:新手常见问题 问:我是新手,没有开发基础,应该如何学习微信公众平台的开发?答:先学习PHP和Mysql,可以在网上找相应的教程,也可参考书籍<PHP和MySQL Web开发(原书第4版)>:再学习微信公众平台开发入门教程,了解微信收发消息原理及回复:然后根据微信开发文档,熟悉接口,并在此基础上实现一些基本的小功能,并扩展到更复杂的功能上. 问:URL和Token是什么意思

微信公众平台开发最佳实践(第2版)

<微信公众平台开发最佳实践 第2版>微信公众平台开发经典之作全新改版,精心挑选最经典的商业项目开发,成千上万人次微信公众平台开发者从中受益 前言 出版说明 自从方倍工作室在博客园推出微信公众平台开发系列教程后,受到广大微信开发人员及爱好者的热情关注,相关文章的日访问量高达2万人次,而<微信公众平台开发入门教程>的阅读量超过50万,博客访问量总计超过500万,成为微信公众平台开发更新最快,传播最广.受众最多.资料最全的博客,很多博文被许多有影响力的网站转载,并被各大搜索引擎收录且排名

Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明

紧接上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明>,这里专讲OAuth2.0. 理解OAuth2.0 首先我们通过一张图片来了解一下OAuth2.0的运作模式: 从上图我们可以看到,整个过程进行了2次"握手",最终利用授权的AccessToken进行一系列的请求,相关的过程说明如下: A:由客户端向服务器发出验证请求,请求中一般会携带这些参数 ID标识,例如appId 验证后跳转到的URL(redirectUrl) 状态参数

Senparc.Weixin.MP SDK 微信公众平台开发教程(十六):AccessToken自动管理机制

Senparc.Weixin.MP SDK 微信公众平台开发教程(十六):AccessToken自动管理机制 在<Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明>中,我介绍了获取AccessToken(通用接口)的方法. 在实际的开发过程中,所有的高级接口都需要提供AccessToken,因此我们每次在调用高级接口之前,都需要执行一次获取AccessToken的方法,例如: 1 var accessToken = AccessTokenContainer.

Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明

这里所说的高级接口是指面向通过认证的服务号开通的高级功能. 高级功能大致可以分类为: 用户接口 分组接口 客服接口(有别于之前介绍的多客服) 群发接口 多媒体接口 二维码接口 模板消息接口(不是所有账号都可开通) OAuth2.0(相对比较复杂,后面会有专门介绍) 以上所有的接口都包含在Senparc.Weixin.MP.AdvancedAPIs命名空间下. 一些共同的操作 几乎所有的高级接口都需要用到AccessToken来通讯(注意,下面如果没有特殊说明的接口都需要这个AccessToken

Senparc.Weixin.MP SDK 微信公众平台开发教程(十五):消息加密

原文:Senparc.Weixin.MP SDK 微信公众平台开发教程(十五):消息加密 前不久,微信的企业号使用了强制的消息加密方式,随后公众号也加入了可选的消息加密选项.目前企业号和公众号的加密方式是一致的(格式会有少许差别). 加密设置 进入公众号后台的“开发者中心”,我们可以看到Url对接的设置: 点击[修改设置],可以进入到修改页面: 加密的方式一共有3种: 明文模式,即原始的消息格式 兼容模式,明文.密文将共存,正式发布的产品不建议使用(因为仍然包含了明文,达不到加密的效果) 安全模

Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册

原文:Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册 微信公众平台(下面简称“公众平台”)注册步骤和导航还是比较流畅的,因此这个教程对于上网经验丰富的朋友来说,有点多余.不过为了保持教程系列的完整性,这里还是认认真真把流程梳理一遍. 第一步:进入公众平台地址:https://mp.weixin.qq.com 第二步:如果还没有账号,点击右上角的立即注册按钮. 第三步:填写“1.基本信息”,并点击[注册]: 第四步:登陆注册邮箱进行激活: 在邮箱中打开激活