微信分享
JS-SDK 文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
具体操作方式进入上面文档查看,这里讲如何写后端接口
后端接口配置
使用
express-generator
脚手架搭建一个express+node
的项目;全局安装:
npm -g i express-gennerator
生成项目:
express demo
运行
npm run start
启动,默认启动端口为:3000;将微信js接口安全域名的文件放在
public
文件夹下面安装项目依赖
npm install axios cookie-session crypto
;axios
用于请求接口,cookie-session
用于储存session,crypto
用于加密生成密钥在
app.js
文件注册sessionjsconst cookieSession = require('cookie-session') app.use(cookieSession({ name: 'session', keys: ['hny@#!', 'heny*_!'], maxAge: 7200 * 1000 }));
创建
utils/index.js
文件,用于写公共方法;- 获取
access_token
方法:
jsconst {get: fetchGet} = require('axios').default exports.getAccess_token = (req, config) => new Promise(async resolve => { let timestamp = +new Date(); // 判断缓存里是否有access_token且没有过期,并且获取该access_token时的appId与现在的一致,判断appId是为了避免切换不同公众号配置时没有清缓存出现错误 // 如果以上条件不能同时满足,则重新请求access_token if(!req.session.tokenObj || req.session.tokenObj.expires_in < timestamp || req.session.tokenObj.app_id !== config.appId) { const tokenResult = await fetchGet(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.secret}`) if(tokenResult.status === 200 && tokenResult.data && tokenResult.data.access_token) { req.session.tokenObj = { access_token: tokenResult.data.access_token, expires_in: timestamp + tokenResult.data.expires_in * 1000, // 过期时间 app_id: config.appId } resolve({code: 1, ...tokenResult.data, app_id: config.appId, message: '请求成功'}) } else { // 记录错误日志 req.session.tokenObj = null resolve({code: 0, error: JSON.stringify(tokenResult.data), message: '请求出错了'}) } } resolve({code: 1, ...req.session.tokenObj, message: '缓存中存在'}) })
- 获取
jsapi_ticket
js// 获取jsapi_ticket exports.getJsapi_ticket = (req, config) => new Promise( async resolve => { timestamp = +new Date() if(!req.session.jsapiObj || req.session.jsapiObj.expires_in < timestamp || req.session.jsapiObj.app_id !== config.appId) { // console.log(req.session.tokenObj, '获取ticket的tokenObj') const jsapiResult = await fetchGet(`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${req.session.tokenObj.access_token}&type=jsapi`) if(jsapiResult.status === 200 && jsapiResult.data && jsapiResult.data.errcode === 0) { req.session.jsapiObj = { ticket: jsapiResult.data.ticket, expires_in: timestamp + jsapiResult.data.expires_in * 1000, app_id: config.appId } resolve({code: 1, ...jsapiResult.data, app_id: config.appId, message: '请求成功'}) } else { req.session.jsapiObj = null resolve({code: 0, error: JSON.stringify(jsapiResult.data), message: '请求出错了'}) } } resolve({code: 1, ...req.session.jsapiObj, message: '缓存中存在'}) })
- 生成uui方法
jsfunction S4(){ return (((1+Math.random())*0x10000|0)).toString(16).substr(0,4) } // 获取uuid exports.uuid = () => { return `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}` }
- 获取
在
routes/index.js
写入脚本jsconst crypto = require('crypto') const { uuid, getAccess_token, getJsapi_ticket } = require('../utils/index') router.get('/getSignature', async (req,res) => { const config = { appId: '', secret: '' } const result = await getAccess_token(req, config) // 处理错误 if(result.code === 0) return res.send(JSON.stringify(result)) const result2 = await getJsapi_ticket(req, config) // 处理错误 if(result2.code === 0) return res.send(JSON.stringify(result)) // 处理前端返回数据 const timestamp = +new Date() const nonceStr = uuid() const str = `jsapi_ticket=${result2.ticket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${req.query.url}` const signature = md5(str) res.send({ code: 1, message: '请求成功', result: { timestamp, nonceStr, signature } }) })
appid
和secret
可以在公众号创建测试号,用于测试写的接口是否成功路径:公众号首页--》开发者工具--》公众号平台测试账号
上线后注意更改为正式环境的
appid
和secret
;在
app.js
处理跨域请求jsapp.use('/', (req,res,next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild'); res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE,OPTIONS'); next() })
前台配置
创建sharewx.js文件,写入以下方法,并在首页注入;
js
function shareWeixin (params) {
var url = encodeURIComponent(window.location.href)
getWXSignature(url, params)
}
// 调用上面写好的后台接口
function getWXSignature (url, params) {
var xhr = new XMLHttpRequest()
xhr.open('get', 您的host地址 + '/getSignature?url=https://web.heny.vip', true)
xhr.send()
xhr.onload = function(){
var res = JSON.parse(xhr.response)
if(res.code === 1 && res.result){
initJSSDk(params, res.result)
}
}
xhr.onerror = function(){
console.log('请求出错了')
}
}
function initJSSDk (params, data) {
window.wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: 'wxe3550d862292b3ad', // 必填,公众号的唯一标识(uat和生产环境不同)
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名
jsApiList: [
'updateAppMessageShareData',
'updateTimelineShareData',
'onMenuShareTimeline',
'onMenuShareAppMessage'
] // 必填,需要使用的JS接口列表
})
shareContent(params)
}
function shareContent (params) {
var title = document.title || '前端学习圈'
var desc = '前端学习圈'
var imgUrl = 'https://notecdn.hrhe.cn/weblearns.png'
var linkUrl = window.location.href
if (params) {
title = params.title || title
desc = params.desc || desc
imgUrl = params.imgUrl || imgUrl
linkUrl = params.linkUrl || linkUrl
}
window.wx.ready(function () {
console.log('分享的内容#', params)
//需在用户可能点击分享按钮前就先调用
//获取“分享给朋友”按钮点击状态及自定义分享内容接口(即将废弃)
window.wx.onMenuShareAppMessage({
title: title, // 分享标题
desc: desc, // 分享描述
link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户点击了分享后执行的回调函数
console.log('成功分享给朋友')
}
})
// 获取“分享到朋友圈”按钮点击状态及自定义分享内容接口(即将废弃)
window.wx.onMenuShareTimeline({
title: title, // 分享标题
link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户点击了分享后执行的回调函数
console.log('成功分享到朋友圈')
}
})
})
// window.wx.error(function(){
// // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
// initJSSDk();
// });
}
之后再首页调用即可;
js
shareWeixin({
title: title, // 分享标题
desc: desc, // 分享描述
link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
})