小程序订阅消息推送搭建|订单自动提醒配置步骤

发布时间:2026-07-16 00:02

小程序订阅消息推送是提升用户回访率和订单转化率的重要工具。当用户在小程序中下单后,系统能自动向用户发送“订单已发货”、“服务即将到期”等提醒,无需用户主动打开小程序。本教程将手把手教你从零搭建小程序订阅消息推送功能,并配置订单自动提醒。

---

### 前置准备

1. **已上线的小程序**:确保你的小程序已完成微信认证,且已发布上线。未认证的小程序无法使用订阅消息功能。

2. **小程序AppID与AppSecret**:登录[微信公众平台](https://mp.weixin.qq.com/),在「开发」-「开发设置」中获取。AppSecret仅在首次生成时可见,请妥善保存。

3. **服务器环境**:你需要一台公网可访问的服务器(或使用云函数),用于接收用户下单事件并调用微信接口发送消息。本教程以Node.js(Express框架)为例,其他语言逻辑相同。

4. **微信开发者工具**:用于调试小程序前端代码。

5. **数据库**:用于存储用户的openid、订阅模板ID、订单状态等数据。本教程以MySQL为例。

---

### 分步操作步骤

#### 1. 申请并配置订阅消息模板

**操作目的**:在微信公众平台创建消息模板,获取模板ID,这是推送消息的“格式说明书”。

1. 登录微信公众平台,进入「功能」-「订阅消息」。

2. 点击「公共模板库」标签页,在搜索框输入“订单发货提醒”或“服务状态通知”,找到适合你业务的模板。例如选择“订单发货通知”,点击「选用」。

3. 在「我的模板」列表中,会看到刚添加的模板。点击模板名称,进入详情页。

4. **配置模板字段**:每个模板都有固定的参数(如订单编号、商品名称、发货时间、温馨提示)。你需要将这些参数与你系统中的数据对应。例如:

- `订单编号`:对应你数据库中的`order_id`

- `商品名称`:对应`product_name`

- `发货时间`:对应`delivery_time`

- `温馨提示`:可填写固定文案,如“请留意快递信息”。

5. **获取模板ID**:在模板详情页顶部,复制「模板ID」(如:`qwe123rty456uio789`)。后续发送消息时必须使用此ID。

#### 2. 小程序前端:引导用户订阅并获取凭证

**操作目的**:用户首次进入小程序时,需要主动点击“允许”按钮,才能接收后续消息。这一步必须在用户操作触发(如点击按钮)时调用,不能自动弹窗。

1. 在小程序页面(如订单详情页)添加一个「接收发货提醒」按钮,绑定点击事件。

2. 在点击事件处理函数中,调用微信API `wx.requestSubscribeMessage`。代码示例(app.js或页面js中):

```javascript

// 页面逻辑

Page({

data: {

tmplIds: ['qwe123rty456uio789'] // 替换为你的模板ID

},

subscribeMessage() {

const that = this;

wx.requestSubscribeMessage({

tmplIds: that.data.tmplIds,

success(res) {

// res 返回用户授权结果

// 例如:{ 'qwe123rty456uio789': 'accept' } 表示用户同意

if (res[that.data.tmplIds[0]] === 'accept') {

console.log('用户已同意订阅');

// 可以在此处调用后端接口,记录该用户已订阅此模板

// 例如:wx.request({ url: 'https://你的域名/api/saveSubscribe', method: 'POST', data: { openid: '用户openid', tmplId: '模板ID' } })

} else {

console.log('用户拒绝了订阅');

}

},

fail(err) {

console.error('订阅失败', err);

}

});

}

})

```

3. **重要**:`wx.requestSubscribeMessage` 必须在用户点击按钮后调用,且每次只能传入一个模板ID(或最多三个,但建议一次一个)。用户同意后,该授权**单次有效**。也就是说,用户每次希望收到消息时,都需要重新弹窗授权。但微信允许在用户授权后,你可以在7天内向用户发送1条消息(具体次数取决于模板类型,通常为1次/次授权)。

#### 3. 后端:接收用户授权记录并存储

**操作目的**:将用户授权信息(openid、模板ID、授权时间)存入数据库,以便后续发送消息时查询。

1. 在你的服务器上创建数据库表 `subscribe_records`,结构如下(MySQL示例):

```sql

CREATE TABLE `subscribe_records` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`openid` varchar(100) NOT NULL COMMENT '用户唯一标识',

`template_id` varchar(100) NOT NULL COMMENT '订阅模板ID',

`subscribe_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '授权时间',

`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1-有效 0-已使用',

PRIMARY KEY (`id`),

KEY `idx_openid` (`openid`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

```

2. 编写后端接口 `/api/saveSubscribe`,接收小程序传来的 `openid` 和 `tmplId`,插入数据库。示例(Node.js + Express):

```javascript

// 假设你已使用express、mysql2等库

app.post('/api/saveSubscribe', async (req, res) => {

const { openid, tmplId } = req.body;

try {

// 先检查该用户是否已存在有效授权(避免重复插入)

const [existing] = await db.query('SELECT id FROM subscribe_records WHERE openid = ? AND template_id = ? AND status = 1', [openid, tmplId]);

if (existing.length === 0) {

await db.query('INSERT INTO subscribe_records (openid, template_id) VALUES (?, ?)', [openid, tmplId]);

}

res.json({ code: 0, msg: 'success' });

} catch (error) {

console.error(error);

res.status(500).json({ code: -1, msg: 'fail' });

}

});

```

#### 4. 后端:获取AccessToken

**操作目的**:调用微信订阅消息接口前,必须先获取接口调用凭证 `access_token`。

1. 编写获取access_token的函数。微信接口地址:`GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET`。

2. 由于access_token有效期为7200秒(2小时),建议缓存到内存或Redis中,避免频繁请求。示例代码:

```javascript

const axios = require('axios');

const APPID = '你的AppID';

const APPSECRET = '你的AppSecret';

let cachedToken = null;

let tokenExpireTime = 0;

async function getAccessToken() {

if (cachedToken && Date.now() < tokenExpireTime) {

return cachedToken;

}

const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;

const response = await axios.get(url);

if (response.data.access_token) {

cachedToken = response.data.access_token;

tokenExpireTime = Date.now() + (response.data.expires_in - 300) * 1000; // 提前5分钟过期

return cachedToken;

} else {

throw new Error('获取access_token失败:' + JSON.stringify(response.data));

}

}

```

#### 5. 后端:发送订阅消息(订单自动提醒)

**操作目的**:当订单状态变为“已发货”时,系统自动向用户推送消息。

1. 在你的订单处理逻辑中(例如发货操作完成后),调用发送消息函数。

2. 发送消息的微信接口地址:`POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN`

3. 请求体格式示例:

```json

{

"touser": "用户openid",

"template_id": "你的模板ID",

"page": "pages/order/detail?orderId=123", // 用户点击消息后跳转的小程序页面

"data": {

"thing1": { "value": "2023年秋季新款卫衣" }, // 商品名称

"character_string2": { "value": "ORD20231001" }, // 订单编号

"time3": { "value": "2023-10-01 14:00:00" }, // 发货时间

"thing4": { "value": "请留意快递信息,保持电话畅通" } // 温馨提示

}

}

```

**注意**:`data`中的字段名(如`thing1`、`character_string2`)必须与模板详情页中的参数名完全一致。模板中参数类型(thing、character_string、time等)也必须对应。

4. 编写发送函数:

```javascript

async function sendSubscribeMessage(openid, templateId, data, page) {

const accessToken = await getAccessToken();

const url = `https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${accessToken}`;

const body = {

touser: openid,

template_id: templateId,

page: page || '',

data: data

};

try {

const response = await axios.post(url, body);

if (response.data.errcode === 0) {

console.log('消息发送成功');

// 更新数据库记录,标记该授权已使用

await db.query('UPDATE subscribe_records SET status = 0 WHERE openid = ? AND template_id = ? AND status = 1', [openid, templateId]);

return true;

} else {

console.error('发送失败', response.data);

return false;

}

} catch (error) {

console.error('请求异常', error);

return false;

}

}

```

5. **触发时机**:在你后端发货接口中,调用此函数。例如:

```javascript

// 假设这是你的发货接口

app.post('/api/deliverOrder', async (req, res) => {

const { orderId } = req.body;

// 1. 更新订单状态为已发货

await db.query('UPDATE orders SET status = "shipped" WHERE id = ?', [orderId]);

// 2. 查询订单详情(用户openid、商品名等)

const [order] = await db.query('SELECT openid, product_name, order_no FROM orders WHERE id = ?', [orderId]);

// 3. 查询该用户是否有有效的订阅授权

const [sub] = await db.query('SELECT id FROM subscribe_records WHERE openid = ? AND template_id = ? AND status = 1', [order.openid, '你的模板ID']);

if (sub.length > 0) {

// 4. 发送消息

const data = {

thing1: { value: order.product_name },

character_string2: { value: order.order_no },

time3: { value: new Date().toLocaleString() },

thing4: { value: '您的订单已发货,请留意查收' }

};

await sendSubscribeMessage(order.openid, '你的模板ID', data, `pages/order/detail?orderId=${orderId}`);

}

res.json({ code: 0, msg: '发货成功' });

});

```

#### 6. 测试与验证

1. 使用微信开发者工具,点击“接收发货提醒”按钮,允许授权。

2. 在你的后台手动将某个订单状态改为“已发货”,或直接调用发货接口。

3. 观察服务器日志,确认消息发送成功(返回`errcode:0`)。

4. 打开手机微信,进入该小程序,查看是否收到“服务通知”中的订阅消息。注意:消息不会在小程序内弹出,而是在微信首页的“服务通知”中显示。

---

### 常见问题

**Q1:用户授权后,为什么没有收到消息?**

- **原因1**:用户授权后,你发送消息时使用的模板ID与授权时的模板ID不一致。检查前后端模板ID是否完全一致。

- **原因2**:用户授权后,你发送消息的时间超过了7天(部分模板有效期更短)。授权是一次性的,发送后即失效。

- **原因3**:用户在小程序设置中关闭了“订阅消息”开关。用户可在「发现」-「小程序」-右上角「...」-「设置」中管理。

- **原因4**:消息内容格式错误。检查`data`中的字段名和类型是否与模板完全匹配,例如`thing`类型不能超过20个字符。

**Q2:如何让用户能多次收到消息?**

- **方案**:每次需要发送消息前,都让用户点击按钮重新授权。例如,用户每次下单后,在订单详情页都显示“订阅发货提醒”按钮。用户点击后,你获得一次发送权限,然后在发货时发送。下次再下单,用户需要再次点击。

**Q3:access_token获取失败怎么办?**

- **检查**:AppID和AppSecret是否正确。注意AppSecret不要泄露,最好使用环境变量存储。

- **频率**:微信对access_token获取有频率限制(每日2000次),正常使用不会触发。

**Q4:发送消息时返回`errcode:43101`?**

- **含义**:用户拒绝授权或授权已过期。检查数据库中的`status`字段,确保该授权未被使用过且未过期。

**Q5:小程序页面跳转无效?**

- **原因**:`page`参数必须是小程序已注册的页面路径,且不能带参数?可以带参数,但路径必须正确。例如`pages/order/detail?orderId=123`。注意路径大小写。

---

### 收尾总结

通过以上步骤,你已成功搭建小程序订阅消息推送系统,并实现了订单自动提醒功能。核心流程为:用户主动授权 → 后端存储授权记录 → 触发事件(如发货) → 获取access_token → 调用微信接口发送消息。请务必注意,订阅消息是“单次授权、单次发送”机制,不能像公众号模板消息那样无限推送。合理利用这一机制,在关键节点(如发货、退款、到期)提醒用户,能有效提升用户体验和复购率。建议在用户授权后,立即发送一条测试消息,确保链路畅通。