微信公众号开发

一、微信公众号开发的意义

目前微信公众平台提供给公众号的功能只是简单的被动回复,主动发送,内嵌网页等,无法满足许多用户的需求,所以就需要根据微信平台提供的接口进行进一步开发。

二、微信公众号开发模型:

三、接入微信公众平台

3.1填写服务器配置:

登录微信公众平台官网后,在公众平台后台管理页面 - 开发者中心页,点击“修改配置”按钮

3.2分析:

        URL是开发者用来接收微信消息和事件的接口URL。

        Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。

        EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。

        加解密方式的默认状态为明文模式,选择兼容模式和安全模式需要提前配置好相关加解密代码

3.3利用测试平台

测试平台登陆地址http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

3.4验证服务器地址的有效性:

3.4.1开发者提交信息后,微信服务器将发送GET请求携带4个参数到填写的服务器地址上:

校验流程:

1. 将token、timestamp、nonce三个参数进行字典序排序

2. 将三个参数字符串拼接成一个字符串进行sha1加密

3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

代码实现:

        @app.route('/wechat8000')

        def wechat():

            #设置token

token = 'python'

            #获取参数

            data = request.args

signature = data.get('signature')

timestamp = data.get('timestamp')

nonce = data.get('nonce')

echostr = data.get('echostr')

            #对参数进行字典排序,拼接字符串

temp = [timestamp,nonce,token]

temp.sort()

temp = ''.join(temp)

            #使用sha1加密,与signature进行比较

            if (hashlib.sha1(temp).hexdigest()==signature):

                    return make_response(echostr)

            else:

                    return 'error',403

            if __name__ == '__main__':

                    app.run(port=8000)

3.5开发者服务器配置:

3.5.1首先要有一台公网服务器(阿里云)

3.5.2连接服务器:    ssh  s80xx@101.200.170.171    #服务器账号@服务器IP地址

3.5.3切换到flask_py2 虚拟环境:workon flask_py2

如果提示workon命令未找到:source ~/.bashrc

3.5.4拷贝文件到服务器:

               #scp 源文件   目标文件

scp ./wechat.py    s80xx@101.200.170.171:~/xxxx/

3.5.5在微信开发平台输入服务器URL和Token进行验证

四、公众号接收与发送消息

4.1概念:

4.1.1验证URL有效性成功后即接入生效,成为开发者。如果公众号类型为服务号(订阅号只能使用普通消息接口),可以在公众平台网站中申请认证,认证成功的服务号将获得众多接口权限,以满足开发者需求。

4.1.2此后用户每次向公众号发送消息、或者产生自定义菜单点击事件时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,然后开发者可以依据自身业务逻辑进行响应,例如回复消息等。

4.1.3用户向公众号发送消息时,公众号方收到的消息发送者是一个OpenID,是使用用户微信号加密后的结果,每个用户对每个公众号有一个唯一的OpenID。

4.2接收普通消息:

4.2.1当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

4.2.2XML数据包格式:

<xml>

#开发者公众号

#用户账号(OpenID)

1348831860#消息创建时间戳

 #消息类型,text是文本类型消息

#文本消息内容

1234567890123456 #消息的ID

</xml>

4.3回复普通消息:

4.3.1当用户发送消息给公众号时,会产生一个POST请求,开发者可以在响应包中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。

4.3.2假如服务器无法保证在五秒内处理并回复,必须直接回复success,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。

4.3.3一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:

        1. 开发者在5秒内未回复任何内容

        2. 开发者回复了异常数据,比如JSON数据等

4.3.4返回的XML格式为:

<xml>

 #用户账号(OpenID)

  12345678#消息创建时间

#消息类型(文本)

 #消息内容

</xml>

4.4代码实现:

fromflaskimportFlask,request,abort,render_template

importhashlib

importxmltodict

importtime

importurllib2

importjson

# 常量

# 微信的token令牌

WECHAT_TOKEN ="itcast"

WECHAT_APPID ="wx36766f74dbfeef15"

WECHAT_APPSECRET ="aaf6dbca95a012895eb570f0ba549ee5"

app = Flask(__name__)

@app.route("/wechat8000",methods=["GET","POST"])

defwechat():

