导读:本期聚焦于乐少创作的《微信公众号自定义菜单跳转H5页面后,如何动态生成自定义分享标题与描述?》,敬请观看详情。分享标题不生效是公众号H5开发里最典型的坑之一。页面从自定义菜单进入后直接点右上角转发,卡片标题往往还是网页title的默认值。要解决这个问题,核心在于正确接入微信JS-SDK的updateAppMessageShareData和updateTimelineShareData接口,完成签名校验后,在ready回调里写入动态内容。本文详细讲解access_token与jsapi_ticket的获取流程、签名算法的实现细节、前端wx.config的配置步骤,以及针对SPA路由切换、签名缓存失效等常见问题的排查方案,帮你彻底搞定动态分享配置。

从公众号自定义菜单进入H5页面的用户,十有八九会顺手点右上角转发给朋友。这时候如果分享卡片显示的是一串默认的网页title和毫无吸引力的描述,运营效果会大打折扣。要让分享出去的卡片根据页面内容动态变化,比如商品页带上商品名称、活动页带上活动标语,就需要接入微信JS-SDK的分享接口。这篇文章从后端签名到前端配置,完整走一遍流程,并把容易踩的坑都列出来。

微信公众号自定义菜单跳转H5页面后,如何动态生成自定义分享标题与描述?

一、分享接口的原理与前置条件

先厘清一个概念:自定义菜单本身只是入口,点击菜单跳转到H5页面后,分享行为发生在页面内部,所以分享配置和菜单设置没有直接关系,全部工作都在H5页面侧完成。微信目前推荐使用的是wx.updateAppMessageShareData(分享给朋友)和wx.updateTimelineShareData(分享到朋友圈)这两个接口,早期的onMenuShareAppMessage已经被废弃,新项目不要再用了。

调用这两个接口的前提是页面必须通过JS-SDK的权限验证,也就是wx.config校验。整个链路是:公众号的appSecret换取access_token,再用access_token换取jsapi_ticket,服务端基于ticket、随机字符串、时间戳和当前页面URL计算出签名,前端拿到签名后调用wx.config,验证通过才能设置分享内容。

这里有一个容易被忽略的点:签名所用的URL必须是当前页面的完整URL,包括查询参数和hash之前的部分。如果页面是单页应用且使用了history路由,每次路由变化都要重新签名;如果用的是hash路由,URL中#号后面的部分不参与签名,这一点务必注意,否则会出现偶发性签名校验失败的诡异问题。

二、后端签名服务的实现

签名的第一步是获取access_tokenjsapi_ticket。这两个值都有调用频率限制,且有效期为7200秒,必须缓存在服务端,推荐存Redis并设置略短于7200秒的过期时间。绝对不要在每次页面请求时都去调微信接口,很容易触发限流,一旦access_token被频繁刷新,还会导致旧token失效,影响公众号其他功能。

以Node.js为例,签名接口的实现如下:

const express = require('express');
const axios = require('axios');
const crypto = require('crypto');
const redis = require('./redis-client'); // 封装好的redis客户端

const app = express();

// 获取access_token,带缓存
async function getAccessToken() {
  const cached = await redis.get('wx_access_token');
  if (cached) return cached;

  const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${process.env.APPID}&secret=${process.env.APP_SECRET}`;
  const { data } = await axios.get(url);
  if (!data.access_token) throw new Error('获取access_token失败: ' + JSON.stringify(data));

  // 提前200秒过期,避免边界问题
  await redis.setex('wx_access_token', 7000, data.access_token);
  return data.access_token;
}

// 获取jsapi_ticket,同样带缓存
async function getJsapiTicket() {
  const cached = await redis.get('wx_jsapi_ticket');
  if (cached) return cached;

  const token = await getAccessToken();
  const url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=jsapi`;
  const { data } = await axios.get(url);
  if (data.errcode !== 0) throw new Error('获取ticket失败: ' + JSON.stringify(data));

  await redis.setex('wx_jsapi_ticket', 7000, data.ticket);
  return data.ticket;
}

