有了测试账号之后,我们该做什么呢?当然是接收来自于微信的消息和事件。
公众号接收用户消息分为七类,包括文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息、链接消息。
公众号接收用户事件分为五类,包括关注事件、取消事件、扫描带参数二维码事件、上报地理位置事件、自定义菜单事件。
当公众号接收到来自微信的消息时,需要做以下几步处理:
1 验证消息是否来源于微信
这个方法在上一节已学习过。
2 解析来自于微信的消息和事件
微信的消息正文是一个XML,我们收到这个XML需要进行解析,wechatpy提供了一个解析XML的方法parse_message,传入XML,返回解析后的对象。我们可以从解析后的对象中获取消息的内容。
from wechatpy import parse_message msg = parse_message(xml)
3 视图编写
视图中的GET方法,上一节已经写好了,这一节主要是POST方法。POST方法主要是判断用户的消息和事件,至于收到这些消息,如何回复,在后面的章节中会讲到。
这里需要注意的一点是用户关注公众号的时候,可以获取到用户的openid。在登录流程中会用到,比如:用户关注公众号的时候,获取用户的openid,保存在数据库中,而用户在登录注册输入手机的页面,再获取一次openid,并在数据库中找到这个Openid,并更新用户的手机号。同时,数据库中保存了Openid,可以随时根据Openid获取用户的其它资料。
from django.views.generic import View
from rest_framework import status
import logging
from django.http import HttpResponse
from wechatpy.utils import check_signature
from wechatpy.exceptions import InvalidSignatureException
from GeneralTools import Constants
from wechatpy import parse_message
# 获取在配置文件中定义的logger,用来记录日志
logger = logging.getLogger('wec_info')
# from . import Replies
class WechatInterface(View):
"""
微信公众号开发服务器配置
"""
@classmethod
def get(cls, request):
"""
微信服务器验证消息
:param request:GET请求携带参数(signature、timestamp、nonce、echostr)
:return:原样返回echostr参数
"""
# logger.info("body:%s" % request.body)
# logger.info("GET:%s" % request.GET)
# logger.info("POST:%s" % request.POST)
# 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
signature = request.GET.get('signature')
# 时间戳
timestamp = request.GET.get('timestamp')
# 随机数
nonce = request.GET.get('nonce')
# 随机字符串
echostr = request.GET.get('echostr')
logger.info("signature:%s" % signature)
logger.info("timestamp:%s" % timestamp)
logger.info("nonce:%s" % nonce)
logger.info("echostr:%s" % echostr)
# 校验参数
if not all([signature, timestamp, nonce, echostr]):
# 请求参数错误
return HttpResponse(status.HTTP_400_BAD_REQUEST)
try:
check_signature(
token=Constants.WECHAT_TOKEN, # 开发者在公众号配置中配置的令牌
signature=signature, # 微信加密签名
timestamp=timestamp, # 时间戳
nonce=nonce # 随机数
)
except InvalidSignatureException as e:
# 处理异常情况或忽略
logger.error(e)
# 微信签名错误
return HttpResponse(status.HTTP_403_FORBIDDEN)
# 验证成功时,应原样返回 echostr 参数值
return HttpResponse(echostr)
@classmethod
def post(cls, request):
print('===============>访问到了,')
"""
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
"""
# logger.info("body:%s" % request.body)
# logger.info("GET:%s" % request.GET)
# logger.info("POST:%s" % request.POST)
# 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
signature = request.GET.get('signature')
# 时间戳
timestamp = request.GET.get('timestamp')
# 随机数
nonce = request.GET.get('nonce')
# openid
openid = request.GET.get('openid')
# logger.info("signature:%s" % signature)
# logger.info("timestamp:%s" % timestamp)
# logger.info("nonce:%s" % nonce)
# openid:o-dlPwDD8x_tKgeinvgj9CY9sfSI
# logger.info("openid:%s" % openid)
# 校验参数
if not all([signature, timestamp, nonce, openid]):
# 请求参数错误
return HttpResponse(status.HTTP_400_BAD_REQUEST)
try:
check_signature(Constants.WECHAT_TOKEN, signature, timestamp, nonce)
except InvalidSignatureException as e:
# 处理异常情况或忽略
logger.error(e)
# 微信签名错误
return HttpResponse(status.HTTP_403_FORBIDDEN)
xml = request.body
logger.info("xml:%s" % xml)
if not xml:
# 请求参数错误
return HttpResponse(status.HTTP_400_BAD_REQUEST)
msg = parse_message(xml)
# logger.info("msg type:%s" % type(msg))
# logger.info("msg_type:%s" % msg_type)
msg_content = None
if msg.type == "text":
print('====================>')
msg_content = '收到文本信息'
elif msg.type == 'image':
msg_content = '收到图片信息'
elif msg.type == 'voice':
msg_content = '收到语音信息'
elif msg.type == 'video':
msg_content = '收到视频消息'
print(msg.media_id)
elif msg.type == 'shortvideo':
msg_content = '收到小视频消息'
print(msg.media_id)
elif msg.type == 'location':
msg_content = '收到地理位置消息'
print(msg.label)
elif msg.type == 'link':
msg_content = '收到链接消息'
print(msg.link)
elif msg.type == 'event':
if msg.event == 'subscribe':
# 在用户关注公众号的时候,获取用户的openid,保存在数据库中,而当用户在注册的时候,
# 从注册页面再获取一次openid,同时把用户的手机号和openid,并根据该openid更新该用户的手机号。
print('============================>获取用户openid')
print(msg.source)
print('============================>')
msg_content = '用户关注'
elif msg.event == 'unsubscribe':
print('取消关注公众号') # 取消关注公众号后,不能向用户发送消息,但可以对用户资料进行处理。
elif msg.event == 'subscribe_scan':
msg_content = '未关注用户扫描带参二维码事件'
elif msg.event == 'scan':
msg_content = '已关注用户扫描带参二维码事件'
elif msg.event == 'location':
msg_content = '上报地理信息事件'
elif msg.event == 'click':
msg_content = '点击自定义菜单'
elif msg.event == 'view':
msg_content = '点击菜单跳转事件'
else:
msg_content = '其它消息'
print(msg_content)
return HttpResponse('')
4 配置Wechat分路由
from django.urls import path
from .views.WechartInterface import WeChatInterface
urlpatterns = [
path('WechatInterface/', WeChatInterface.as_view()),
]
5 配置工程总路由
把Wechat分路由加到总路由中
from django.contrib import admin
from django.urls import path, include, re_path
from rest_framework.documentation import include_docs_urls
from TongHeng2 import settings
from rest_framework_jwt.views import obtain_jwt_token
DESCRIPTION = """
包括仝恒绩效云所有接口文档。包括以下应用:
1 GeneralTools:常用工具APP
2 Organizations: 组织机构(包含组织下的人员)APP
3 Examples:示例APP,用于新知识的测试案例
"""
urlpatterns = [
path('admin/', admin.site.urls),
path('Examples/', include('Applications.Examples.urls')),
path('Organizations/', include('Applications.Organizations.urls')),
path('Wechat/', include('Applications.WeChat.urls')),
path('docs/', include_docs_urls(title='API接口文档', description=DESCRIPTION)),
path('authorizations/', obtain_jwt_token)
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
6 把工程发布到指定IP的服务器上
7 测试公众号消息和事件

浙公网安备 33010602011771号