瀏覽消息推送的時(shí)候,在模板卡片部分停滯很久;其中主要涉及url的回調(diào)工作,不太熟悉。 官網(wǎng)鏈接-模板卡片
官方特殊說(shuō)明:
特殊說(shuō)明
- 僅有 按鈕交互型、投票選擇型、多項(xiàng)選擇型 以及填寫了action_menu字段的文本通知型、圖文展示型的卡片支持回調(diào)更新或通過(guò)接口更新卡片。
- 支持回調(diào)更新的卡片可支持用戶點(diǎn)擊觸發(fā)交互事件,需要開發(fā)者設(shè)置的回調(diào)接口來(lái)處理回調(diào)事件,回調(diào)協(xié)議可見(jiàn)文檔 模板卡片事件推送,注意 沒(méi)有配置回調(diào)接口的應(yīng)用不可發(fā)送支持回調(diào)的卡片。
- 開發(fā)者的服務(wù)收到回調(diào)事件后,需要根據(jù)協(xié)議返回相應(yīng)的數(shù)據(jù)以更新卡片,對(duì)應(yīng)的協(xié)議見(jiàn)文檔 更新模版卡片消息。
- 此接口發(fā)送支持回調(diào)更新的卡片消息之后,返回的參數(shù)里會(huì)帶上response_code,可使用response_code調(diào)用更新模版卡片消息接口,response_code 24小時(shí)內(nèi)有效,且只能調(diào)用一次接口。
目前解決第二條,配置回調(diào)接口支持發(fā)送模板卡片
配置回調(diào)接口
官網(wǎng)鏈接-回調(diào)服務(wù)
通過(guò)回調(diào)服務(wù)可以自定義消息,如識(shí)別關(guān)鍵詞,動(dòng)態(tài)獲取消息的狀態(tài)等。
在使用代碼開發(fā)前,首先需要在相應(yīng)的應(yīng)用中配置回調(diào)接口服務(wù),定義URL, Token, EncodingAESKey。
這里的URL就是之后訪問(wèn)的回調(diào)地址
步驟:
- 打開企業(yè)微信的管理者后臺(tái),進(jìn)入應(yīng)用管理,選擇消息推送的目標(biāo)程序
- 選擇下面收發(fā)消息,設(shè)置API接收
- 進(jìn)行配置
但是當(dāng)點(diǎn)擊保存的時(shí)候,需要進(jìn)行回調(diào)驗(yàn)證;設(shè)置的URL接口需要支持GET、POST兩種請(qǐng)求服務(wù),GET用于進(jìn)行驗(yàn)證,POST用來(lái)之后收發(fā)消息(提供給其他需要回調(diào)接口的服務(wù))
因此,需要先定義一套接口滿足GET,才能保存配置;這里可以參照官網(wǎng)提供的第三方庫(kù)完成驗(yàn)證,其中包括一系列加密算法可以參考 官網(wǎng)鏈接-加密參數(shù)說(shuō)明
回調(diào)接口的GET請(qǐng)求驗(yàn)證
首先下載第三方加密庫(kù) 加密庫(kù)鏈接;選擇合適的語(yǔ)言去github進(jìn)行下載
配置django項(xiàng)目,定義回調(diào)接口:http://ip:port/jyg/vertifyinfo,企業(yè)管理員在保存回調(diào)配置信息時(shí),企業(yè)微信會(huì)發(fā)送一條驗(yàn)證消息到填寫的URL,即在給定的url后面添加timestamp, nonce, echostr, msg_signature用于驗(yàn)證
def versityInfo(request):
sToken = "xxx"
sEncodingAESKey = "xxx" # 剛才配置的,寫在這里,可以將配置信息單獨(dú)抽出
sCorpID = "xxx" # corpID
if request.method == 'GET': # GEt為驗(yàn)證
wxcpt=WXBizMsgCrypt(sToken,sEncodingAESKey,sCorpID)
# 提取請(qǐng)求中的參數(shù)
sVerifyMsgSig = request.GET.get("msg_signature")
sVerifyTimeStamp=request.GET.get("timestamp")
sVerifyNonce=request.GET.get("nonce")
sVerifyEchoStr=request.GET.get("echostr")
# 調(diào)用第三方庫(kù)進(jìn)行驗(yàn)證
ret,sEchoStr=wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce,sVerifyEchoStr)
if(ret!=0):
print("ERR: VerifyURL ret: " + str(ret))
sys.exit(1)
# 返回驗(yàn)證解密后的消息
return HttpResponse(sEchoStr)
例如VerifyURL為第三方庫(kù),里面一共提供了三個(gè)方法,詳細(xì)可以瀏覽官網(wǎng)。
代碼完成可以使用接口測(cè)試工具進(jìn)行測(cè)試:官網(wǎng)鏈接-接口測(cè)試工具
然后返回點(diǎn)擊保存即可完成配置。
發(fā)送模板卡片消息
請(qǐng)求方式:GET(HTTPS)
請(qǐng)求地址:https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list?access_token=ACCESS_TOKEN
請(qǐng)求參數(shù):
{
"touser" : "JiuXiaTian",
"msgtype" : "template_card",
"agentid" : 1000033,
"template_card" : {
"card_type" : "text_notice",
"source" : {
"desc": "企業(yè)微信",
"desc_color": 1
},
"action_menu": {
"desc": "卡片副交互輔助文本說(shuō)明",
"action_list": [
{"text": "接受推送", "key": "A"},
{"text": "不再推送", "key": "B"}
]
},
"task_id": "task_id",
"main_title" : {
"title" : "歡迎使用企業(yè)微信",
"desc" : "您的好友正在邀請(qǐng)您加入企業(yè)微信"
},
"quote_area": {
"type": 1,
"url": "https://work.weixin.qq.com",
"title": "企業(yè)微信的引用樣式",
"quote_text": "企業(yè)微信真好用呀真好用"
},
"emphasis_content": {
"title": "100",
"desc": "核心數(shù)據(jù)"
},
"sub_title_text" : "下載企業(yè)微信還能搶紅包!",
"horizontal_content_list" : [
{
"keyname": "邀請(qǐng)人",
"value": "張三"
},
{
"type": 1,
"keyname": "企業(yè)微信官網(wǎng)",
"value": "點(diǎn)擊訪問(wèn)",
"url": "https://work.weixin.qq.com"
}
],
"card_action": {
"type": 1,
"url": "https://work.weixin.qq.com"
}
},
"enable_id_trans": 0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
運(yùn)行結(jié)果:
被動(dòng)響應(yīng)消息
在企業(yè)微信中可以根據(jù)發(fā)送的消息定制回調(diào)消息,效果圖如下:
被動(dòng)接收消息走的回調(diào)接口的POST方法,官網(wǎng)調(diào)用接口如下:
請(qǐng)求方式:POST
請(qǐng)求地址 :http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323
請(qǐng)求體:當(dāng)用戶提交消息后,會(huì)在請(qǐng)求體中封裝成一個(gè)${xml}格式的數(shù)據(jù)
可以使用 if request.method 的方式進(jìn)行路由分發(fā),但是觀察參數(shù):GET驗(yàn)證中包含sVerifyEchoStr,而POST中存放的時(shí)候請(qǐng)求體數(shù)據(jù),也可以根據(jù)這個(gè)點(diǎn)就行判斷,如:
# 公共參數(shù)
sVerifyMsgSig = request.GET.get("msg_signature")
sVerifyTimeStamp = request.GET.get("timestamp")
sVerifyNonce = request.GET.get("nonce")
sVerifyEchoStr = request.GET.get("echostr")
if sVerifyEchoStr:
pass
else: # 接收消息
pass
準(zhǔn)備工作,定義一個(gè)自定義的消息體,去處理信息解密,加密等其他情況:
# 自定義消息處理
class MessageHandler:
def __init__(self, baseData):
self.wxcpt = baseData['wxcpt']
self.sVerifyMsgSig = baseData['sVerifyMsgSig']
self.sVerifyTimeStamp = baseData['sVerifyTimeStamp']
self.sVerifyNonce = baseData['sVerifyNonce']
# 請(qǐng)求中處理初始化參數(shù)
# 數(shù)據(jù)初始化
sToken = URLRobackSetting['sToken']
sEncodingAESKey = URLRobackSetting['sEncodingAESKey']
sCorpID = URLRobackSetting['sCorpID']
wxcpt = WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID)
# 公共參數(shù)
sVerifyMsgSig = request.GET.get("msg_signature")
sVerifyTimeStamp = request.GET.get("timestamp")
sVerifyNonce = request.GET.get("nonce")
sVerifyEchoStr = request.GET.get("echostr")
baseData = {
"wxcpt": wxcpt,
"sVerifyMsgSig": sVerifyMsgSig,
"sVerifyTimeStamp": sVerifyTimeStamp,
"sVerifyNonce": sVerifyNonce
}
# 自定義消息處理類
messageHandler = MessageHandler(baseData)
接受消息,解析成明文,調(diào)用官方的解密函數(shù):DecryptMsg
def receiveInfo(self, sReqData):
""""接收消息"""
try:
# 解密
sReqMsgSig = self.sVerifyMsgSig
sReqTimeStamp = self.sVerifyTimeStamp
sReqNonce = self.sVerifyNonce
# 解密函數(shù)
ret, sMsg = self.wxcpt.DecryptMsg(
sReqData, sReqMsgSig, sReqTimeStamp, sReqNonce)
print("=>", ret, sMsg)
# 此時(shí)sMsg為明文
return ret, sMsg
except Exception as e:
raise e
解析明文中的內(nèi)容,然后定制消息:
def responseInfo(self, sEncryptMsg):
result = xmltodict.parse(sEncryptMsg)
xml = result["xml"]
# 解析內(nèi)容
content = xml['Content']
fromUserName = xml['FromUserName']
# 定制消息
if content == "test":
message = "this is success test"
else:
message = "please check document"
return self.customMessage(fromUserName, message)
xmltodict: 模塊,用于將xml轉(zhuǎn)換為python中的字典文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-499453.html
定制的消息按照官方進(jìn)行數(shù)據(jù)加密,調(diào)用函數(shù):EncryptMsg文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-499453.html
def customMessage(self, user, content):
try:
response_data = "<xml><ToUserName><![CDATA[" + user + \
"]]></ToUserName><FromUserName><![CDATA[corid]]></FromUserName><CreateTime>1476422779</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + content + "]]></Content></xml>"
# response_data = unicode(response_data).encode('utf8') # python2處理
print("data=>", response_data)
ret, sEncryptMsg = self.wxcpt.EncryptMsg(
response_data, self.sVerifyNonce, self.sVerifyTimeStamp)
if(ret != 0):
raise Exception
# 返回加密的回復(fù)消息
final_data = {
"code": 200,
"sEncryptMsg": sEncryptMsg
}
return HttpResponse(json.dumps(final_data))
except Exception:
raise Exception
完整測(cè)試Demo
@csrf_exempt
def versityInfo(request):
sToken = URLRobackSetting['sToken']
sEncodingAESKey = URLRobackSetting['sEncodingAESKey']
sCorpID = URLRobackSetting['sCorpID']
try:
wxcpt = WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID)
# 公共參數(shù)
sVerifyMsgSig = request.GET.get("msg_signature")
sVerifyTimeStamp = request.GET.get("timestamp")
sVerifyNonce = request.GET.get("nonce")
sVerifyEchoStr = request.GET.get("echostr")
baseData = {
"wxcpt": wxcpt,
"sVerifyMsgSig": sVerifyMsgSig,
"sVerifyTimeStamp": sVerifyTimeStamp,
"sVerifyNonce": sVerifyNonce
}
# 自定義消息處理類
messageHandler = MessageHandler(baseData)
if sVerifyEchoStr:
print("=>", sVerifyMsgSig, sVerifyTimeStamp, sVerifyEchoStr)
ret, sEchoStr = wxcpt.VerifyURL(
sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr)
if(ret != 0):
print("ERR: VerifyURL ret: " + str(ret))
final_data = {
"code": 400,
"sEncryptMsg": "驗(yàn)證未通過(guò)"
}
return HttpResponse(json.dumps(final_data))
return HttpResponse(sEchoStr)
else: # 接收消息
# 提取參數(shù)
# unicode(string).encode("utf-8")
sReqData = request.body
sReqMsgSig = sVerifyMsgSig
sReqTimeStamp = sVerifyTimeStamp
sReqNonce = sVerifyNonce
print("=>", sReqData, type(sReqMsgSig), sReqTimeStamp, sReqNonce)
# 接收數(shù)據(jù)
ret, sEncryptMsg = messageHandler.receiveInfo(sReqData)
if(ret != 0):
print("ERR: EncryptMsg ret: ", str(ret))
final_data = {
"code": 400,
"sEncryptMsg": "參數(shù)錯(cuò)誤"
}
return HttpResponse(json.dumps(final_data))
# 解析明文數(shù)據(jù),然后發(fā)送消息
return messageHandler.responseInfo(sEncryptMsg)
except Exception as e:
print("system error:", e)
final_data = {
"code": 10056,
"sEncryptMsg": "系統(tǒng)當(dāng)前維修。。。"
}
response = HttpResponse(json.dumps(final_data))
return response
# 自定義消息體
class MessageHandler:
def __init__(self, baseData):
self.wxcpt = baseData['wxcpt']
self.sVerifyMsgSig = baseData['sVerifyMsgSig']
self.sVerifyTimeStamp = baseData['sVerifyTimeStamp']
self.sVerifyNonce = baseData['sVerifyNonce']
def receiveInfo(self, sReqData):
""""接收消息"""
try:
# 解密
sReqMsgSig = self.sVerifyMsgSig
sReqTimeStamp = self.sVerifyTimeStamp
sReqNonce = self.sVerifyNonce
# 解密函數(shù)
ret, sMsg = self.wxcpt.DecryptMsg(
sReqData, sReqMsgSig, sReqTimeStamp, sReqNonce)
print("=>", ret, sMsg)
# 此時(shí)sMsg為明文
return ret, sMsg
except Exception as e:
raise e
def responseInfo(self, sEncryptMsg):
result = xmltodict.parse(sEncryptMsg)
xml = result["xml"]
# 解析內(nèi)容
content = xml['Content']
fromUserName = xml['FromUserName']
# 定制消息
if content == "test":
message = "this is success test"
else:
message = "please check document"
return self.customMessage(fromUserName, message)
def customMessage(self, user, content):
try:
response_data = "<xml><ToUserName><![CDATA[" + user + \
"]]></ToUserName><FromUserName><![CDATA[wx7fc55822f12887ad]]></FromUserName><CreateTime>1476422779</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + content + "]]></Content></xml>"
# response_data = unicode(response_data).encode('utf8') # python2處理
print("data=>", response_data)
ret, sEncryptMsg = self.wxcpt.EncryptMsg(
response_data, self.sVerifyNonce, self.sVerifyTimeStamp)
if(ret != 0):
raise Exception
# 返回加密的回復(fù)消息
final_data = {
"code": 200,
"sEncryptMsg": sEncryptMsg
}
return HttpResponse(json.dumps(final_data))
except Exception:
raise Exception
到了這里,關(guān)于【企業(yè)微信-消息推送】模板卡片消息-Python代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!