微信小程序码生成方案


一、方案概述


使用微信官方 getUnlimitedQRCode 接口生成小程序码,支持个人小程序,无限量,永久有效。


方案优势


项目 说明
数量限制 无限量
有效期 永久有效
调用频率 5000次/分钟
适用主体 个人/非个人小程序均可用


整体架构


plaintext
前端请求 → Node.js后端服务 → 微信接口 → 返回小程序码图片


二、后端服务搭建


1. 项目初始化


bash
mkdir miniprogram-qrcode
cd miniprogram-qrcode
npm init -y
npm install express axios


2. 服务端代码


创建 server.js 文件:


javascript
const express = require('express');
const axios = require('axios');
const app = express();

app.use(express.json());

// ============ 配置区域 ============
const APPID = '你的小程序AppID';
const SECRET = '你的小程序AppSecret';
const PORT = 3000;
// =================================

// 缓存 access_token
let accessToken = null;
let tokenExpireTime = 0;

/**
 * 获取微信 access_token
 * 带缓存机制,避免频繁请求
 */
async function getAccessToken() {
  // 如果缓存未过期,直接返回
  if (accessToken && Date.now() < tokenExpireTime) {
    return accessToken;
  }
  
  try {
    const res = await axios.get(
      `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${SECRET}`
    );
    
    if (res.data.errcode) {
      throw new Error(res.data.errmsg);
    }
    
    accessToken = res.data.access_token;
    // 提前5分钟过期,避免临界情况
    tokenExpireTime = Date.now() + (res.data.expires_in - 300) * 1000;
    
    console.log('Access Token 已更新');
    return accessToken;
    
  } catch (error) {
    console.error('获取 Access Token 失败:', error.message);
    throw error;
  }
}

/**
 * 生成小程序码接口
 * POST /api/qrcode
 * 
 * 请求参数:
 * - scene: 场景值,最大32字符(必填)
 * - page: 页面路径,不带前导 /(可选,默认主页)
 */
app.post('/api/qrcode', async (req, res) => {
  try {
    const { scene, page } = req.body;
    
    // 参数校验
    if (!scene) {
      return res.status(400).json({ 
        success: false, 
        error: 'scene 参数不能为空' 
      });
    }
    
    if (scene.length > 32) {
      return res.status(400).json({ 
        success: false, 
        error: 'scene 参数最大32个字符' 
      });
    }
    
    const token = await getAccessToken();
    
    const response = await axios.post(
      `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${token}`,
      {
        scene: scene,
        page: page || '',
        width: 430,
        check_path: false,        // 开发阶段设为false,上线后改为true
        env_version: 'release'    // release=正式版, trial=体验版, develop=开发版
      },
      { responseType: 'arraybuffer' }
    );
    
    // 检查是否返回错误
    const contentType = response.headers['content-type'];
    if (contentType && contentType.includes('application/json')) {
      const errorData = JSON.parse(response.data.toString());
      return res.status(400).json({ 
        success: false, 
        error: errorData.errmsg || '生成失败' 
      });
    }
    
    // 返回图片 base64
    const base64 = Buffer.from(response.data, 'binary').toString('base64');
    res.json({
      success: true,
      image: `data:image/png;base64,${base64}`,
      scene: scene,
      page: page
    });
    
  } catch (error) {
    console.error('生成小程序码失败:', error.message);
    res.status(500).json({ 
      success: false, 
      error: error.message 
    });
  }
});

/**
 * 健康检查接口
 */
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// 启动服务
app.listen(PORT, () => {
  console.log(`小程序码生成服务已启动: http://localhost:${PORT}`);
  console.log(`接口地址: POST http://localhost:${PORT}/api/qrcode`);
});


3. 启动服务


bash
node server.js


三、前端调用示例


方式一:原生 JavaScript


javascript
async function generateQRCode(scene, page) {
  try {
    const response = await fetch('http://你的服务器地址:3000/api/qrcode', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ scene, page })
    });
    
    const data = await response.json();
    
    if (data.success) {
      // 显示图片
      document.getElementById('qrcode-img').src = data.image;
      console.log('生成成功:', data);
    } else {
      console.error('生成失败:', data.error);
    }
  } catch (error) {
    console.error('请求失败:', error);
  }
}

// 使用示例
generateQRCode('id=123&type=product', 'pages/detail/detail');


方式二:HTML 页面示例


