本文实例讲述了Python开发微信公众平台的方法。分享给大家供大家参考,具体如下:
这两天将之前基于微信公众平台的代码重构了下,基础功能以库的方式提供,提供了demo使用的是django,看着之前为赶进度写的代码真的惨不忍睹,所以weixin-knife产生了,正如其名,提供的是必要的功能,而不是完整的应用。weixin-knife可以很方便的处理关注,取关注事件,处理文本消息,回复用户信息,jssdk处理,oauth认证,以及微信支付。
github地址:https://github.com/Skycrab/weixin-knife。
首先看看怎么用
1
2
3
4
5
6
7
8
|
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"
|
上面处理了关注和取关事件,通过装饰器处理的还算透明。
处理文本消息,回复图文消息如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@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处理,代码会很难看,通过装饰器可以很好的处理这个问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
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获取当前用户
1
2
3
4
5
6
|
@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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
@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调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
$.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缓存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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,当然实例也是可以用的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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框架。
希望本文所述对大家Python程序设计有所帮助。