微信公众号定时提醒

2023-05-16

写在前面

参考:微信公众号定时提醒女友今日天气以及距离发薪日还有多久
以上答主已经写的非常详细了,不过关于接口配置信息那一块我还想说两句, 另外我也根据我编写 node 代码的习惯改了下一项目目录,最后的效果如下效果

如果你不想看了 源码奉上
顺便可以给我的博客刷一下pvuv[旺柴]https://blog.liufashi.top

前提

  • 首先自己要有一个云服务器
  • 如果你是像上面的同学一样给女朋友用的那么你还需要一个女朋友

准备工作

申请测试号

为什么是测试号呢? 申请地址 因为发送模板消息目前微信只对认证的服务号开放
模板消息

安装 express

全局安装 npm i express-generator -g, 创建项目express -e office-account
进入项目目录安装依赖npm i

验证微信 token

/routes文件夹新建 wechat.js,用于授权验
安装 jsshanpm i jssha -S

const express = require("express");
const router = express.Router();
const jsSHA = require("jssha");
/**
 * 授权验证
 */
router.get("/", function (req, res, next) {
  // 这里写你刚刚在上面随机生成的字符串
  const token = "";
  //1.获取微信服务器Get请求的参数 signature、timestamp、nonce、echostr
  let signature = req.query.signature, //微信加密签名
    timestamp = req.query.timestamp, //时间戳
    nonce = req.query.nonce, //随机数
    echostr = req.query.echostr; //随机字符串

  //2.将token、timestamp、nonce三个参数进行字典序排序
  let array = [token, timestamp, nonce];
  array.sort();

  //3.将三个参数字符串拼接成一个字符串进行sha1加密
  let tempStr = array.join("");
  let shaObj = new jsSHA("SHA-1", "TEXT");
  shaObj.update(tempStr);
  let scyptoString = shaObj.getHash("HEX");

  //4.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
  if (signature === scyptoString) {
    console.log("验证成功");
    res.send(echostr);
  } else {
    console.log("验证失败");
    res.send("验证失败");
  }
});

module.exports = router;

上面代码中的 token 需与此处一致token可以随机生成也可以自随便写个符合条件的
这些完成后需要将项目部署至服务器测试是否验证成功。如果你的服务器上安装了 git 那么直接将代码上传至 git,然后在服务器 clone 下来即可,进入目录使用 pm2 运行pm2 start bin/www --name wechat 添加别名更好区分。
接口配置的 url 可以设置为 http://[你的 ip]:[项目运行的端口 默认 3000]/wechat,这样就可以访问到你刚刚写的 routes/wechat.js,前提是你的服务器需要配置对应端口(3000)安全组规则token
如果你不想通过 ip 访问可以购买一个域名,配置域名解析token
在 nginx 配置代理,将域名代理到对应端口 如下:
上面是 https 的配置,下面是 监听 80 端口重定向到 https

server {
    listen 443;
	ssl   on;
    #配置HTTPS的默认访问端口为443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    #如果您使用Nginx 1.15.0及以上版本,请使用listen 443 ssl代替listen 443和ssl on。
    server_name wechat.liufashi.top; #需要将yourdomain替换成证书绑定的域名。

    ssl_certificate ssl/wechat/wechat.liufashi.top.pem;  #需要将cert-file-name.pem替换成已上传的证书文件的名称。
    ssl_certificate_key  ssl/wechat/wechat.liufashi.top.key; #需要将cert-file-name.key替换成已上传的证书私钥文件的名称。
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    #表示使用的加密套件的类型。
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #表示使用的TLS协议的类型。
    ssl_prefer_server_ciphers on;
    location / {
        proxy_pass http://localhost:3000;
    }
}
server {
    listen 80;
    server_name wechat.liufashi.top; #需要将yourdomain替换成证书绑定的域名。
    rewrite ^(.*)$ https://$host$1;
}

如果暂时不使用 https,只需要简单的几行即可

