当前位置:   article > 正文

微信公众号开发教程

微信公众号开发教程

本教程为看微信公众号视频做的笔记,原视频链接:尚硅谷公众号开发,微信公众号开发实战_哔哩哔哩_bilibili

平台

微信公众号管理:公众号 (qq.com)

微信公众测试号平台:微信公众平台 (qq.com)

微信公众号开发文档:微信公众平台开发概述 | 微信开放文档 (qq.com)

目录说明:

|_ config 存放配置文件

|_ index.js 配置文件,存放了需要用到的内容

|_ utils 工具

|_ tool.js 存放写的工具类

|_ wechat 存放微信接口

|_ auth.js 微信服务器的有效性验证

|_ accessToken.js 获取微信 access_token(调用微信接口必须携带的参数,是全局的唯一凭证,2小时失效)

|_ app.js 程序入口

接口配置信息

进入微信公众平台 (qq.com),看到如下页面

首先配置接口(接口配置信息),用 js 使用 express 框架编写如下代码:

  1. // 引入express
  2. const express = require('express');
  3. const app = express();
  4. app.use((req, res, next) => {
  5.  console.log(111);
  6.  res.send(111);
  7. });
  8. app.listen(3000, () => {
  9.  console.log('Server is running at http://localhost:3000');
  10. });

也就是创建一个运行在 3000 端口的服务器,这里我们 localhost:3000 这个端口并不能用于微信这个配置接口。

URL

打开 ngrok.exe ,目标路径D:\A-study\software\cpolar.exe,进行内网穿透,将本地端口号开启的服务映射外网跨域访问一个网址,输入如下命令:

// 此处 3000 为服务器所在端口号
cpolar http 3000

页面如下:

 

此时访问:http://7ed2c829.r3.cpolar.top即可实现和 localhost:3000 一样的效果。

这个地址可用于微信这个配置接口。复制此路径,粘贴到配置接口中。

ngrok 这个程序不要关闭,关闭此接口无法响应。

Token

这里的 Token 是一个微信签名的一个参数,在这里可以随意填写,越长越好。

配置完如下

 

验证消息来源

这里我们之所以使用 app.use(),原因是可以接受处理所有消息,配置好上两项,点击提交,在app.use()中查看req.query,得到一下结果:

{
    // 微信的加密签名
    signature: '0393d4e16dc0cf2c907c6d7d9c6bfdfce4c2efce',
    // 微信的随机字符串
    echostr: '4359501947458813682',
    // 微信的发送请求时间戳
    timestamp: '1661430480',
    // 微信的随机数字
    nonce: '1215363190'
}

我们的目的是要验证消息是否是来自微信服务器的,原理:

计算得出 signature 微信加密签名,和微信传递过来的 signature 进行对比,如果二者相同,则说明消息来自于微信服务器,反之,不是微信服务器发送的消息。

那么怎么进行计算呢,如下是步骤:

  1. 将参与微信加密签名的三个参数(传来的:timestamp、nonce、自己设置的:token),组合到一起,按照字典排序,并组合在一起形成一个数组

  2. 将数组拼接所有项拼接成一个字符串,进行 sha1 加密

  3. 加密完成就生成了一个 signatrue ,和微信发送过来的进行对比

    如果一样,说明消息来自于微信服务器,返回 echostr 给微信服务器

    如果不一样,说明不是微信发送的消息,返回 error

设置一个 config 变量用于储存我们所有需要用到的值:

  1. const config = {
  2.  token: "VikeyAlvinForever",
  3.  appID: "wx56e0df28b365f4d2",
  4.  appsevret: "5b7d5c835c65e984ecb21e0c63864103"
  5. }

安装 sha1 :cnpm i sha1

