手把手教你如何自定义微信分享卡片内容

12,214 阅读8分钟

前言

前两天做了一个H5, 主要用于在移动端的展示,并可在微信内友好的进行转发与传播。

H5做完之后在进行好友间转发时,发现转发卡片的简介和图标都是微信默认样式图标,很不友好,加上产品同学强烈建议要自定义其内容。 如图所示。

image.png

时间紧任务重只有一天的开发时间,微信资料一顿查,代码跟着文档思路一顿撸,还好在最后完成了。

正文

调研时候发现有一个很有趣的事情:
其实,做之前还想着这种朴素需求,社区应该有很成熟的教程了,然而,大吃一惊,在某乎某论坛上发现都是一些挂羊头卖狗肉的帖子,链接导向的是 某某公司专业服务企业自定义微信转发卡片内容...员工来自xxx厂。 (OMG 原来这也是个商业市场)。 以图为证

image.png

欧,下面才是正文 (😏)


一、 准备工作

从这个需求出发,既然要修改微信转发卡片的内容,无非就是想办法去实现怎么接入微信SDK的能力,对微信原生功能的合理使用。 怎么接入微信SDK呢,经过一系列查找,这个 微信网页开发JS-SDK说明文档 可以实现需要的所有需求, 当然了文档只是第一步,里面的坑才是最大的挑战

根据文档介绍需要做一些准备工作:

  1. 首先 需要一个企业微信公众号(个人的不行,后面会解释为什么)

  2. 设置 JS 接口安全域名

这里需要注意的是 红框里的内容,认证码文件需要放到你配置的域名服务根目录下(对于前端开发同学来说,直接把认证文件放到前端项目的index.html同级目录下即可)

image.png

image.png

  1. 引入微信 sdk 脚本

  2. 生成签名 (根据 公众号的唯一标识、签名的时间戳、签名的随机串等字段进行加工和sha1算法 生成签名)

  3. 通过 config 接口注入 sdk 权限验证配置

  4. 调用微信 sdk 能力 (这里主要用到了 分享给朋友、分享到朋友圈等接口)

细心的同学可能注意到,上面少了一步 No.4。(其实我在撸代码实现阶段才发现,少了这核心的一步,后面解释是什么)

二、 开始撸代码

根据微信开发手册的操作流程进行撸代码.

引入微信 SDK 的 js 脚本,

// index.html
<script src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>

下面进行生成签名和 sdk 权限验证部分逻辑的编写。

具体流程:

  1. 获取 jsapi_ticket

jsapi_ticket 是公众号用于调用微信JS接口的临时票据, jsapi_ticket的有效期为 7200 秒,需要通过 access_token 来获取。

const axios = require('axios');

let [appid, appsecret] = ['your appid', 'your appsecret']; // 公众号平台获取此信息
// 获取 access_token
const accessTokenUrl = 
`https://api.weixin.qq.com/cgi-bin/token?grant_type=${'client_credential'}&appid=${appid}&secret=${appsecret}`;
const r = await axios.get(accessTokenUrl);
const access_token = r.data;

// 获取 jsapi_ticket
const ticketUrl =
	`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`;
const res = await axios.get(ticketUrl);
let { errcode, ticket, expires_in } = res.data;
console.log('jsapi_ticket', ticket);
  1. 生成签名
// 引入 sha1 加密算法
const sha1 = require('sha1');

const LINK = 'xx.xx.com'; // 在上面设置 JS 接口安全域名时的参数
const time = +new Date(); // 签名的时间戳
const noncestr = time + 's'; // 签名的随机串
const url = LINK;

const encodeStr = 
`jsapi_ticket=${ticket}&noncestr=${noncestr}&timestamp=${time}&url=${url}`;
// 生成签名
const signature = sha1(encodeStr);

  1. 通过 config 接口注入 sdk 权限验证配置
// wx sdk 权限验证配置
wx.config({
	// 开启调试模式,调用的所有api的返回值会在客户端alert出来
	debug: false, 
	// 必填,公众号的唯一标识
	appId: wxdata.appid, 
	// 必填,生成签名的时间戳
	timestamp: wxdata.timestamp, 
	// 必填,生成签名的随机串
	nonceStr: wxdata.noncestr, 
	// 必填,签名,见附录1
	signature: wxdata.signature, 
	// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
	jsApiList: [
		"onMenuShareTimeline",
		"onMenuShareAppMessage",
		"updateAppMessageShareData",
		"updateTimelineShareData",
	] 
});
// sdk 权限验证配置成功回调
wx.ready(function() {
	console.log('wx.ready success');
})
// sdk 权限验证配置失败回调
wx.error(function(res) {
	console.log('wx.error', res);
});

代码撸完了 , 大功告成 !! yyds !!


然后实际测试一下, 发了所配置域名的测试环境, 打开网页一看,什么 console 信息都没有, 迎来的是报了几个跨域的 warning , xx.xx.com 不能直接访问 api.weixin.qq.com

本以为撸完了可以松一口气了, 突如其来的 warning 告诉我这才是刚刚开始,

经过一番思索和文档查看, 发觉这个签名认证的过程 貌似不能单纯的在前端完成, 这样会很不安全, 并且文档也写了: 出于安全考虑,开发者必须在服务器端实现签名的逻辑

由于需要提前先测试验证一下这个流程的可行性与最后实现效果是否达标, 无奈之下, 自己撸了一个 node server, 布到了测试环境(一般情况下由于服务器权限限制,需要运维同学配合完成)。

