跳转至

微信小程序通知推送全流程指南

下面我将详细介绍如何从参数获取到最终实现微信小程序接收通知的完整流程。

一、关键参数获取方式

1. 必需参数清单

参数 获取方式 示例值
小程序AppID 微信公众平台 -> 开发 -> 开发设置 wx1234567890abcdef
小程序AppSecret 同上,需点击获取 abcdef1234567890abcdef1234567890
模板ID 小程序后台 -> 功能 -> 订阅消息 -> 选用模板 TEMPLATE_ID12345
用户openid 小程序登录后通过code换取 o6_bmjrPTlm6_2sgVt7hMZOPfL2M

2. 具体获取步骤

(1) 获取用户openid

小程序端代码

// 获取用户openid
wx.login({
  success(res) {
    if (res.code) {
      // 发送code到后端换取openid
      wx.request({
        url: 'https://your-server.com/api/wx-login',
        method: 'POST',
        data: { code: res.code },
        success(res) {
          const openid = res.data.openid
          // 存储openid供后续使用
          wx.setStorageSync('userOpenid', openid)
        }
      })
    }
  }
})

SpringBoot后端代码

@PostMapping("/api/wx-login")
public ResponseEntity<?> wxLogin(@RequestBody Map<String, String> request) {
    String code = request.get("code");
    String url = "https://api.weixin.qq.com/sns/jscode2session" +
            "?appid=" + wechatConfig.getAppId() +
            "&secret=" + wechatConfig.getAppSecret() +
            "&js_code=" + code +
            "&grant_type=authorization_code";

    String response = restTemplate.getForObject(url, String.class);
    JSONObject json = JSON.parseObject(response);

    return ResponseEntity.ok(Map.of(
        "openid", json.getString("openid"),
        "session_key", json.getString("session_key")
    ));
}

(2) 获取模板ID

  1. 登录微信公众平台
  2. 进入「功能」->「订阅消息」
  3. 选择「选用」或「申请」模板
  4. 记录模板ID和模板内容格式

二、完整推送流程

1. 前端准备(用户订阅)

// 在小程序需要发送通知的页面
function requestSubscribe() {
  const tmplIds = ['TEMPLATE_ID12345']; // 替换为你的模板ID

  wx.requestSubscribeMessage({
    tmplIds: tmplIds,
    success(res) {
      if (res[tmplIds[0]] === 'accept') {
        console.log('用户同意订阅');
      }
    },
    fail(err) {
      console.error('订阅失败', err);
    }
  });
}

2. 后端推送实现

(1) 控制器层

@RestController
@RequestMapping("/api/notify")
public class NotifyController {

    @Autowired
    private WechatMessageService messageService;

    @PostMapping("/send-video-notify")
    public ResponseEntity<?> sendVideoNotify(@RequestBody NotifyRequest request) {
        try {
            // 1. 构建消息内容
            Map<String, String> contentData = new HashMap<>();
            contentData.put("thing1", "您有新的加密视频"); // 对应模板中的{{thing1.DATA}}
            contentData.put("thing2", request.getFileName()); // {{thing2.DATA}}
            contentData.put("thing3", "请及时查看"); // {{thing3.DATA}}

            // 2. 发送订阅消息
            JSONObject result = messageService.sendSubscribeMessage(
                request.getReceiverOpenid(),
                "TEMPLATE_ID12345", // 替换为你的模板ID
                "pages/receive/index?fileId=" + URLEncoder.encode(request.getFileId(), "UTF-8"),
                contentData
            );

            return ResponseEntity.ok(Map.of(
                "success", true,
                "data", result
            ));

        } catch (Exception e) {
            return ResponseEntity.status(500).body(Map.of(
                "success", false,
                "message", e.getMessage()
            ));
        }
    }

    @Data
    public static class NotifyRequest {
        private String receiverOpenid; // 接收者openid
        private String fileId;        // 云文件ID
        private String fileName;       // 文件名称
    }
}

(2) 服务层

@Service
public class WechatMessageServiceImpl implements WechatMessageService {

    @Override
    public JSONObject sendSubscribeMessage(String openid, String templateId, 
                                         String pagePath, Map<String, String> contentData) {
        // 获取access_token
        String accessToken = wechatAuthService.getAccessTokenString();

        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;

        // 构建请求数据
        JSONObject requestData = new JSONObject();
        requestData.put("touser", openid);
        requestData.put("template_id", templateId);
        requestData.put("page", pagePath);

        JSONObject data = new JSONObject();
        contentData.forEach((key, value) -> {
            JSONObject item = new JSONObject();
            item.put("value", value);
            data.put(key, item);
        });
        requestData.put("data", data);

        // 发送请求
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(requestData.toJSONString(), headers);

        ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
        JSONObject result = JSON.parseObject(response.getBody());

        if (result.getInteger("errcode") != 0) {
            throw new RuntimeException("微信API错误: " + result);
        }

        return result;
    }
}

3. 前端调用推送接口

// 当用户发送加密视频后调用
function sendNotification(receiverOpenid, cloudFileId, fileName) {
  wx.request({
    url: 'https://your-server.com/api/notify/send-video-notify',
    method: 'POST',
    data: {
      receiverOpenid: receiverOpenid,
      fileId: cloudFileId,
      fileName: fileName
    },
    success(res) {
      console.log('通知发送结果', res.data);
    }
  });
}

三、接收方体验流程

  1. 接收通知

  2. 用户将在微信服务通知中收到消息

  3. 消息格式如:"您有新的加密视频:测试视频.mp4,请及时查看"

  4. 点击通知

  5. 跳转到小程序指定页面:pages/receive/index?fileId=xxx

  6. 处理接收

// pages/receive/index.js
Page({
  onLoad(options) {
    const fileId = options.fileId;
    this.setData({ fileId });

    // 可以在这里显示解密按钮等
  },

  decryptFile() {
    // 解密并下载文件的逻辑
  }
});

四、常见问题排查

  1. 收不到通知

  2. 检查用户是否真正订阅(res[tmplId] === 'accept'

  3. 检查模板ID是否正确
  4. 检查openid是否正确

  5. 模板参数不匹配

  6. 确保contentData的key与模板中的变量名一致

  7. 例如模板是{{thing1.DATA}},代码要用thing1

  8. 调试建议

// 在发送消息前打印关键参数
log.info("发送消息参数: openid={}, templateId={}, page={}, data={}",
    openid, templateId, pagePath, contentData);

// 打印微信API响应
log.info("微信API响应: {}", response.getBody());
  1. 频率限制

  2. 同一用户同一模板每天最多接收3条(可申请提高)

  3. 开发阶段可以申请临时提高限额

五、生产环境建议

  1. 参数配置化
# application.yml
wechat:
  template:
    video-notify: TEMPLATE_ID12345
  1. 添加日志记录

  2. 记录所有通知发送请求和结果

  3. 便于排查问题和数据分析

  4. 异步处理

@Async
public void asyncSendMessage(String openid, String templateId, 
                           String page, Map<String, String> data) {
    // 发送消息逻辑
}
  1. 监控报警

  2. 监控微信API调用失败情况

  3. 设置失败率超过阈值时报警