可以用微信的测试平台来进行开发测试
首先,我们得先验证服务器的有效性
在测试平台中,有个接口信息配置信息
URL http://服务器的IP/wechat
Token fxh # 用于验证的
URL得注意的是,端口只能是80,不写则默认的是80
点击提交按钮时,微信服务器会向上面填写的ip发送一个GET请求,其携带四个参数
参数 | 描述 |
---|---|
signature | w微信加密签名,signature结合开发者填写的token参数和请求中timestamp参数、noce参数 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
开发者通过检验signature对请求进行校验,若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败
校验流程:
from flask import Flask,request,abort
import hashlib
app = Flask(__name__)
@app.route('/wechat')
def wechat():
# 设置token
token = 'python'
# 获取参数
data = request.args
signature = data.get('signature')
timestamp = data.get('timestamp')
nonce = data.get('nonce')
echostr = data.get('echostr')
# 校验参数
if not all([signature, timestamp, nonce]):
abort(400)
# 按照微信的流程进行计算签名
temp = [timestamp,nonce,token]
# 排序
temp.sort()
# 拼接字符串
temp_str = ''.join(temp)
# 进行sha1加密,得到正确的签名值
sign = hashlib.sha1(tmp_str).hexdigest() # hexdigest()获取加密后的结果
if signature == sign:
return echostr
else:
return abort(403)
if __name__ == '__main__':
app.run(port=8000,debug=True)
把代码运行在我们的服务器上面,然后平台上点击提交
注意:因为我之前在服务器上用Nginx部署了项目,所以当微信服务器访问时会不成功,导致点击提交会提示配置失败,这时就得去修改下nginx的配置文件,在监听的80端口中加上
location /wechat {
proxy http://127.0.0.1:8000;
}
用户向公众号发送消息时,公众号方收到的消息发送者是一个OpenID,是使用用户微信号加密后的结果,每个用户对每个公众号有一个唯一的OpenID
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上
格式如下:
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>1478317060CreateTime>
<MsgType>MsgType>
<Content>Content>
<MsgId>6349323426230210995MsgId>
xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方账号(一个OpenID) |
CreateTime | 消息创建时间 |
MsgType | text(文本消息的类型) |
Content | 文本消息内容 |
MsgID | 消息ID,64位整型 |
xmltdict模块
xmltodict.parse()
:将XML数据转为Python字典dictxmltodict.unparse()
:将dict数据转换为XML数据发送文本消息
无非就是按上面的xml的格式把数据发送回去
if signature != sign:
# 表示请求不是微信发的
abort(403)
else:
# 表示是微信发送的请求
if request.method == "GET":
# 表示是第一次接入微信服务器的验证
echostr = request.args.get("echostr")
if not echostr:
abort(400)
return echostr
elif request.method == "POST":
# 表示微信服务器转发消息过来
xml_str = request.data
if not xml_str:
abort(400)
# 对xml字符串进行解析
xml_dict = xmltodict.parse(xml_str)
xml_dict = xml_dict.get("xml")
# 提取消息类型
msg_type = xml_dict.get("MsgType")
if msg_type == "text":
# 表示发送的是文本消息
# 构造返回值,经由微信服务器回复给用户的消息内容
resp_dict = {
"xml": {
"ToUserName": xml_dict.get("FromUserName"),
"FromUserName": xml_dict.get("ToUserName"),
"CreateTime": int(time.time()),
"MsgType": "text",
"Content": xml_dict.get("Content")
}
}
else:
resp_dict = {
"xml": {
"ToUserName": xml_dict.get("FromUserName"),
"FromUserName": xml_dict.get("ToUserName"),
"CreateTime": int(time.time()),
"MsgType": "text",
"Content": "i love u"
}
}
# 将字典转换为xml字符串
resp_xml_str = xmltodict.unparse(resp_dict)
# 返回消息数据给微信服务器
return resp_xml_str
图片消息
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>1348831860CreateTime>
<MsgType>MsgType>
<PicUrl>PicUrl>
<MediaId>MediaId>
<MsgId>1234567890123456MsgId>
xml>
参数 | 描述 | 回复时是否需要 |
---|---|---|
ToUserName | 开发者微信号 | 是 |
FromUserName | 发送方帐号(一个OpenID) | 是 |
CreateTime | 消息创建时间 (整型) | 是 |
MsgType | image | 是 |
PicUrl | 图片链接 | 是 |
MediaId | 图片消息媒体id,可以调用多媒体文件下载接口拉取数据 | 是 |
MsgId | 消息id,64位整型 |
视频消息
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>1357290913CreateTime>
<MsgType>MsgType>
<MediaId>MediaId>
<ThumbMediaId>ThumbMediaId>
<MsgId>1234567890123456MsgId>
xml>
参数 | 描述 |
---|---|
MsgType | 视频为video(小视频shortvideo) |
MediaId | 视频消息媒体id,可以调用多媒体文件下载接口拉取数据 |
ThumbMediaId | 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据 |
回复
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>12345678CreateTime>
<MsgType>MsgType>
<Video>
<MediaId>MediaId>
<Title>Title>
<Description>Description>
Video>
xml>
Title:视频消息的标题,并不是必须传
Description:视频消息的描述,不是必须
语音消息
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>1357290913CreateTime>
<MsgType>MsgType>
<MediaId>MediaId>
<Format>Format>
<MsgId>1234567890123456MsgId>
xml>
参数 | 描述 |
---|---|
MsgType | 语音为voice |
MediaId | 语音消息媒体id,可以调用多媒体文件下载接口拉取数据 |
Format | 语音格式,如amr,speex等 |
用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>123456789CreateTime>
<MsgType>MsgType>
<Event>Event>
xml>
我们要实现一个微信内网页,通过微信访问网页时,网页会展示微信用户的个人信息。因为涉及到用户的个人信息,所以需要有用户授权才可以。当用户授权后,我们的网页服务器(开发者服务器)会拿到用户的“授权书”(code),我们用这个code向微信服务器领取访问令牌(accecc_token)和用户的身份号码(openid),然后凭借access_token和openid向微信服务器提取用户的个人信息
获取流程
设置网页授权回调域名
让用户访问下面链接,同意授权,获取code
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数 | 是否必读 | 说明 |
---|---|---|
appid | 是 | 公众号唯一标识 |
redirect_url | 是 | 授权后重定向的回调链接地址,请使用urlencode对链接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用授权作用域,snsapi_base(不弹出授权页面,直接跳转,只能获取用户的openid),snsapi_userinfo(弹出授权页面,可通过openid拿到昵称、性别、所在地)。并且,即使在未授权的情况下,只要用户授权,也能获取其信息 |
state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 |
#wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 |
通过code换取网页授权access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
code:填写上一步获取的code
grant_type:就填写authorization_code
返回的json数据
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
获取用户信息,请求
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
代码
WECHAT_APPID = "wx67755f74fxfeef78"
WECHAT_APPSECRET = "aaf6dbca95a012895eb570f0ba549ee5"
@app.route("/wechat8000/index")
def index():
"""让用户通过微信访问的网页页面视图"""
# 从微信服务器中拿去用户的资料数据
# 1. 拿去code参数
code = request.args.get("code")
if not code:
return u"确实code参数"
# 2. 向微信服务器发送http请求,获取access_token
url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" \
% (WECHAT_APPID, WECHAT_APPSECRET, code)
# 使用urllib2的urlopen方法发送请求
# 如果只传网址url参数,则默认使用http的get请求方式, 返回响应对象
response = urllib2.urlopen(url)
# 获取响应体数据,微信返回的json数据
json_str = response.read()
resp_dict = json.loads(json_str)
# 提取access_token
if "errcode" in resp_dict:
return u"获取access_token失败"
access_token = resp_dict.get("access_token")
open_id = resp_dict.get("openid") # 用户的编号
# 3. 向微信服务器发送http请求,获取用户的资料数据
url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" \
% (access_token, open_id)
response = urllib2.urlopen(url)
# 读取微信传回的json的响应体数据
user_json_str = response.read()
user_dict_data = json.loads(user_json_str)
if "errcode" in user_dict_data:
return u"获取用户信息失败"
else:
# 将用户的资料数据填充到页面中
return render_template("index.html", user=user_dict_data)