server {
    listen 80;
    server_name wechat.liufashi.top;
    location / {
        proxy_pass http://localhost:3000;
    }
}

验证通过后将自己的域名添加为 JS 接口安全域名

开始动手

为了方便维护和后面添加新的,我将用到的获取 token 和发送消息两个方法拿了出来,新建 getToken.js 和 postMessage.js。然后将一些可能会变动的信息拿了出来,新建 info.js。下面用到的依赖没有装的话记得装一下,贴一份开发依赖

"dependencies": {
    "axios": "^0.27.2",
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "ejs": "~2.6.1",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "jssha": "^3.2.0",
    "moment": "^2.29.3",
    "morgan": "~1.9.1",
    "nodemon": "^2.0.16"
  }

getToken.js

const fs = require("fs");
const path = require("path");
const axios = require("axios");
const moment = require("moment");
const info = require("./info");
function getToken() {
  return new Promise((resolve, reject) => {
    const tokenFile = path.join(__dirname, "token.json");
    fs.readFile(tokenFile, "utf-8", function (err, data) {
      if (err) {
        reject(err);
      } else {
        if (data) {
          const token = JSON.parse(data);
          if (token.expires_in > moment().unix()) {
            resolve(token.access_token);
            return;
          }
        }
        axios
          .get(
            `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${info.appId}&secret=${info.appSecret}`
          )
          .then((res) => {
            resolve(res.data.access_token);
            const t = res.data;
            t.expires_in = t.expires_in + moment().unix() - 1200;
            fs.writeFile(
              tokenFile,
              JSON.stringify(t, "", "\t"),
              function (err) {
                if (err) {
                  reject(err);
                }
              }
            );
          })
          .catch((err) => reject(err));
      }
    });
  });
}
module.exports = getToken;

postMessage.js

const axios = require("axios");

function postMessage(token, templateId, openId, data) {
  axios
    .post(
      "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" +
        token,
      {
        touser: openId,
        template_id: templateId, // 模板信息id
        topcolor: "#FF0000",
        data: data,
      }
    )
    .then((res) => {
      console.log(res.data);
    })
    .catch((err) => {
      console.log(err);
    });
}

module.exports = postMessage;

info.js

module.exports = {
  appId: "", //appID
  appSecret: "", //appsecret
  gouldKey: "", //搞得天气的key
  //使用encodeURL,不然在node中中文编码可能会出问题
  address: encodeURI(""), //需要获取天气的地址,使用地址获取abccode,防止abccode改动
  city: encodeURI(""), //需要获取天气的城市 可不要
  openId: "", //加密后的微信号,关注公众号之后可以看到
  myOpenId: "", //自己的,用看看有没有发送成功
};

新建一个 posts 文件夹,里面新建提醒,比如我新建了一个下班提醒 afterWork.js
然后再公众号中新建模板,如:

下班时间到啦! 不要忘记打卡哦! 明天天气是{{Weather.DATA}} 气温{{Temperature.DATA}} {{Reminder.DATA}}

Weather.DATA 会匹配到Weather: { value: tomorrowWeather.dayweather, color: "#ff9900", }中的内容,并且会添加文字颜色
生成模板后会有个 templateId
templateId

const info = require("../info");
const getToken = require("../getToken");
const postMessage = require("../postMessage");
const axios = require("axios");
const moment = require("moment");
// 模板id
const templateId = "";