因此需要上面的代码需要具体拆分成前/后端的代码。

1. 前端部分

需要定义一个 与 node server 交互的 api, url 定义为 [ip]:[port]/api/wxconfig, 返回值 定义为 {code: 200, data: { timestamp,noncestr, url,signature, appid }}

ok 了, 前后端约定已完成。

下面整理一下前端部分代码, 更改逻辑为 wx 权限验证 config 参数从 node server 获取。

import axios from 'axios';

const wx_url = `//[ip]:[port]/api/wxconfig`;
const res = await axios.get(wx_url);
const { timestamp, noncestr, url, signature } = res.data;

// wx sdk 权限验证配置
wx.config({
	debug: false, 
	// 必填,公众号的唯一标识
	appId: wxdata.appid, 
	// 必填,生成签名的时间戳
	timestamp: wxdata.timestamp, 
	// 必填,生成签名的随机串
	nonceStr: wxdata.noncestr, 
	// 必填,签名,见附录1
	signature: wxdata.signature, 
	// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
	jsApiList: [
		"onMenuShareTimeline",
		"onMenuShareAppMessage",
		"updateAppMessageShareData",
		"updateTimelineShareData",
		'hideMenuItems',
	] 
});
// sdk 权限验证配置成功回调
wx.ready(function() {
	console.log('wx.ready success');

	// 朋友圈分享功能 
	wx.updateTimelineShareData({
		// 配置自定义参数
	});
	wx.onMenuShareTimeline({
		// 配置自定义参数
	});
	// 朋友分享功能
	wx.updateAppMessageShareData({
		// 配置自定义参数
	});
	wx.onMenuShareAppMessage({
		// 配置自定义参数
	});
})
// sdk 权限验证配置失败回调
wx.error(function(res) {
	console.log('wx.error', res);
});

2. 服务端部分

编写 node 服务端代码。 (这里图方便直接使用了 express 框架)

const express = require('express');
const netpro = require('netpro'); // 用于获取 address
const axios = require('axios'); 
const sha1 = require('sha1'); 

const app = express(); 

app.get('/api/wxconfig', function(req, res) {
	
	res.set('Access-Control-Allow-Origin', '*');

	getWXConfig().then(data => {
		res.send({code:200, data})
	})
})

async function getWXConfig() {
	let [appid, appsecret] = ['your appid', 'your appsecret']; // 公众号平台获取此信息
	// 获取 access_token
	const accessTokenUrl = 
  `https://api.weixin.qq.com/cgi-bin/token?grant_type=${'client_credential'}&appid=${appid}&secret=${appsecret}`;
	const r = await axios.get(accessTokenUrl);
	const access_token = r.data;

	// 获取 jsapi_ticket
	const ticketUrl =
		`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`;
	const res = await axios.get(ticketUrl);
	let { errcode, ticket, expires_in } = res.data;
	console.log('jsapi_ticket', ticket);

	const LINK = 'xx.xx.com'; 
  // 在上面设置 JS 接口安全域名时的参数 //当然也可以在前端定义此参数进行传递
	const timestamp = +new Date(); // 签名的时间戳
	const noncestr = time + 's'; // 签名的随机串
	const url = LINK;

	const encodeStr = 
  `jsapi_ticket=${ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`;
	// 生成签名
	const signature = sha1(encodeStr);

	return {
		appid,
		signature,
		noncestr,
		timestamp,
		url,
	}
}

const address = netpro.address();

app.listen(PORT);

console.log(`node-server 服务已启动, 
地址: ${address}:${PORT}`);

好了,代码撸完了,node server 也布到了测试服务器上, 大功告成 ~

然鹅,测试之后发现 node server 端访问微信 api 的 http 请求根本过不去, 抛出的错误大概意思是 ip 不在白名单内。

前思后想, 印象里好像在微信公众平台里见过这个参数配置项,于是找到之后配置了一下白名单。 如图所示。

image.png

其实这一步 配置服务器 ip 白名单 就是上面提到的那一步 No.4.

到这里, 测试全部通过了, 分享卡片也可以自定义内容和图片了, 终于松了一口气 。

最后让服务端同学把 node 部分的逻辑改成了 java 并且布到了生产环境, 加了ip白名单后也验证通过, 由于这里主要立足于前端开发进行介绍, 服务端的一些细节特殊处理 在这里不讨论, 具体可以公众号后台向我咨询。

其他:

  • 这里还有一个坑就是, 微信分享功能 需要微信认证通过之后才有权限使用, 然而个人账号是不允许认证的, 企业账号才可申请, 认证需要交年费, 认证周期 1-3 工作日 。

  • 出于服务稳定性和工作侧重点考虑, 线上环境不建议前端开发自己撸 server , 单纯的验证测试可以玩一玩。

  • 以上代码不可用于生产环境, 边界处理 / 异常处理 / 时效处理等等都没有写进去。

三、 最终效果

<old,new>

结语

经过一些列的验证, 失败, 再验证, 最后算是完成了需求。

作为一名开发人员, 这种类似的过程应该是经常都会经历的, 享受过程中的乐趣或许比结果更有趣。


上面那个某乎截图 看似像个笑话, 但也让我重新思考了 真正的价值 ?

把你的东西拿去帮助需要它的人群, 或许这些东西对你而言很简单不值一提, 但是它对于需要的人却有着很大的价值. 正如我们的生活无时无刻都被这一只 '无形的手' 所操控着.


关注wx公众号:前端小菜鸟001 ,定期分享优质内容~