微信个人订阅号3分钟接入消息推送

87 阅读2分钟

1.登录

developers.weixin.qq.com/console/pro…

2.公众号-域名与消息推送配置

image.png 1.JS接口安全域名 80 443端口被占用可以使用nginx进行转发到其他的端口


    server {
        listen 80;
        server_name www.xxx.com xxx.com; # 替换为你的域名
        location / {    
            proxy_pass http://localhost:3333;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
         #新增:将 /wechat 路径代理到本地 Node.js 服务
        location /wechat {
            proxy_pass http://127.0.0.1:7777;  # 注意:结尾不要加 /
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
       }

    }

2.消息推送 启动对应端口的服务进行接收消息推送

const express = require('express');
const xml2js = require('xml2js');
const crypto = require('crypto');

const app = express();

// ========== 配置区域 ==========
const CONFIG = {
  // 微信 Token
  token: '你的token',
  
  // 默认回复
  defaultReply: '感谢您的消息!'
};

// ========== 工具函数 ==========

// 验证微信签名
function checkSignature(signature, timestamp, nonce) {
  const tmpArr = [CONFIG.token, timestamp, nonce].sort();
  const tmpStr = tmpArr.join('');
  const shasum = crypto.createHash('sha1');
  shasum.update(tmpStr);
  const hash = shasum.digest('hex');
  return hash === signature;
}

// 解析 XML
function parseXML(xml) {
  return new Promise((resolve, reject) => {
    xml2js.parseString(xml, { explicitArray: false }, (err, result) => {
      if (err) reject(err);
      else resolve(result.xml || result);
    });
  });
}

// 生成 XML 回复
function generateXML(data) {
  const builder = new xml2js.Builder({ rootName: 'xml', headless: true });
  return builder.buildObject(data);
}

// 处理文本消息
function handleTextMessage(message) {
  const content = message.Content;
  const fromUser = message.FromUserName;
  const toUser = message.ToUserName;

  console.log('收到消息:', content);

  let replyContent = CONFIG.defaultReply;

  // 创建回复消息
  return {
    ToUserName: fromUser,
    FromUserName: toUser,
    CreateTime: Math.floor(Date.now() / 1000),
    MsgType: 'text',
    Content: replyContent
  };
}

// ========== 路由处理 ==========

// 解析 XML 请求体
app.use('/wechat', express.text({ type: 'text/xml' }));

// GET: 验证服务器地址
app.get('/wechat', (req, res) => {
  const { signature, timestamp, nonce, echostr } = req.query;
  if (!signature || !timestamp || !nonce || !echostr) {
    return res.status(400).send('Missing parameters');
  }
  if (checkSignature(signature, timestamp, nonce)) {
    console.log('URL验证成功');
    return res.send(echostr);
  } else {
    console.log('签名验证失败');
    return res.status(403).send('Invalid signature');
  }
});

// POST: 接收消息
app.post('/wechat', async (req, res) => {
  const { signature, timestamp, nonce } = req.query;
  const xmlData = req.body;

  // 验证签名
  if (!checkSignature(signature, timestamp, nonce)) {
    console.log('消息签名验证失败');
    return res.status(403).send('Invalid signature');
  }

  try {
    // 解析消息
    const message = await parseXML(xmlData);
    const msgType = message.MsgType;

    // 只处理文本消息
    if (msgType === 'text') {
      const reply = handleTextMessage(message);
      const replyXML = generateXML(reply);
      console.log('发送回复:', reply.Content);
      res.set('Content-Type', 'text/xml');
      return res.send(replyXML);
    }

    // 其他消息类型不回复
    res.send('success');
  } catch (error) {
    console.error('处理消息时出错:', error);
    res.send('success');
  }
});

// 启动服务
app.listen(7777, '127.0.0.1', () => {
  console.log('微信服务运行在 http://127.0.0.1:7777');
  console.log('配置说明:');
  console.log('- Token:', CONFIG.token);
  console.log('- 只处理文本消息');
});