微信公众号开发

文章目录

      • 订阅号、服务号
      • 微信公众号开发场景
      • 扩展应用模型
      • 接入微信公众平台
      • 公众号接收与发送消息
      • 接受其他普通消息
      • 关注、取消关注
      • 微信网页授权

订阅号、服务号

  • 微信公众号主要面向的是名人、政府、媒体、企业等机构的,它又分为订阅号服务号
  • 订阅号服务号都有订阅和普通的区分,订阅的账号其开通的接口权限会更多些
    • 订阅号:主要偏向于为用户传达资讯,(功能类似报纸杂志,为用户提供新闻信息或娱乐趣事),每天可群发1条消息,消息是在订阅账号列表里的
    • 服务号:主要偏向于服务交互(功能类似12315,114,银行,提供绑定信息,服务交互),每月可群发4条消息,它的消息是在用户的聊天列表的
  • 注册地址

微信公众号开发场景

  • 公众号的消息自动回复想做的智能一些,类似于iphone的Siri,例如粉丝发送“今天的北京天气”到公众号,回复粉丝信息时要按照特定时间特定城市给予反馈;
  • 公众号内嵌的网页需要获取浏览用户的微信头像、昵称、当前定位等信息
  • 以上两种均是微信公众平台预定义功能无法完成的,所以就需要公众号开发了

扩展应用模型

  • 就是在用一台我们自己的服务器对接微信的服务器,微信服务器把用户发来的消息转接到我们的服务器,然后我们的服务器在经过处理后,把需要恢复的东西交给微信服务器,由其发送回给微信用户
    微信公众号开发_第1张图片

接入微信公众平台

  • 可以用微信的测试平台来进行开发测试

  • 首先,我们得先验证服务器的有效性

    • 在测试平台中,有个接口信息配置信息

      URL    http://服务器的IP/wechat
      Token  fxh   # 用于验证的
      

      URL得注意的是,端口只能是80,不写则默认的是80

    • 点击提交按钮时,微信服务器会向上面填写的ip发送一个GET请求,其携带四个参数

      参数 描述
      signature w微信加密签名,signature结合开发者填写的token参数和请求中timestamp参数、noce参数
      timestamp 时间戳
      nonce 随机数
      echostr 随机字符串
    • 开发者通过检验signature对请求进行校验,若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败

    • 校验流程:

      • token、timestamp、nonce三个参数进行字典序排序
      • 将三个参数字符串拼接成一个字符串进行sha1加密
      • 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
      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模块

    • 该模块是用来帮助我们更方便的模块,有两个常用的方法parseunparse
      • xmltodict.parse():将XML数据转为Python字典dict
      • xmltodict.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>
    
    
    • Event:事件类型,subscribe(订阅)、unsubscribe(取消订阅)

微信网页授权

  • 我们要实现一个微信内网页,通过微信访问网页时,网页会展示微信用户的个人信息。因为涉及到用户的个人信息,所以需要有用户授权才可以。当用户授权后,我们的网页服务器(开发者服务器)会拿到用户的“授权书”(code),我们用这个code向微信服务器领取访问令牌(accecc_token)和用户的身份号码(openid),然后凭借access_token和openid向微信服务器提取用户的个人信息

    • 第一步:用户同意授权,获取code
    • 第二步:通过code换取网页授权access_token
    • 第三步:拉取用户信息(需scope为 snsapi_userinfo)
  • 获取流程

    • 设置网页授权回调域名

    • 让用户访问下面链接,同意授权,获取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)
      
      

你可能感兴趣的:(Flask,微信,python,公众号开发)