轉自 http://blog.csdn.net/yueguanghaidao/article/details/45748793
這兩天將之前基於微信公衆平臺的代碼重構了下,基礎功能以庫的方式提供,提供了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"
一般我們會使用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()
就可以使用request.user獲取當前用戶
- @sns_userinfo
- def oauth(request):
- """網頁授權獲取用戶信息"""
- resp = HttpResponse(request.openid)
- resp.set_cookie("openid", Helper.sign_cookie(request.openid))
- return resp
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框架。