在上篇博客阿里云部署django实现公网访问已经实现了了django在阿里云上的部署,接下来记录django实现微信公众号简单回复的开发过程,以方便日后查看

  内容概要:

  (1)微信公众号声请

  (2)微信公众号开发者配置

  (3)文本回复实现

  (4)图片回复实现

1. 微信公众号声请

  微信公众号的申请就不作介绍了,参考微信公众平台开发者文档中的入门指引

2. 微信公众号开发者配置

  开发者配置是微信公众号开发的第一步,显得极其重要

  公众平台官网登录之后,找到“基本配置”菜单栏,如下图:

  

  重点说明URL(服务器地址的配置),即与微信服务器直接通讯的服务器地址,我这里设置的是http://外网ip/wx/

  同时django中的配置如下:(说明:我的django工程为mysite,微信应用为wechat)

  (1)mysite目录下的urls.py配置如下

  1. #from django.contrib import admin
  2. #from django.urls import path
  3. #from django.conf.urls import include,url
  4.  
  5. from django.conf.urls import url, include
  6. from django.contrib import admin
  7. urlpatterns = [
  8. url(r'^admin/', admin.site.urls),
  9. url(r'^blog/', include(('blog.urls',"blog"),namespace="blog")),
  10. url(r'^account/', include(('account.urls','account'),namespace='account')),
  11. url(r'^wx/', include(('wechat.urls','wechat'),namespace='wechat')),
  12. ]

  (2)wechat目录下的urls.py配置如下

  1. from django.conf.urls import url
  2. from .views import WeChat
  3.  
  4. urlpatterns = [url(r'^$', WeChat.as_view())]

  注:第一次我的URL配置为http://外网ip/wx,但在进行微信回复时提示"You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SL.....",百度后将修改settings:APPEND_SLASH=False也没有成功,后将配置改为http://外网ip/wx/成功了,若大家遇到同样的问题,可以多做尝试,主要原因还是因为表单的提交要将from的action地址改为/结尾

  (3)token验证

  token验证流程如下图:

  

  代码实现:

  1. # Create your views here.
  2. # -*- coding: utf- -*-
  3. from django.shortcuts import render
  4.  
  5. from django.http import HttpResponse
  6. from django.views.decorators.csrf import csrf_exempt
  7. from django.views.generic.base import View
  8. from django.template import loader, Context
  9. from xml.etree import ElementTree as ET
  10. import time
  11. import hashlib
  12. from .analysis import Analysis
  13. from django.utils.encoding import smart_str
  14.  
  15. class WeChat(View):
  16. #这里我当时写成了防止跨站请求伪造,其实不是这样的,恰恰相反。因为django默认是开启了csrf防护中间件的
  17. #所以这里使用@csrf_exempt是单独为这个函数去掉这个防护功能。
  18. @csrf_exempt
  19. def dispatch(self, *args, **kwargs):
  20. return super(WeChat, self).dispatch(*args, **kwargs)
  21.  
  22. #微信的介入验证是GET方法
  23. #微信正常的收发消息是POST方法
  24. @csrf_exempt
  25. def get(self, request):
  26. print("welcome wx")
  27. #下面这四个参数是在接入时,微信的服务器发送过来的参数
  28. signature = request.GET.get('signature', None)
  29. #print(signature)
  30. timestamp = request.GET.get('timestamp', None)
  31. nonce = request.GET.get('nonce', None)
  32. echostr = request.GET.get('echostr', None)
  33.  
  34. #这个token是我们自己来定义的,并且这个要填写在开发文档中的Token的位置
  35. token = 'fateli'
  36.  
  37. #把token,timestamp, nonce放在一个序列中,并且按字符排序
  38. hashlist = [token, timestamp, nonce]
  39. hashlist.sort()
  40.  
  41. #将上面的序列合成一个字符串
  42. hashstr = ''.join([s for s in hashlist])
  43.  
  44. #通过python标准库中的sha1加密算法,处理上面的字符串,形成新的字符串。
  45. s1 = hashlib.sha1()
  46. s1.update(hashstr.encode("utf8"))
  47. hashstr = s1.hexdigest()
  48. #print(hashstr)
  49. #把我们生成的字符串和微信服务器发送过来的字符串比较,
  50. #如果相同,就把服务器发过来的echostr字符串返回去
  51. if hashstr == signature:
  52. return HttpResponse(echostr)
  53. else:
  54. return HttpResponse("field")

  配置成功后就可以开始后续的消息回复工作了。若出现为问题,一定要仔细阅读开发者文档说明。

3. 文本回复实现

  回复的实现主要是要清除协议,其后就很简单了。

(1)接受文本格式

  1. <xml>
  2. <ToUserName><![CDATA[公众号]]></ToUserName>
  3. <FromUserName><![CDATA[粉丝号]]></FromUserName>
  4. <CreateTime></CreateTime>
  5. <MsgType><![CDATA[text]]></MsgType>
  6. <Content><![CDATA[欢迎开启公众号开发者模式]]></Content>
  7. <MsgId></MsgId>
  8. </xml>