"""对接微信公众号服务器"""

    # 接收微信服务器发送的参数

    signature = request.args.get("signature")

    timestamp = request.args.get("timestamp")

    nonce = request.args.get("nonce")

    # 校验参数

    if notall([signature,timestamp,nonce]):

        abort(400)

    # 按照微信的流程进行计算签名

    li = [WECHAT_TOKEN,timestamp,nonce]

    # 排序

    li.sort()

    # 拼接字符串

    tmp_str ="".join(li)

    # 进行sha1加密, 得到正确的签名值

    sign = hashlib.sha1(tmp_str).hexdigest()

    # 将自己计算的签名值与请求的签名参数进行对比,如果相同,则证明请求来自微信服务器

    ifsignature != sign:

        # 表示请求不是微信发的

        abort(403)

    else:

        # 表示是微信发送的请求

        ifrequest.method =="GET":

            # 表示是第一次接入微信服务器的验证

            echostr = request.args.get("echostr")

            if notechostr:

                abort(400)

            returnechostr

        elifrequest.method =="POST":

            # 表示微信服务器转发消息过来

            xml_str = request.data

            if notxml_str:

                abort(400)

            # 对xml字符串进行解析

            xml_dict = xmltodict.parse(xml_str)

            xml_dict = xml_dict.get("xml")

            # 提取消息类型

            msg_type = xml_dict.get("MsgType")

            ifmsg_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)

            # 返回消息数据给微信服务器

            returnresp_xml_str

五、微信网页授权

5.1概念:当微信内网页需要用到用户的个人信息时,需要用户进行授权。

5.2授权的步骤:

            1. 第一步:用户同意授权,获取code

            2. 第二步:通过code换取网页授权access_token

            3. 第三步:拉取用户信息(需scope为 snsapi_userinfo)

5.3授权流程:

5.3.1设置网页授权回调域名:

在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的开发者中心页配置授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL

5.3.2用户同意授权,获取code

5.3.2.1让用户访问一下链接地址:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

5.3.2.2地址参数分析:

                     appid:公众号的唯一标识

                     redirect_uri:授权后重定向的回调链接地址,请使用urlencode对链接进行处理

                     response_type:返回类型,固定填写code

                     scope:填写snsapi_userinfo表示页面可通过OpenID获取用户详细信息

                     state:重定向后会带上state参数,可填可不填                   

#wechat_redirect:最后必须带此参数

5.3.2.3下图为scope等于snsapi_userinfo时的授权页面:


如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE

5.3.2.4通过code换取网页授权access_token:

请求方法:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

5.3.2.5参数分析:

5.3.2.6返回值:

            正确时返回的JSON数据包如下:

            {

"access_token":"ACCESS_TOKEN",

                   "expires_in":7200,

                   "refresh_token":"REFRESH_TOKEN",

                   "openid":"OPENID",

                   "scope":"SCOPE"

            }

            错误时返回的JSON数据包如下:

            {

                    "errcode":40029,

                    "errmsg":"invalid code"

            }

5.3.2.7拉取用户信息(需scope为 snsapi_userinfo):

请求方法:https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

5.3.2.8参数分析:

5.3.2.9返回值:

正确时返回的JSON数据包如下:

            {

               "openid":" OPENID",

               "nickname": NICKNAME,

               "sex":"1",

               "province":"PROVINCE"

               "city":"CITY",

               "country":"COUNTRY",

               "headimgurl":    "头像地址",

               "privilege":[

               "PRIVILEGE1"

               "PRIVILEGE2"

                ],

                "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"

            }

5.3.2.10 JSON数据分析:

5.4用户实际访问的页面地址:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx36766f74dbfeef15&redirect_uri=http%3A//www.itcastcpp.cn/wechat8000/index

&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect

注意:需要使用urllib.quote()函数对redirect_uri进行转码

5.5代码实现:

#www.itcastcpp.cn/wechat8000/index

@app.route("/wechat8000/index")

defindex():

"""让用户通过微信访问的网页页面视图"""

    # 从微信服务器中拿去用户的资料数据

    # 1. 获取code参数

    code = request.args.get("code")

    if notcode:

        returnu"缺失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"inresp_dict:

        returnu"获取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"inuser_dict_data:

    returnu"获取用户信息失败"

    else:

    # 将用户的资料数据填充到页面中

        returnrender_template("index.html",user=user_dict_data)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容