1. 项目概述与背景
在微信公众号开发中,模板消息推送是一个极其重要的功能模块。它允许开发者通过预先定义的模板,向用户发送结构化的通知消息。这种消息形式比普通文本消息更加规范、美观,适用于订单状态变更、系统提醒、业务通知等各种场景。
我最近在一个电商项目中实现了基于ThinkPHP框架的模板消息推送功能。这个功能主要用于在用户下单后,及时向用户推送订单状态变更通知。相比传统的短信通知,微信模板消息具有成本低、到达率高、用户体验好等优势。
2. 微信模板消息基础配置
2.1 准备工作
在开始编码前,我们需要完成以下准备工作:
-
申请模板消息权限:在微信公众平台->功能->模板消息中,申请开通模板消息功能权限。
-
添加消息模板:选择适合业务场景的模板,记录下模板ID。例如我们使用的订单状态通知模板ID为"TM12345"。
-
获取接口调用凭证:需要准备好AppID和AppSecret,用于获取access_token。
注意:微信官方对模板消息的使用有严格限制,只能用于用户触发后的服务通知,不能用于营销推广。
2.2 服务类设计
我设计了一个WeChatSendMessageService服务类来封装所有与微信消息推送相关的逻辑。这种设计有以下优点:
- 将微信相关配置集中管理
- 复用access_token获取逻辑
- 统一处理API调用错误
- 便于后续功能扩展
类的基本结构如下:
php复制class WeChatSendMessageService {
private $appId;
private $appSecret;
private $templateId;
public function __construct() {
$this->appId = '你的AppID';
$this->appSecret = '你的AppSecret';
$this->templateId = 'TM12345'; // 模板ID
}
// 其他方法...
}
3. 核心功能实现
3.1 获取Access Token
access_token是调用微信API的全局唯一凭证,有效期为2小时。我们需要定时获取并缓存它。
php复制public function getAccessToken() {
// 先检查缓存中是否有有效的access_token
$cacheKey = 'wechat_access_token';
$accessToken = Cache::get($cacheKey);
if ($accessToken) {
return $accessToken;
}
// 从微信API获取新的access_token
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}";
$response = $this->httpRequest($url);
$data = json_decode($response, true);
if (isset($data['access_token'])) {
// 缓存access_token,设置过期时间为7100秒(比实际有效期短)
Cache::set($cacheKey, $data['access_token'], 7100);
return $data['access_token'];
}
throw new Exception('获取access_token失败: ' . ($data['errmsg'] ?? '未知错误'));
}
提示:在实际项目中,建议使用Redis等高效的缓存系统来存储access_token,避免频繁请求微信服务器。
3.2 发送模板消息
下面是发送模板消息的核心方法实现:
php复制public function sendTemplateMessage($openid, $templateData) {
$accessToken = $this->getAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$accessToken}";
$postData = [
'touser' => $openid,
'template_id' => $this->templateId,
'data' => $templateData
];
$response = $this->httpRequest($url, json_encode($postData));
$result = json_decode($response, true);
if ($result['errcode'] != 0) {
throw new Exception('发送模板消息失败: ' . $result['errmsg']);
}
return true;
}
3.3 订单完成通知实现
针对订单完成场景,我专门封装了一个方法:
php复制public function jiedanchenggongTongzhi($openid, $orderInfo) {
$templateData = [
'first' => ['value' => '您的订单已完成处理', 'color' => '#173177'],
'keyword1' => ['value' => $orderInfo['order_no'], 'color' => '#173177'],
'keyword2' => ['value' => $orderInfo['complete_time'], 'color' => '#173177'],
'remark' => ['value' => '感谢您的使用,欢迎再次光临!', 'color' => '#173177']
];
return $this->sendTemplateMessage($openid, $templateData);
}
4. HTTP请求封装
与微信API交互需要使用HTTP请求,我封装了一个通用的请求方法:
php复制private function httpRequest($url, $postData = null) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if ($postData) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
}
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('CURL请求错误: ' . curl_error($ch));
}
curl_close($ch);
return $response;
}
5. 实际使用示例
在控制器中调用服务类发送模板消息:
php复制public function orderComplete() {
$orderId = input('order_id');
$order = OrderModel::find($orderId);
$user = UserModel::find($order->user_id);
$WeChatSendMessageService = new WeChatSendMessageService();
try {
$WeChatSendMessageService->jiedanchenggongTongzhi(
$user->openid,
[
'order_no' => $order->order_no,
'complete_time' => date('Y-m-d H:i:s')
]
);
return json(['code' => 200, 'msg' => '通知发送成功']);
} catch (Exception $e) {
return json(['code' => 500, 'msg' => $e->getMessage()]);
}
}
6. 常见问题与解决方案
6.1 模板消息发送失败
问题现象:返回错误码40037,提示"invalid template_id"
解决方案:
- 检查模板ID是否正确
- 确认该模板是否已在公众号后台添加
- 确保模板没有被删除或修改
6.2 access_token获取失败
问题现象:返回错误码40164,提示"invalid ip"
解决方案:
- 在公众号后台配置服务器IP白名单
- 确保调用的服务器IP在公网可访问
6.3 用户收不到消息
问题现象:API返回成功,但用户未收到消息
解决方案:
- 检查用户是否已关注公众号
- 确认用户没有取消消息接收
- 检查openid是否正确
- 确保消息没有进入垃圾箱
7. 性能优化建议
-
access_token缓存:使用Redis等高效缓存系统,避免频繁请求微信服务器。
-
批量发送:对于大量消息,可以考虑使用消息队列异步处理。
-
错误重试机制:对于临时性错误(如网络问题),实现自动重试逻辑。
-
日志记录:详细记录每次发送的请求和响应,便于问题排查。
-
频率限制:遵守微信API的调用频率限制,避免被封禁。
8. 安全注意事项
-
保护AppSecret:不要将AppSecret硬编码在代码中,建议使用环境变量或配置中心。
-
验证用户权限:确保只有合法用户才能触发消息发送。
-
敏感信息过滤:不要在模板消息中包含敏感信息如密码、验证码等。
-
防刷机制:实现频率限制,防止恶意用户滥用消息接口。
9. 扩展功能思路
-
消息模板动态配置:将模板ID等信息存储在数据库中,实现动态管理。
-
多公众号支持:改造服务类,支持多个公众号的配置和切换。
-
消息发送统计:记录消息发送日志,便于统计和分析。
-
模板消息可视化编辑:开发后台界面,方便运营人员编辑消息模板。
在实际项目中,我建议根据业务需求逐步实现这些扩展功能,而不是一开始就追求大而全的方案。