(2)回复文本格式

  1. <xml>
  2. <ToUserName><![CDATA[粉丝号]]></ToUserName>
  3. <FromUserName><![CDATA[公众号]]></FromUserName>
  4. <CreateTime></CreateTime>
  5. <MsgType><![CDATA[text]]></MsgType>
  6. <Content><![CDATA[test]]></Content>
  7. </xml>

(3)代码实现

  新建analysis.py

  1. from xml.etree import ElementTree as ET
  2. import time
  3.  
  4. class Analysis:
  5. def __init__(self, xmlData):
  6. print("接收到的数据:" + xmlData)
  7.  
  8. def prase(self, xmlText):
  9. xmlData = ET.fromstring(xmlText)
  10. msgType = xmlData.find("MsgType").text
  11. toUserName = xmlData.find("ToUserName").text
  12. fromUserName= xmlData.find("FromUserName").text
  13.  
  14. if msgType == 'text':
  15. content = xmlData.find("Content").text
  16.  
  17. TextMsgObj = TextMsg(toUserName, fromUserName, content)
  18. return TextMsgObj.structReply()
  19.  
  20. elif msgType == 'image':
  21. mediaId = xmlData.find("MediaId").text
  22.  
  23. ImageMsgObj = ImageMsg(toUserName,fromUserName,mediaId)
  24. return ImageMsgObj.structReply()
  25.  
  26. class TextMsg:
  27. def __init__(self,toUser,fromUser,recvMsg):
  28. self._toUser = toUser
  29. self._fromUser = fromUser
  30. self._recvMsg = recvMsg
  31. self._nowTime = int(time.time())
  32.  
  33. def structReply(self):
  34. content = self._recvMsg
  35. text = """
  36. <xml>
  37. <ToUserName><![CDATA[{}]]></ToUserName>
  38. <FromUserName><![CDATA[{}]]></FromUserName>
  39. <CreateTime>{}</CreateTime>
  40. <MsgType><![CDATA[text]]></MsgType>
  41. <Content><![CDATA[{}]]></Content>
  42. </xml>
  43. """.format(self._fromUser, self._toUser,self._nowTime,content) #前面两个参数的顺序需要特别注意
  44.  
  45. return text

  POST代码如下:

  1. @csrf_exempt
  2. def post(self, request):
  3. print("POST请求")
  4. analysisObj = Analysis(smart_str(request.body))
  5. toWxData = analysisObj.prase(smart_str(request.body))
  6. print(toWxData)
  7. return HttpResponse(smart_str(toWxData))

4. 图片回复实现

  实现了文本回复后图片恢复也就很简单了,过程一样,只是协议字段有区别

