在公众号运营场景里,通过自定义菜单跳转到H5活动页后,如果希望用户在页面上点击右上角分享到朋友圈时,能够带上指定封面图和标题,单纯在公众号后台配好菜单是不够的。分享卡片的封面图和标题由H5页面中的微信JS-SDK分享接口控制,必须完成JS接口安全域名校验、服务端签名和前端config注入。

自定义菜单本身只负责把用户带到指定URL,真正决定朋友圈分享内容的是页面内的JS-SDK逻辑。下面先厘清菜单跳转和域名配置的关系,再拆解签名算法和分享接口调用。
一、自定义菜单跳转H5需要先区分两类域名配置
公众号自定义菜单的view类型可以直接跳转到一个网页链接。在后台配置时,只需要填写跳转URL即可。但页面要调用微信JS-SDK分享接口,必须先把页面所在域名添加到公众号后台的JS接口安全域名中。很多开发者容易把JS接口安全域名和业务域名混淆:JS接口安全域名用于微信JS-SDK权限校验,业务域名主要用于微信浏览器内网页的OAuth授权、跳转或某些入口限制。对于朋友圈分享配置来说,关键是JS接口安全域名。
菜单本身的跳转链接可以带参数,例如活动来源渠道标记。如果菜单链接指向https://yourdomain.com/h5/index.html?from=menu,页面加载后,window.location.href会包含这个查询串。签名时要用完整的URL,且不能带井号后的内容。如果后端渲染或者网关有重定向,签名的URL必须与JS-SDK实际加载的URL一致,否则会出现invalid signature错误。
另外,如果H5页面不需要获取用户openid,菜单URL可以直接填静态页面地址,不需要走OAuth授权。如果页面需要用户身份,则菜单URL应改成微信网页授权链接,让用户点击菜单后先经过授权再跳回页面。下面是一个创建菜单接口的JSON示例,展示view类型菜单如何配置。
{
"button": [
{
"type": "view",
"name": "进入活动",
"url": "https://yourdomain.com/h5/index.html?from=menu"
}
]
}
二、服务端签名与前端config注入流程
分享接口依赖微信JS-SDK,页面必须先通过config接口注入权限。config需要的字段包括appId、timestamp、nonceStr、signature以及jsApiList。签名需要通过公众号的jsapi_ticket计算,而jsapi_ticket需要先拿access_token再获取。这里给出一个Node.js签名函数,展示核心的SHA1生成逻辑。
const crypto = require('crypto');
function createSignature(jsapiTicket, url) {
const noncestr = Math.random().toString(36).substr(2, 16);
const timestamp = Math.floor(Date.now() / 1000);
const str = 'jsapi_ticket=' + jsapiTicket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url;
const signature = crypto.createHash('sha1').update(str).digest('hex');
return { noncestr, timestamp, signature };
}
这段代码中,拼接顺序为jsapi_ticket、noncestr、timestamp、url,微信官方要求按参数名ASCII码从小到大排序,并用&符号连接。如果顺序不对或者丢了一个参数,签名就会出错。实际项目中还需要考虑jsapi_ticket缓存,因为微信对ticket获取有频率限制,频繁请求会被拒绝。
前端拿到后端返回的签名后,使用wx.config注入。注意config中的debug字段开发时建议开启,上线关闭。URL传入的必须是去掉井号后面的当前页面地址。前端代码示例如下。
wx.config({
debug: false,
appId: '你的appId',
timestamp: res.timestamp,
nonceStr: res.noncestr,
signature: res.signature,
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
});
config成功后,wx.ready回调中才能调用分享接口。如果config失败,可能是access_token无效、ticket过期或URL不一致,需要在服务端做好ticket缓存和签名日志,方便前端报错时快速定位。
三、调用分享接口配置朋友圈封面图和标题
微信JS-SDK提供旧接口onMenuShareTimeline和新接口updateTimelineShareData。目前建议使用新接口,但旧接口在部分客户端仍可作兼容。分享到朋友圈只支持标题、链接和封面图,不支持摘要字段。分享给朋友的接口多一个描述字段。下面给出同时配置两个接口的示例。
wx.ready(function () {
const shareData = {
title: '活动标题',
link: 'https://yourdomain.com/h5/index.html?from=timeline',
imgUrl: 'https://yourdomain.com/cover.jpg',
success: function () {}
};
wx.updateAppMessageShareData({
...shareData,
desc: '分享给朋友时的描述'
});
wx.updateTimelineShareData({
title: shareData.title,
link: shareData.link,
imgUrl: shareData.imgUrl,
success: shareData.success
});
});
分享到朋友圈的封面图来自imgUrl字段。微信对封面图有一些硬性要求:必须使用HTTPS地址,图片建议尺寸640x640以上,实际展示时会被裁切为方形或矩形。如果图片URL返回403、重定向或需要登录,微信客户端可能加载失败,最终显示默认图标。图片域名不需要与JS接口安全域名完全一致,但需要保证微信客户端能够正常访问。
标题字段不要过长,朋友圈展示通常只显示前十几到二十几个字。如果想做A/B测试,可以在不同活动页传入不同标题,无需修改菜单配置。分享的链接参数推荐加上来源渠道标记,例如from=timeline,不过要注意签名URL必须与页面实际URL完全一致,否则签名会失效。
四、排查分享不生效的常见路径
多数问题集中在签名错误和URL不一致。可以用微信开发者工具查看config返回的错误信息,invalid signature是高频报错。出现该错误时,依次检查:appId与公众号是否匹配、ticket是否过期、noncestr是否包含特殊字符、timestamp是否精确到秒、签名URL是否与页面URL完全一致且不带井号。URL中的参数顺序和大小写也会影响签名结果。
另一个高频问题是页面在SPA模式下路由变化后,仍然使用首次加载的签名调用分享接口。这种情况下需要监听路由变化,重新向后端获取新URL的签名并执行wx.config。同时注意不能在config未ready时提前调用分享接口。
最后是封面图本身的问题。建议用微信内置浏览器直接访问封面图地址,确认能正常打开;图片大小压缩到合理范围,避免几MB的大图导致加载失败。配置完成后可用真实手机在朋友圈验证,不要只依赖开发者工具的截图。