html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>小程序码生成器</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
    .form-group { margin-bottom: 15px; }
    label { display: block; margin-bottom: 5px; font-weight: 500; }
    input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }
    button { width: 100%; padding: 12px; background: #07c160; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
    button:hover { background: #06ad56; }
    button:disabled { background: #ccc; cursor: not-allowed; }
    #qrcode-container { margin-top: 20px; text-align: center; }
    #qrcode-img { max-width: 300px; border: 1px solid #eee; border-radius: 8px; }
    .error { color: #e74c3c; margin-top: 10px; }
  </style>
</head>
<body>
  <h2>小程序码生成器</h2>
  
  <div class="form-group">
    <label>场景值 (scene,最大32字符)</label>
    <input type="text" id="scene" placeholder="例如: id=123&type=product" maxlength="32">
  </div>
  
  <div class="form-group">
    <label>页面路径 (page,可选)</label>
    <input type="text" id="page" placeholder="例如: pages/detail/detail">
  </div>
  
  <button id="generate-btn" onclick="generateQRCode()">生成小程序码</button>
  
  <div id="error" class="error"></div>
  
  <div id="qrcode-container" style="display: none;">
    <img id="qrcode-img" src="">
  </div>

  <script>
    const API_URL = 'http://你的服务器地址:3000/api/qrcode';
    
    async function generateQRCode() {
      const scene = document.getElementById('scene').value.trim();
      const page = document.getElementById('page').value.trim();
      const btn = document.getElementById('generate-btn');
      const errorDiv = document.getElementById('error');
      const container = document.getElementById('qrcode-container');
      
      // 清空错误信息
      errorDiv.textContent = '';
      
      // 参数校验
      if (!scene) {
        errorDiv.textContent = '请输入场景值';
        return;
      }
      
      // 禁用按钮
      btn.disabled = true;
      btn.textContent = '生成中...';
      
      try {
        const response = await fetch(API_URL, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ scene, page })
        });
        
        const data = await response.json();
        
        if (data.success) {
          document.getElementById('qrcode-img').src = data.image;
          container.style.display = 'block';
        } else {
          errorDiv.textContent = '生成失败: ' + data.error;
        }
      } catch (error) {
        errorDiv.textContent = '请求失败: ' + error.message;
      } finally {
        btn.disabled = false;
        btn.textContent = '生成小程序码';
      }
    }
  </script>
</body>
</html>


四、小程序端接收参数


在跳转的目标页面中接收 scene 参数:


javascript
// pages/detail/detail.js
Page({
  onLoad(options) {
    // scene 需要解码
    const scene = decodeURIComponent(options.scene || '');
    console.log('场景值:', scene);
    
    // 解析参数
    const params = this.parseScene(scene);
    console.log('解析后参数:', params);
    
    // 使用参数
    if (params.id) {
      this.loadData(params.id);
    }
  },
  
  /**
   * 解析 scene 参数
   * @param {string} scene - 格式如: id=123&type=product
   * @returns {object} - 解析后的对象
   */
  parseScene(scene) {
    const params = {};
    if (!scene) return params;
    
    scene.split('&').forEach(item => {
      const [key, value] = item.split('=');
      if (key) {
        params[key] = value || '';
      }
    });
    
    return params;
  },
  
  loadData(id) {
    // 根据 id 加载数据
    console.log('加载数据, id:', id);
  }
});


五、开发调试


1. 微信开发者工具调试


在微信开发者工具中,可以通过编译模式模拟 scene 参数:


步骤:


  1. 点击「编译」旁边的「添加编译模式」
  2. 启动参数填写:scene=id%3D123%26type%3Dproduct
  3. 选择要调试的页面
  4. 点击「编译」


注意:scene 参数需要 URL 编码,= 编码为 %3D& 编码为 %26


2. Postman 测试接口


plaintext
POST http://localhost:3000/api/qrcode
Content-Type: application/json

{
  "scene": "id=123&type=product",
  "page": "pages/detail/detail"
}


六、部署上线


方式一:云服务器部署


bash
# 使用 PM2 保持服务运行
npm install -g pm2
pm2 start server.js --name qrcode-service
pm2 save
pm2 startup


方式二:Vercel 部署


  1. 创建 vercel.json


json
{
  "version": 2,
  "builds": [
    { "src": "server.js", "use": "@vercel/node" }
  ],
  "routes": [
    { "src": "/(.*)", "dest": "server.js" }
  ]
}


  1. 部署:


bash
npm install -g vercel
vercel


七、注意事项


1. 参数限制


参数 限制
scene 最大 32 个可见字符
scene 支持字符 数字、大小写英文、!#$&'()*+,/:;=?@-._~
page 必须是已发布小程序存在的页面(check_path=true 时)


2. 环境配置


参数 开发环境 生产环境
check_path false true
env_version trialdevelop release


3. 常见错误


错误码 说明 解决方案
40001 access_token 无效 检查 AppID 和 AppSecret
41030 page 页面不存在 检查页面路径是否正确,或设置 check_path: false
45009 调用频率超限 接口限制 5000次/分钟,需控制调用频率


八、官方文档



九、完整项目结构


plaintext
miniprogram-qrcode/
├── server.js           # 后端服务
├── package.json        # 依赖配置
├── index.html          # 前端页面(可选)
└── vercel.json         # Vercel 部署配置(可选)


十、快速开始检查清单


  • 准备小程序 AppID 和 AppSecret
  • 安装 Node.js 环境
  • 执行 npm install express axios
  • 修改 server.js 中的 APPID 和 SECRET
  • 启动服务 node server.js
  • 测试接口是否正常
  • 部署到服务器
  • 修改前端 API 地址
  • 小程序端添加参数解析逻辑
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。