验证代码如下:

  1. // 引入express
  2. const express = require('express');
  3. const app = express();
  4. // 引入 sha1 模块将计算出的结果加密
  5. const sha1 = require('sha1');
  6. // 配置对象,存我们需要的内容
  7. const config = {
  8.  token: 'VikeyAlvinForever',
  9.  appID: 'wx56e0df28b365f4d2',
  10.  appsevret: '5b7d5c835c65e984ecb21e0c63864103',
  11. };
  12. app.use((req, res, next) => {
  13.  console.log(req.query);
  14.  // 解构赋值
  15.  const { signature, echostr, timestamp, nonce } = req.query;
  16.  const { token } = config;
  17.  console.log('1232' + echostr);
  18.  //将参与微信加密签名的三个参数(传来的:timestamp、nonce、自己设置的:token),组合到一起,按照字典排序,并组合在一起形成一个数组
  19.  const arr = [timestamp, nonce, token];
  20.  // 排序
  21.  const arrSort = arr.sort();
  22.  console.log('arrSort:' + arrSort);
  23.  // 将数组所有参数拼接
  24.  const str = arr.join('');
  25.  console.log('str:' + str);
  26.  // 加密
  27.  const sha1Str = sha1(str);
  28.  console.log('加密后:' + sha1Str);
  29.  // 判断是否相同
  30.  if (sha1Str === signature) {
  31.    res.json(echostr);
  32. } else {
  33.    res.end('error');
  34.    console.log('error');
  35. }
  36. });
  37. app.listen(3000, () => {
  38.  console.log('Server is running at http://localhost:3000');
  39. });

然后在微信公众平台上点击提交,这里我遇到了一个问题,各种代码都没有问题,然而一直配置失败,是那个 ngrok 不行,换成 cpolar 就好使,气死我了。

如图即为成功。

cploar官网:cpolar - secure introspectable tunnels to localhost

获取access_token

access_token 是微信调用接口的唯一凭证,访问微信的接口必须都携带此凭证。

特点:

  1. 唯一的

  2. 有效期为2小时,最好留出时间来请求,我们一般提前5分钟请求

  3. 接口权限 每天最多 2000 次

请求地址:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

请求方式:GET

携带参数:

参数是否必须说明
grant_type获取access_token填写client_credential
appid第三方用户唯一凭证
secret第三方用户唯一凭证密钥,即appsecret

设计思路:

  1. 首次本地没有,发送请求获取 access_token,保存下来(本地文件)

  2. 第二次及以后:

  • 先去本地读取文件,判断他是否过期

    • 过期了 -> 重新请求获取 access_token ,保存下来覆盖之前的文件(保证文件唯一)

    • 没有过期 -> 直接使用

整体思路:

读取本地文件(readAccessToken)

  • 本地有文件

    • 判断是否过期(isValidAccessToken)

    • 过期 -> 重新请求获取 access_token(getAccessToken) ,保存下来覆盖之前的文件(保证文件唯一)(saveAccessToken)

    • 没过期 -> 直接使用

  • 本地没有文件

    • 发送请求获取 access_token(getAccessToken),保存下来(本地文件)(saveAccessToken),直接使用

自动回复

接收用户发来的消息

微信服务器会发送两种类型的消息给开发者服务器:

  1. GET 请求 -> 验证服务器的有效性

  2. POST 请求 -> 微信服务器会将用户发送的数据以POST请求的方式转发到开发者服务器上

再 auth.js 中验证微信服务器发送的是 GET请求 还是 POST请求 获取。

使用手机像测试号发送消息,得到如下

  1. {
  2. signature: 'bd1ffd2a36fdc44ca5b6b0d45ac3980b78489346',
  3. timestamp: '1661772245',
  4. nonce: '1886903686',
  5. openid: 'o1cZB6SJhrmbTWVCfo6l_rzwrkgY'
  6. }

这个 openid 为用户的微信id。

需要接收请求体中的数据,这是一个流式数据。

请求后获取数据:

  1. <xml>
  2. <ToUserName><![CDATA[gh_5cc210c9b162]]></ToUserName>   // 开发者id
  3. <FromUserName><![CDATA[o1cZB6SJhrmbTWVCfo6l_rzwrkgY]]></FromUserName>   // 用户的openid
  4. <CreateTime>1661773339</CreateTime>
  5. <MsgType><![CDATA[text]]></MsgType>
  6. <Content><![CDATA[你好]]></Content>
  7. <MsgId>23790873740096595</MsgId>
  8. </xml>

将xml数据解析为 js 对象

这里我们需要使用一个库:xml2js,使用 xml2js 所提供的 parseString 方法来转换:

parseString(要转换的xml数据,{trim:是否留白},(err,data)=>{})

上文转换成如下:

  1. {
  2. xml: {
  3.   ToUserName: [ 'gh_5cc210c9b162' ],
  4.   FromUserName: [ 'o1cZB6SJhrmbTWVCfo6l_rzwrkgY' ],
  5.   CreateTime: [ '1661774019' ],
  6.   MsgType: [ 'text' ],
  7.   Content: [ '哈喽' ],
  8.   MsgId: [ '23790883295887531' ]
  9. }
  10. }