(1)接受文本格式

  1. <xml>
  2. <ToUserName><![CDATA[公众号]]></ToUserName>
  3. <FromUserName><![CDATA[粉丝号]]></FromUserName>
  4. <CreateTime></CreateTime>
  5. <MsgType><![CDATA[image]]></MsgType>
  6. <PicUrl><![CDATA[http://mmbiz.qpic.cn/xxxxxx /0]]></PicUrl>
  7. <MsgId></MsgId>
  8. <MediaId><![CDATA[gyci5a-xxxxx-OL]]></MediaId>
  9. </xml>

(2)回复文本格式

  1. <xml>
  2. <ToUserName><![CDATA[粉丝号]]></ToUserName>
  3. <FromUserName><![CDATA[公众号]]></FromUserName>
  4. <CreateTime></CreateTime>
  5. <MsgType><![CDATA[image]]></MsgType>
  6. <Image>
  7. <MediaId><![CDATA[gyci5oxxxxxxv3cOL]]></MediaId>
  8. </Image>
  9. </xml>

注意回复文本格式中只有MediaId,后续博客进行说明

(3)代码实现

  1. class ImageMsg:
  2. def __init__(self,toUser,fromUser,mediaId):
  3. self._toUser = toUser
  4. self._fromUser = fromUser
  5. self._rediaId = mediaId
  6. self._nowTime = int(time.time())
  7. self._mediaId = mediaId
  8.  
  9. def structReply(self):
  10. text = """
  11. <xml>
  12. <ToUserName><![CDATA[{}]]></ToUserName>
  13. <FromUserName><![CDATA[{}]]></FromUserName>
  14. <CreateTime>{}</CreateTime>
  15. <MsgType><![CDATA[image]]></MsgType>
  16. <Image>
  17. <MediaId><![CDATA[{}]]></MediaId>
  18. </Image>
  19. </xml>
  20. """.format(self._fromUser, self._toUser,self._nowTime,self._mediaId) #前面两个参数的顺序需要特别注意
  21.  
  22. return text

  

  在开发过程中遇到问题,可以使用微信公众平台提供的在线接口调试工具。

原计划是继续进行菜单项的开发,但由于是个人订阅号,无法卡通认证,也就无法获取API开发权限,目前只能到此。

Django实现微信公众号简单自动回复的更多相关文章

  1. node微信公众号开发---自动回复

    微信开发的特点:1.post请求 (一定要注意,这里和配置域名的时候不一样,配置域名是get请求)2.数据包是xml格式的3.你给微信返回的数据也是xml格式的 var parseString = r ...

  2. 小机器人自动回复(python,可扩展开发微信公众号的小机器人)

    api来之图灵机器人.我们都知道微信公众号可以有自动回复,我们先用python脚本编写一个简单的自动回复的脚本,利用图灵机器人的api. http://www.tuling123.com/help/h ...

  3. [.NET] 使用 Senparc.Weixin 接入微信公众号开发:简单实现自动回复

    使用 Senparc.Weixin 接入微信公众号开发:简单实现自动回复 目录 一.前提 二.基本配置信息简析 三.配置服务器地址(URL) 四.请求处理 一.前提 先申请微信公众号的授权,找到或配置 ...

  4. 线程安全使用(四) [.NET] 简单接入微信公众号开发:实现自动回复 [C#]C#中字符串的操作 自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化 自已动手做高性能消息队列 自行实现高性能MVC WebAPI 面试题随笔 字符串反转

    线程安全使用(四)   这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来. 这里主要讲解下CancellationT ...

  5. Django + Apache + 树莓派 搭建内网微信公众号服务器

    其实早在微信开放公众号开发平台时就想弄一个自己的公众号服务器,奈何对web服务器搭建和开发一窍不通,只是注册了一下开发者帐号,并没有采取行动,万恶的拖延症. 前一年,开始接触python,打开了神奇世 ...

  6. 使用python django快速搭建微信公众号后台

    前言 使用python语言,django web框架,以及wechatpy,快速完成微信公众号后台服务的简易搭建,做记录于此. wechatpy是一个python的微信公众平台sdk,封装了被动消息和 ...

  7. C#微信公众号开发 -- (三)用户关注之后自动回复

    通过了上一篇文章之后的微信开发者验证之后,我们就可以做微信公众号的代码开发了. 当我们点击关注某个公众号的时候,有时候会发现他会自动给我们回复一条消息,比如欢迎关注XXX公众号.这个功能其实是在点击关 ...

  8. 微信公众号PHP简单开发流程

    原文:微信公众号PHP简单开发流程 微信公众号开发分傻瓜模式和开发者模式两种,前者不要考虑调用某些接口,只要根据后台提示傻瓜式操作即可,适用于非专业开发人员. 开发模式当然就是懂程序开发的人员使用的. ...

  9. 微信公众号自动回复_Java

    先声明一下,这是一个maven工程pom文件需要的依赖: <dependency> <groupId>dom4j</groupId> <artifactId& ...

随机推荐

  1. windo form 窗体布局方式

    DataGridView:显示数据表后台数据绑定:List<xxx> list = new List<xxx>();dataGridView1.DataSource = lis ...

  2. C语言单元测试框架--EmbedUnit

    1.简介 Embedded Unit是个纯标准c构建的单元测试框架,主要用在嵌入式c的单体测试上,其主要特点是不依赖于任何C的标准库,所有的对象都是静态分配. 最早这个项目托管在SourceForge ...

  3. 【Python】进程和线程

    多进程 多线程 ThreadLocal 进程vs线程 分布式进程 Top 学习廖老师的py官网的笔记 多任务的实现方式有三种方式: 1.多进程 2.多线程 3.多进程+多线程(这种比较复杂,实际很少采 ...

  4. win vista系统的ReadyBoost性能测试

    如果想提高电脑的性能,大家通常会选择升级处理器.内存或是相关硬件,而新一代Windows Vista操作系统中增加的ReadyBoost功能,号称只需一个USB接口的闪存盘(俗称U盘),就能达到加快系 ...

  5. require和require_once经济性能对比

    require和require_once都是PHP函数,开发人员可以使用它们在某个特定的脚本中导入外部PHP文件.你可以根据应用程序的复杂度调用一次或若干次require_once/require.使 ...

  6. Linux图形化界面下使用命令进行截图的方法

    以前在LINUX里面截图都是直接按print screen键或者 alt + print screen. 但是print screen是整个屏幕, alt + print screen是当前窗口. 想 ...

  7. Spring_管理 Bean 的生命周期

    beans-cycle.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns=&quo ...

  8. GIT生成 SSH Key步骤

    //设置user.name和email 提交到git之后会显示用户名(在随意一个目录打开git-bash执行就行)Administrator@DESKTOP-BP3H0HS MINGW64 /d/mi ...

  9. SFTP无法连接 Connection closed by server with exitcode 127

    命令: Pass: ************状态: Connected to 66.77.88.99错误: Connection closed by server with exitcode 127错 ...

  10. EF Code-First 学习之旅 多对多的关系

    public class Student { public Student() { this.Courses = new HashSet<Course>(); } public int S ...