const postAfterWork = async () => {
  const city = await axios
    .get(
      `https://restapi.amap.com/v3/geocode/geo?key=${info.gouldKey}&address=${info.address}&city=${info.city}`
    )
    .catch((err) => console.log(err));
  const { data: weatherInfo } = await axios
    .get(
      `https://restapi.amap.com/v3/weather/weatherInfo?key=${info.gouldKey}&city=${city.data.geocodes[0].adcode}&extensions=all&output=JSON`
    )
    .catch((err) => console.log(err));
  if (weatherInfo.status === "1") {
    const todayWeather = weatherInfo.forecasts[0].casts[0];
    const tomorrowWeather = weatherInfo.forecasts[0].casts[1];

    const getReminder = () => {
      const day = 5 - moment().weekday();
      switch (day) {
        case 0:
          return "恭喜你又熬到了周末,要好好休息享受周末啦";
        case 1:
          return "今天星期四,明天星期五,周末就要来啦";
        case 2:
          return "还有两天就周末了,开心起来!!!";
        case 3:
          return "叮~ 第二天工作结束,继续加油鸭!";
        case 4:
          return "本周第一天工作结束啦! 是不是很难熬~ 还有四天哦 O(∩_∩)O哈哈~";
      }
    };
    const data = {
      Weather: {
        value: tomorrowWeather.dayweather,
        color: "#ff9900",
      },
      Temperature: {
        value: `${tomorrowWeather.daytemp}℃ ~ ${tomorrowWeather.nighttemp}`,
        color: "#2d8cf0",
      },
      Reminder: {
        value: getReminder(),
        color: "#ffc0cb",
      },
    };
    getToken()
      .then((token) => {
        // 接受信息的人的openid
        postMessage(token, templateId, info.myOpenId, data);
        postMessage(token, templateId, info.openId, data);
      })
      .catch((err) => {
        console.log(err);
      });
  }
};
module.exports = postAfterWork;

最后将 postAfterWork 引入到 app.js,添加执行条件可以使用定时任务的插件来执行。但是我这里就简单的一分钟执行一次了。在 app.js 中加入

const postAfterWork = require("./posts/afterWork");
// 轮询时间,发送对应的post
const cycle = setInterval(async function () {
  const h = moment().hour();
  const m = moment().minute();
  const week = moment().weekday();
  // 不同时间执行不行的post
  try {
    //周一到周五 下午五点五十九
    if (h === 5 && m === 59 && week && week < 6) {
      postAfterWork();
    }
  } catch (error) {
    console.log(error);
    clearInterval(cycle);
  }
}, 1000 * 60);