回复用户发来的消息

判断用户发送的消息:

全匹配: ===

半匹配:message.Content.match('爱')

  1. const content = '您在说什么,我听不懂'
  2. if(message.MsgType === 'text'){
  3.    // 全匹配 用户必须发送指定消息才匹配到
  4.    if(message.Content === "1"){
  5.        content = "大吉大利,今晚吃鸡"
  6.        // 半匹配 只要用户发送消息包含 爱 就会匹配
  7.   }else if(message.Content.match("爱")){
  8.        content = '我爱你~'
  9.   }
  10. }
  11. // 这里ju
  12. let reply = `<xml>
  13.      <ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
  14.      <FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
  15.      <CreateTime>${Date.now()}</CreateTime>
  16.      <MsgType><![CDATA[text]]></MsgType>
  17.      <Content><![CDATA[${content}]]></Content>
  18.      </xml>`;
  19. res.send(reply);

详细请看文档,这里不多赘述。

自定义菜单创建接口

  1. // 自定义菜单
  2. module.exports = {
  3.  button: [
  4.   {
  5.      type: 'click',
  6.      name: '戳我啊~',
  7.      key: 'CLICK',
  8.   },
  9.   {
  10.      name: '菜单',
  11.      sub_button: [
  12.       {
  13.          type: 'view',
  14.          name: '跳转链接',
  15.          url: 'http://www.baidu.com/',
  16.       },
  17.        // {
  18.        //   // 小程序
  19.        //   type: 'miniprogram',
  20.        //   name: 'wxa',
  21.        //   url: 'http://mp.weixin.qq.com',
  22.        //   appid: 'wx286b93c14bbf93aa',
  23.        //   pagepath: 'pages/lunar/index',
  24.        // },
  25.       {
  26.          type: 'click',
  27.          name: '赞一下我们',
  28.          key: 'V1001_GOOD',
  29.       },
  30.       {
  31.          type: 'scancode_waitmsg',
  32.          name: '扫码带提示',
  33.          key: '扫码带提示',
  34.       },
  35.       {
  36.          type: 'scancode_push',
  37.          name: '扫码推事件',
  38.          key: '扫码推事件',
  39.       },
  40.        // {
  41.        //   type: 'media_id',
  42.        //   name: '点击按钮发送图片',
  43.        //   media_id: 'MEDIA_ID1',
  44.        // },
  45.        // {
  46.        //   type: 'view_limited',
  47.        //   name: '图文消息',
  48.        //   media_id: 'MEDIA_ID2',
  49.        // },
  50.     ],
  51.   },
  52.   {
  53.      name: '发图',
  54.      sub_button: [
  55.       {
  56.          type: 'pic_sysphoto',
  57.          // 弹出相机
  58.          name: '系统拍照发图',
  59.          key: '系统拍照发图',
  60.       },
  61.       {
  62.          type: 'pic_photo_or_album',
  63.          // 相册或者拍照
  64.          name: '拍照或者相册发图',
  65.          key: '拍照或者相册发图',
  66.       },
  67.       {
  68.          type: 'pic_weixin',
  69.          // 打开相册
  70.          name: '微信相册发图',
  71.          key: '微信相册发图',
  72.       },
  73.       {
  74.          name: '发送位置',
  75.          type: 'location_select',
  76.          key: 'rselfmenu_2_0',
  77.       },
  78.     ],
  79.   },
  80. ],
  81. };

开发页面

首先安装 ejs,这个ejs,相当于 html 页面,直接可以在 node 中指定跳转

在 app.js 中配置 ejs,配置完才能使用:

  1. // 配置模板资源目录
  2. app.set('views','./views')
  3. // 配置模板引擎
  4. app.set('view engine','ejs')

配置完模板资源以及模板引擎,在day01下创建 views 目录,在此文件夹下创建 search.ejs 文件,编写代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  <head>
  4.    <meta charset="UTF-8" />
  5.    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.    <title>Document</title>
  8.  </head>
  9.  <body>
  10.    <h1>这是一个搜索页面</h1>
  11.  </body>
  12. </html>

在 app.js 中编写代码:

  1. app.get('/search', (req, res) => {
  2.  // 渲染页面,把渲染好的页面传给用户
  3.  res.render('search');
  4. });

这样当访问search 这个路径时,将会渲染出此页面

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/280790
推荐阅读
相关标签
  

闽ICP备14008679号