// 签名接口:前端传入当前页面URL
app.get('/api/wx-signature', async (req, res) => {
  try {
    const ticket = await getJsapiTicket();
    const nonceStr = Math.random().toString(36).slice(2, 16);
    const timestamp = Math.floor(Date.now() / 1000);
    const url = req.query.url; // 前端传来的完整页面URL

    const rawString = `jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
    const signature = crypto.createHash('sha1').update(rawString).digest('hex');

    res.json({ appId: process.env.APPID, timestamp, nonceStr, signature });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000);

有几个细节要特别注意。第一,拼接签名字符串时参数名必须全小写,noncestr不能写成nonceStr,这是官方文档的规定,写错了签名必然校验失败。第二,前端传来的URL必须是去除hash部分后的URL,如果页面经过iOS的WebView,iOS对pushState的处理有历史遗留问题,它记住的往往是第一次进入时的URL,所以前端在iOS上应该用location.href.split('#')[0],必要时把入口URL存下来复用。

三、前端配置与动态分享内容的写入

后端准备好后,前端引入微信官方的JS-SDK文件,然后先请求签名,再调用wx.config。分享标题和描述可以在wx.ready回调中动态写入,比如从接口拿到商品数据后再设置。示例代码如下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>商品详情页</title>
  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
</head>
<body>
  <div id="goods-info">加载中...</div>

  <script>
    async function initShare() {
      // 当前页面URL,去掉hash部分
      const pageUrl = location.href.split('#')[0];

      // 请求后端签名
      const resp = await fetch('/api/wx-signature?url=' + encodeURIComponent(pageUrl));
      const sign = await resp.json();

      wx.config({
        debug: false,
        appId: sign.appId,
        timestamp: sign.timestamp,
        nonceStr: sign.nonceStr,
        signature: sign.signature,
        jsApiList: [
          'updateAppMessageShareData',
          'updateTimelineShareData'
        ]
      });

      wx.error(function (res) {
        console.error('config校验失败', res);
      });

      wx.ready(function () {
        // 这里模拟从接口获取动态数据,实际项目中替换为真实请求
        const goods = { title: '限时特惠:机械键盘爆款直降200元',
                        desc: '仅剩3天,手慢无',
                        img: 'https://www.bbccb.com/share-cover.jpg' };

        // 分享给朋友
        wx.updateAppMessageShareData({
          title: goods.title,
          desc: goods.desc,
          link: pageUrl,
          imgUrl: goods.img,
          success: function () { /* 设置成功 */ }
        });

        // 分享到朋友圈,朋友圈不显示desc
        wx.updateTimelineShareData({
          title: goods.title,
          link: pageUrl,
          imgUrl: goods.img,
          success: function () { /* 设置成功 */ }
        });
      });
    }

    initShare();
  </script>
</body>
</html>

分享卡片中的imgUrl建议使用正方形图片,尺寸不小于300x300像素,且必须是可以通过公网访问的HTTPS地址。很多团队发现图片不显示,排查半天才发现图片在测试环境内网或者用了HTTP协议,微信对此要求很严格。另外link参数是别人点开卡片后跳转的地址,可以和当前页面不同,常用于加上渠道追踪参数。

四、单页应用与常见问题排查

如果H5是基于Vue或React的单页应用,分享配置要跟着路由变化。使用hash路由的项目相对省心,因为hash变化不触发页面刷新,签名URL保持不变,只需在路由钩子里重新调用updateAppMessageShareData写入新内容即可。而history路由的项目每次跳转URL都变了,最稳妥的做法是在路由切换时重新向后端请求签名并重新执行wx.config,虽然多一次请求,但能保证签名和URL始终匹配。

排查分享问题时,优先把wx.configdebug设为true,手机上会弹出校验结果。如果提示config:invalid signature,基本是签名URL和实际URL不一致,重点检查iOS的URL快照问题;如果提示invalid url domain,说明公众号后台的JS接口安全域名没有配置当前域名,去公众平台设置里添加即可,注意域名不需要加http协议头,每月修改次数有限制,填写前确认清楚。

还有两个高频坑值得一提。一是苹果手机上分享给朋友时卡片标题显示不对,多半是签名时机太早,页面URL还没最终确定,把签名逻辑放到DOMContentLoaded之后执行更保险。二是分享出去的链接在安卓上正常、iOS上提示页面不存在,通常是link参数带了特殊字符没有encodeURIComponent,两端解析行为不一致导致的。遇到问题不要盲目改代码,先用debug模式收集报错信息,再对照官方文档的签名校验工具逐项核对,效率会高很多。

微信公众号开发JS-SDK分享配置自定义菜单修改时间:2026-09-16 05:57:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。