到此就全部完成了。如果需要添加新的提醒只需要: 在 posts 文件夹中新增逻辑–>在公众号中添加模板–>在 app.js 中引入添加执行条件,然后还是不太了解的可以到这里看看源码的使用方法

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信公众号定时提醒 的相关文章

  • 电脑发热严重:禁用独立显卡(Nvidia)/ TLP解决cpu占用率大

    引言 CPU温度经常居高不下 xff0c 每天风扇嗡嗡响 xff0c 尝试过许多办法都没有解决 xff0c 最后用了一个工具 xff0c 并禁用独显 xff0c 明显改善 xff01 1 禁用独立显卡 参考 xff08 真正帮我解决问题的方
  • 网易云音乐网络问题修复 (加载失败)

    问题 网易云一切网络功能正常 xff0c 唯有在线播放时出现问题 xff0c 提示加载失败 问题解决 查看log xff0c 发现是不能建立到m7 music 126 net 原因不知道 联系舍友问能不能听歌 xff0c 舍友说可以 xff
  • ibus-setup-sunpinyin 打不开

    ibus setup sunpinyin 打不开 提示 Traceback most recent call last File 34 usr share ibus sunpinyin setup main py 34 line 42 in
  • 编译原理 Tiny编译器和TM虚拟机

    编译器与解释器的设计流程 编译器前端部分 词法分析 字符流 gt 记号流 词法分析也称作扫描 xff0c 是编译器的第一个步骤 xff0c 词法分析器读入组成源程序的字符流 xff0c 并且将它们组织成为有意义的词素的序列 xff0c 对于
  • Markdown emoji 收藏

    表情符的使用 人物 syntaxpreviewsyntaxpreviewsyntaxpreview bowtie bowtie smile x1f604 laughing x1f606 blush x1f60a smiley x1f603
  • Powershell中解决win10无法打开设置等应用问题

    在powershell中 选择run as administer 输入 Get AppxPackage AllUsers Foreach Add AppxPackage DisableDevelopmentMode Register spa
  • Arduino设计 有害气体检测小车

    有害气体检测小车 从代码已经可以看得出电路应该怎么接了 具体电路就不放上来了 Arduino控制部分代码 span class token macro property span class token directive keyword
  • xpath —— 父子、兄弟、相邻节点定位方式详解

    1 由父节点定位子节点 最简单的肯定就是由父节点定位子节点了 xff0c 我们有很多方法可以定位 xff0c 下面上个例子 xff1a 对以下html代码 span class token tag span class token tag
  • Wireshark Lab: TCP v7.0

    Wireshark Lab TCP v7 0 Answer the following questions by opening the Wireshark captured packet file tcpethereal trace 1
  • org.openqa.selenium.UnableToSetCookieException: unable to set cookie

    1 当尝试添加cookies时抛出selenium unable to set cookie错误 大多情况是在一个webDriver空域 xff08 没有访问任意一个页面 xff09 中添加cookies xff0c 我们要做的就是在赋值c
  • IPC之Posix共享内存详解

    1 概念 共享内存区 xff0c 按标准可分为Posix共享内存区和System V共享内存区 xff0c 两者在概念上类似 Posix 表示可移植操作系统接口 xff08 Portable Operating System Interfa
  • IIS配置PHP运行环境

    这里写自定义目录标题 添加IIS服务下载安装PHP在IIS7中添加php支持 新建站点修改host文件 添加域名解析测试 添加IIS服务 控制面板 程序 打开或关闭Windows功能 勾选 Internet 信息服务 勾选 IIS 管理控制
  • 使用远程工具远程连接linux(xshell,xftp,xmanager,xrdp)

    前言 首先来说一下为什么要使用远程工具来控制linux呢 xff0c 相信大家都知道linux主要是用来做服务器的 xff0c 而在实际工作中 xff0c linux服务器可能在别的机房 xff0c 所以常常需要使用远程工具来操作 养成使用
  • 创建一个快捷方式设置浏览器跨域

    浏览器跨域设置 chrome以及新版Edge xff08 chrome内核 xff09 新建一个快捷方式 新建一个文件夹 例如 xff1a MyEdgeDevUserData 我是直接在C盘下创建的 xff0c 经过测试 xff0c 其他位
  • Mysql8修改密码和远程访问

    mysql8修改密码和远程访问 MySql 从8 0开始修改密码有了变化 xff0c 在user表加了字段authentication string xff0c 修改密码前先检查authentication string是否为空 1 如果不
  • centos7 安装node环境(一遍过)

    centos7 安装node环境 前言 xff1a 查看当前系统架构 span class token function uname span span class token parameter variable n span span
  • 栈实现回文字符串判断

    回文判断 xff1a 正读和反读都相同的字符序列称为回文 从回文的定义可以看出 xff0c 回文字符串的正序和逆序输出结果是相同的 xff0c 算法需要做的就是将字符串串进行进栈然后出栈操作 xff0c 将其与正序字符串进行比较 xff0c
  • 搭建confluence服务器(详细操作+踩坑说明)

    linux服务器配置推荐 前提 xff1a web服务 xff0c 文件服务 xff0c 数据库服务部署在同一台服务器上 推荐配置 2核 43 4G8G 内存 43 300G硬盘 经过实践 xff0c 4G内存还是不够用 部署资源 atla
  • 各种转码(bytes、string、base64、numpy array、io、BufferedReader )

    将字节流转ndarray import io import struct import cv2 import numpy as np a 61 b 39 x89PNG r n x1a n x00 x00 x00 rIHDR x00 x00
  • 利用hanlp比较文本相似度

    import com hankcs hanlp seg common Term import com hankcs hanlp tokenizer StandardTokenizer import org apache commons la

随机推荐