🆕 add ui
This commit is contained in:
@@ -9,24 +9,14 @@
|
|||||||
3. 安装依赖:`npm i`。
|
3. 安装依赖:`npm i`。
|
||||||
4. 安装 pm2:`npm i -g pm2`。
|
4. 安装 pm2:`npm i -g pm2`。
|
||||||
5. 使用 Nginx 反代我们的 Node.js 服务,默认端口 3000。
|
5. 使用 Nginx 反代我们的 Node.js 服务,默认端口 3000。
|
||||||
6. 使用 pm2 启动应用:`pm2 start ./app.js --name wechat-message-push-service`。
|
|
||||||
|
|
||||||
### 微信公众平台端配置
|
### 微信公众平台端配置
|
||||||
1. 首先前往[此页面](https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index) 拿到 APP_ID 以及 APP_SECRET。
|
1. 首先前往[此页面](https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index)拿到 APP_ID 以及 APP_SECRET。
|
||||||
2. 填写接口配置信息,URL 填 `https://你的域名/verify`,TOKEN 随意,之后点击验证。
|
2. 填写接口配置信息,URL 填 `https://你的域名/verify`,TOKEN 随意,之后点击验证。
|
||||||
3. 使用微信扫描下方的测试号二维码,拿到你的 OPEN_ID。
|
3. 使用微信扫描下方的测试号二维码,拿到你的 OPEN_ID。
|
||||||
4. 新增模板消息模板,模板标题随意,模板内容填 `{{text.DATA}}`,提交后可以拿到 TEMPLATE_ID。
|
4. 新增模板消息模板,模板标题随意,模板内容填 `{{text.DATA}}`,提交后可以拿到 TEMPLATE_ID。
|
||||||
|
|
||||||
### 启动服务
|
### 启动服务
|
||||||
1. 至此,我们已经拿到所有我们需要的信息,接下来设置环境变量,方法很多,例如可以通过在应用的根目录创建 .env 文件,设置以下环境变量:
|
1. 使用 pm2 启动应用:`pm2 start ./app.js --name wechat-message-push-service`。
|
||||||
```
|
2. 访问首页填写配置项并提交。
|
||||||
APP_ID=wx*****
|
2. 之后访问 `https://你的域名/push?content=Hi`,如果微信能够收到消息一条内容为 Hi 的模板消息,则配置成功。
|
||||||
APP_SECRET=*****
|
|
||||||
TOKEN=你的 TOKEN
|
|
||||||
TEMPLATE_ID=****
|
|
||||||
OPEN_ID=****
|
|
||||||
PORT=3000
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 使用 `pm2 restart wechat-message-push-service` 重启服务。
|
|
||||||
3. 之后访问 `https://你的域名/push?content=Hi`,如果微信能够收到消息一条内容为 Hi 的模板消息,则配置成功。
|
|
||||||
@@ -13,6 +13,11 @@ const app = express();
|
|||||||
requestToken(app);
|
requestToken(app);
|
||||||
setInterval(() => requestToken(app), 100 * 60 * 1000);
|
setInterval(() => requestToken(app), 100 * 60 * 1000);
|
||||||
|
|
||||||
|
const port = parseInt(process.env.PORT || "3000");
|
||||||
|
app.set("port", port);
|
||||||
|
app.set("views", path.join(__dirname, "views"));
|
||||||
|
app.set("view engine", "ejs");
|
||||||
|
|
||||||
app.use(logger("dev"));
|
app.use(logger("dev"));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: false }));
|
app.use(express.urlencoded({ extended: false }));
|
||||||
@@ -21,8 +26,6 @@ app.use(express.static(path.join(__dirname, "public")));
|
|||||||
|
|
||||||
app.use("/", indexRouter);
|
app.use("/", indexRouter);
|
||||||
|
|
||||||
const port = parseInt(process.env.PORT || "3000");
|
|
||||||
app.set("port", port);
|
|
||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
|
|
||||||
server.listen(port);
|
server.listen(port);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"cookie-parser": "~1.4.4",
|
"cookie-parser": "~1.4.4",
|
||||||
"debug": "~2.6.9",
|
"debug": "~2.6.9",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"ejs": "^3.1.5",
|
||||||
"express": "~4.16.1",
|
"express": "~4.16.1",
|
||||||
"morgan": "~1.9.1"
|
"morgan": "~1.9.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,12 +2,55 @@ const express = require("express");
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
|
const fs = require("fs");
|
||||||
|
const requestToken = require("./utils").requestToken;
|
||||||
|
|
||||||
router.get("/", (req, res, next) => {
|
router.all("/", (req, res, next) => {
|
||||||
res.send("OK");
|
fs.promises
|
||||||
|
.access("./.env")
|
||||||
|
.then(() => {
|
||||||
|
res.render("message", {
|
||||||
|
message: "服务已在运行。",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
res.render("configure");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/verify", (req, res, next) => {
|
router.post("/configure", (req, res, next) => {
|
||||||
|
fs.promises
|
||||||
|
.access("./.env")
|
||||||
|
.then(() => {
|
||||||
|
res.render("message", {
|
||||||
|
message: ".env 文件已经存在,请手动删除该文件后重试!",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
let content =
|
||||||
|
`APP_ID=${req.body.APP_ID}\n` +
|
||||||
|
`APP_SECRET=${req.body.APP_SECRET}\n` +
|
||||||
|
`TOKEN=${req.body.TOKEN}\n` +
|
||||||
|
`TEMPLATE_ID=${req.body.TEMPLATE_ID}\n` +
|
||||||
|
`OPEN_ID=${req.body.OPEN_ID}`;
|
||||||
|
fs.promises
|
||||||
|
.writeFile("./.env", content, "utf8")
|
||||||
|
.then(() => {
|
||||||
|
res.render("message", {
|
||||||
|
message:
|
||||||
|
".env 文件写入成功,程序即将自动关闭以应用写入的新的环境变量,需要进程守护程序自动重启应用或者手动重启。",
|
||||||
|
});
|
||||||
|
process.exit();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
res.render("message", {
|
||||||
|
message: "在尝试写入 .env 文件时发生错误:" + e,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.all("/verify", (req, res, next) => {
|
||||||
// 验证消息来自微信服务器:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
|
// 验证消息来自微信服务器:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
|
||||||
const { signature, timestamp, nonce, echostr } = req.query;
|
const { signature, timestamp, nonce, echostr } = req.query;
|
||||||
const token = process.env.TOKEN;
|
const token = process.env.TOKEN;
|
||||||
@@ -21,10 +64,9 @@ router.get("/verify", (req, res, next) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/push", (req, res, next) => {
|
router.all("/push", (req, res, next) => {
|
||||||
// Reference: https://mp.weixin.qq.com/debug/cgi-bin/readtmpl?t=tmplmsg/faq_tmpl
|
// Reference: https://mp.weixin.qq.com/debug/cgi-bin/readtmpl?t=tmplmsg/faq_tmpl
|
||||||
let content = req.query.content || req.body.content;
|
let content = req.query.content || req.body.content;
|
||||||
console.log(`Get content: ${content}`);
|
|
||||||
let access_token = req.app.access_token;
|
let access_token = req.app.access_token;
|
||||||
let request_data = {
|
let request_data = {
|
||||||
touser: process.env.OPEN_ID,
|
touser: process.env.OPEN_ID,
|
||||||
@@ -37,6 +79,9 @@ router.get("/push", (req, res, next) => {
|
|||||||
request_data
|
request_data
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
if (response.data && response.data.errcode === "40001") {
|
||||||
|
requestToken(req.app);
|
||||||
|
}
|
||||||
res.json(response.data);
|
res.json(response.data);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.data && res.data.access_token) {
|
if (res.data && res.data.access_token) {
|
||||||
console.log("Get token: ", res.data.access_token);
|
console.log("Token requested.");
|
||||||
token = res.data.access_token;
|
token = res.data.access_token;
|
||||||
app.access_token = token;
|
app.access_token = token;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<%- include('./header') %>
|
||||||
|
<h2 class="subtitle">配置页面</h2>
|
||||||
|
<article class="message is-warning">
|
||||||
|
<div class="message-header">
|
||||||
|
<p>警告</p>
|
||||||
|
</div>
|
||||||
|
<div class="message-body">
|
||||||
|
提交后将在程序的根目录创建一个 .env 文件,之后程序将自动关闭,请确保你已经使用了诸如 pm2 的进程守护程序来自动重启本程序。提交之后如果想要对配置内容进行修改,则你必须手动删除 .env 文件。
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<form action="/configure" method="post">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">APP ID</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" name="APP_ID" type="text" required placeholder="请输入 APP ID">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">APP SECRET</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" name="APP_SECRET" type="text" required placeholder="请输入 APP SECRET">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">OPEN ID</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" name="OPEN_ID" type="text" required placeholder="请输入你的 OPEN ID">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">TEMPLATE ID</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" name="TEMPLATE_ID" type="text" required placeholder="请输入一个模板文章 ID">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">TOKEN</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" name="TOKEN" type="text" required placeholder="请输入你的 TOKEN">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field is-grouped is-grouped-right">
|
||||||
|
<div class="control">
|
||||||
|
<input type="submit" class="button is-link" value="提交">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<input type="reset" class="button is-link is-light" value="重置">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<%- include('./footer') %>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
</div>
|
||||||
|
</body>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css">
|
||||||
|
<title>WeChat Message Push Service</title>
|
||||||
|
</head>
|
||||||
|
<body style="width: 100%;">
|
||||||
|
<div style="margin: auto; max-width: 960px">
|
||||||
|
<h1 class="title" style="margin-top: 16px"><a style="color: black; text-decoration: none">微信消息通知服务</a></h1>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<%- include('./header') %>
|
||||||
|
<article class="message is-primary">
|
||||||
|
<div class="message-header">
|
||||||
|
<p>注意</p>
|
||||||
|
</div>
|
||||||
|
<div class="message-body">
|
||||||
|
<%= message %>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<%- include('./footer') %>
|
||||||
Reference in New Issue
Block a user