015 python之微信公众号开发(基本配置和校验)
<div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown"><h2 id="前言">前言</h2>
<p>最近有微信公众号开发的业务,以前没有用python做过微信公众号开发,记录一下自己的学习和开发历程,共勉!</p>
<h2 id="公众号类型">公众号类型</h2>
<ul>
<li>
<p><strong>订阅号</strong></p>
</li>
<li>
<p>普通订阅号</p>
</li>
<li>
<p>认证订阅号</p>
</li>
<li>
<p><strong>服务号</strong></p>
</li>
<li>
<p>普通服务号</p>
</li>
<li>
<p>认证服务号</p>
</li>
</ul>
<h2 id="服务方式">服务方式</h2>
<ul>
<li>
<p>公众号消息会话:包括被动回复</p>
</li>
<li>
<p>公众号内嵌网页</p>
</li>
</ul>
<h2 id="公众号消息类型">公众号消息类型</h2>
<ul>
<li>
<p>群发消息:由公众号想用户发送消息;</p>
</li>
<li>
<p>被动回复消息:客户端发送消息,公众号回复;</p>
</li>
<li>
<p>客服消息:当用户主动发消息给公众号,公众号48小时里可以无限发送消息;</p>
</li>
<li>
<p>模板消息:使用特定的模板内容主动向用户发送消息;</p>
</li>
</ul>
<h2 id="公众号的网页接口">公众号的网页接口</h2>
<ul>
<li>
<p><strong>接口1:</strong></p>
</li>
<li>
<p>网页被授权获取用户的基本信息,由微信提供接口;</p>
</li>
<li>
<p><strong>接口2:</strong></p>
</li>
<li>
<p>微型JS-SDK,用js代码使用原生的微信工具包;</p>
</li>
</ul>
<h2 id="微信公众号开发">微信公众号开发</h2>
<h3 id="先注册一个微信公众号">先注册一个微信公众号</h3>
<ul>
<li>
<p>注册网址:https://mp.weixin.qq.com/cgi-bin/readtemplate?t=register/step1_tmpl&lang=zh_CN</p>
</li>
<li>
<p>进入注册网址后按相关步骤操作即可;</p>
</li>
<li>
<p>注册成功后会进入微信公众平台管理页面</p>
</li>
<li>
<p>登录后进入首页</p>
</li>
<li>
<p>进行公众号设置</p>
</li>
<li>
<p>包括头像,二维码,名称等;</p>
</li>
<li>
<p>可以设置微信号;</p>
</li>
<li>
<p>注意:</p>
</li>
</ul>
<pre><code class="hljs">1.公众号类型一旦被选择就无法更改;</code></pre>
<h3 id="对接微信公众平台">对接微信公众平台</h3>
<ul>
<li>
<p><strong>填写服务器配置</strong></p>
</li>
<li>
<p>URL:可以是域名网址或直接的ip加端口;http必须为80端口,https必须为443端口;</p>
</li>
<li>
<p>Token: 生成签名,微信服务器用来识别公众号服务器;</p>
</li>
<li>
<p>EncodingAESKey:设置消息加解密密匙;</p>
</li>
<li>
<p><strong>验证服务器地址的有效性</strong></p>
</li>
<li>
<p>开发者必须自己架设服务器,当填写URL提交后,微信服务器会发送get请求到开发者的服务器,携带四个参数,自定义返回echostr参数;</p>
</li>
<li>
<p>校验流程:</p>
</li>
</ul>
<p>将token、timestamp、nonce三个参数进行字典序排序<br>
将三个参数字符串拼接成一个字符串进行sha1加密<br>
开发者获得加密后的字符串可与signature对比,标识该请求来源于微信</p>
<ul>
<li>校验的经典代码,适用于Django、Flask、web.py等框架;</li>
</ul>
<pre class="python"><code class="hljs"><span class="hljs-keyword">import</span> hashlib
<span class="hljs-comment"># 在视图函数中</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle</span><span class="hljs-params">(request)</span>:</span>
<span class="hljs-keyword">try</span>:
<span class="hljs-comment"># 先获取request</span>
<span class="hljs-comment"># data = web.input()</span>
<span class="hljs-comment"># if len(data) == 0:</span>
<span class="hljs-comment"># return "hello, this is handle view"</span>
signature = request.get(<span class="hljs-string">"signature"</span>)<span class="hljs-comment"># 先获取加密签名</span>
timestamp = data.timestamp<span class="hljs-comment"># 获取时间戳</span>
nonce = request.get(<span class="hljs-string">"nonece"</span>)<span class="hljs-comment"># 获取随机数</span>
echostr = request.get(<span class="hljs-string">"echostr"</span>) <span class="hljs-comment"># 获取随机字符串</span>
token = <span class="hljs-string">"xxxx"</span> <span class="hljs-comment">#自己设置的token</span>
<span class="hljs-comment"># 使用字典序排序(按照字母或数字的大小顺序进行排序)</span>
list =
list.sort()
<span class="hljs-comment"># 进行sha1加密</span>
temp = <span class="hljs-string">''</span>.join(list)
sha1 = hashlib.sha1(temp.encode(<span class="hljs-string">'utf-8))
# map(sha1.update, list)
hashcode = sha1.hexdigest()
# 将加密后的字符串和signatrue对比,如果相同返回echostr,表示验证成功
if hashcode == signature:
return echostr
else:
return ""
except Exception as e:
return e
</span></code></pre>
<ul>
<li>也可以通过第三方包wechatpy实现</li>
</ul>
<pre><code class="hljs python"><span class="hljs-keyword">from</span> wechatpy.utils <span class="hljs-keyword">import</span> check_signature
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
app = Flask(__name__)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_all_args</span><span class="hljs-params">(req_dict:Dict)</span>:</span>
echostr = req_dict.get(<span class="hljs-string">"echostr"</span>)<span class="hljs-comment"># 获取随机字符串</span>
signature = req_dict.get(<span class="hljs-string">"signature"</span>)<span class="hljs-comment"># 先获取加密签名</span>
timestamp = req_dict.get(<span class="hljs-string">"timestamp"</span>)<span class="hljs-comment"># 获取时间戳</span>
nonce = req_dict.get(<span class="hljs-string">"nonce"</span>)<span class="hljs-comment"># 获取随机数</span>
<span class="hljs-keyword">return</span> echostr,signature,timestamp,nonce
<span class="hljs-meta">@app.route('/wechat_verify/',methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wechat_verify</span><span class="hljs-params">()</span>:</span>
<span class="hljs-string">'''
用来处理微信服务器对本后台的验证,GET方法。
:return:
'''</span>
<span class="hljs-comment"># 获取参数</span>
rq_dict = request.args
<span class="hljs-keyword">if</span> len(rq_dict) == <span class="hljs-number">0</span>:
<span class="hljs-keyword">return</span> <span class="hljs-string">""</span>
tuple_args = get_all_args(rq_dict)
token = current_app.config.get(<span class="hljs-string">'TOKEN'</span>)
<span class="hljs-keyword">try</span>:
check_signature(token, tuple_args[<span class="hljs-number">1</span>], tuple_args[<span class="hljs-number">2</span>], tuple_args[<span class="hljs-number">3</span>])
<span class="hljs-keyword">except</span> InvalidSignatureException <span class="hljs-keyword">as</span> e:
logger.error(e,exc_info=<span class="hljs-keyword">True</span>)
<span class="hljs-keyword">return</span> <span class="hljs-string">''</span>
<span class="hljs-keyword">else</span>:
<span class="hljs-keyword">return</span> tuple_args[<span class="hljs-number">0</span>]</code></pre>
<ul>
<li>
<p><strong>根据接口实现业务逻辑</strong></p>
</li>
<li>
<p>业务1:接收回复普通消息</p>
</li>
</ul>
<p>当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上,这时我们的公众号将覆盖微信提供的自动回复的功能;</p>
<ul>
<li>微信消息的通信使用的是XMl的数据格式,在python中使用xmltodict模块处理xml的数据;主要有两个方法:</li>
</ul>
<pre class="python"><code class="hljs">xmltodict.parse():可以将xml数据转为python中的dict字典数据;
xmltodict.unparse():可以将字典转换为xml字符串</code></pre>
<ol>
<li>文本消息</li>
</ol>
<pre><code class="hljs xml"># 一般也有固定的格式
<span class="hljs-tag"><<span class="hljs-name">xml</span>></span>
<span class="hljs-tag"><<span class="hljs-name">ToUserName</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">ToUserName</span>></span> # 开发者微信号
<span class="hljs-tag"><<span class="hljs-name">FromUserName</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">FromUserName</span>></span># 发送方微信号
<span class="hljs-tag"><<span class="hljs-name">CreateTime</span>></span>1460537339<span class="hljs-tag"></<span class="hljs-name">CreateTime</span>></span># 消息的创建时间
<span class="hljs-tag"><<span class="hljs-name">MsgType</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">MsgType</span>></span># 文本的格式
<span class="hljs-tag"><<span class="hljs-name">Content</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">Content</span>></span># 内容
<span class="hljs-tag"><<span class="hljs-name">MsgId</span>></span>6272960105994287618<span class="hljs-tag"></<span class="hljs-name">MsgId</span>></span> # 消息本身的id
<span class="hljs-tag"></<span class="hljs-name">xml</span>></span>
</code></pre>
<ol>
<li>回复文本</li>
</ol>
<pre class="python"><code class="hljs"><xml>
<ToUserName><!]></ToUserName> <span class="hljs-comment"># 接收方账号 </span>
<FromUserName><!]></FromUserName> <span class="hljs-comment"># 开发者账号</span>
<CreateTime><span class="hljs-number">12345678</span></CreateTime> <span class="hljs-comment"># 创建时间</span>
<MsgType><!]></MsgType> <span class="hljs-comment"># 文本类型</span>
<Content><!]></Content> <span class="hljs-comment"># 文本内容</span>
</xml></code></pre>
<ul>
<li>图片消息</li>
</ul>
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">MsgType</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">MsgType</span>></span># 图片的类型为image
<span class="hljs-tag"><<span class="hljs-name">PicUrl</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">PicUrl</span>></span> # 图片链接
<span class="hljs-tag"><<span class="hljs-name">MediaId</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">MediaId</span>></span># 图片消息id</code></pre>
<ul>
<li>视频消息</li>
</ul>
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">MsgType</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">MsgType</span>></span> # 视频类型为video,小视频为shortvideo</code></pre>
<ul>
<li>语音消息</li>
</ul>
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">MsgType</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">MsgType</span>></span># 语音格式
<span class="hljs-tag"><<span class="hljs-name">MediaId</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">MediaId</span>></span># 消息id
<span class="hljs-tag"><<span class="hljs-name">Format</span>></span><!]><span class="hljs-tag"></<span class="hljs-name">Format</span>></span> # 语音格式,如amr</code></pre>
<h2 id="视图处理原则">视图处理原则</h2>
<ul>
<li>
<p>可以将普通的消息处理放置在一个视图中,在一个视图中进行判断处理,减少视图的数量。</p>
</li>
<li>
<p>如果不能再5秒内及时返回,可以先返回成功或空字符串,避免出现严重的错误。</p>
</li>
</ul>
<h3 id="实现内嵌网页">实现内嵌网页</h3>
<p>分成三步走:</p>
<ol>
<li>第一步:用户同意授权,获取code,code指的是用户的授权书;这时有微信发起的;</li>
<li>第二步:通过code换取网页授权access_token,这时微信发下的通信证;</li>
<li>第三步:拉取用户信息(需scope为 snsapi_userinfo);</li>
</ol>
<ul>
<li>设置网页授权回调域名</li>
</ul>
<p><strong>注意</strong></p>
<ul>
<li>
<p>填写的是域名,而不是URL,所以不需要添加http://等;</p>
</li>
<li>
<p>可以填写IP和端口;</p>
</li>
</ul>
<h2 id="相关文档">相关文档</h2>
<ul>
<li>
<p>获取微信公众号access_token接口凭证:url: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET</p>
</li>
<li>
<p>获取微信IP地址:https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN</p>
</li>
<li>
<p>自定义菜单接口:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN</p>
</li>
<li>
<p>微信开发文档:https://mp.weixin.qq.com/wiki/home/index.html</p>
</li>
</ul>
<p><strong>总结:本篇博客是对开发微信公众号的一些整体需要做的准备工作和整体的认识,下一篇开始正式开发。</strong></p>
</div><br><br>
来源:https://www.cnblogs.com/abdm-989/p/11991407.html
頁:
[1]