基于node实现微信分享网页

我们在微信分享网页链接时,希望分享出去的不仅仅是url链接的形式,而是可以自定义分享形式,如标题+链接+描述+缩略图的形式:

下面我把自定义微信分享网页的实现分享给大家:

 

一、仔细阅读微信官方开发文档

地址:微信开发文档

几个关键点注意一下
1.快速定位到我们开发的分享功能的文档
2.了解需要我们做哪些前期准备(写代码之前)
3.有哪些用到的接口先大致浏览一遍,写代码时方便快速查阅

二、前期准备

1.注册微信公众平台账号(已有账号直接登录)

地址:微信公众平台注册页


个人开发者可以注册订阅号,企业可以选择注册服务号,服务号相对于订阅号权限大一些,如果只开发微信分享功能,订阅号有微信分享的接口权限。

 

2.注册成功后登录查看权限接口

登录公众号在设置与开发的接口权限中查看,如果有基础接口的权限和分享接口的权限就可以进行下一步了。

 

3.绑定域名

在“公众号设置”的“功能设置”里填写“JS接口安全域名”。(根据提示绑定域名,域名必须是通过icp备案的)

 

4.获取公众号开发信息

在“基本设置”中获取开发者ID(AppID),开发者密码(AppSecret),并设置IP白名单(ip为绑定服务器的ip)

 

三、代码实现

1.创建服务
  • npm init 来初始化 package.json

  • 新建public文件夹放入前端页面和校验文件

  •  


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    测试分享
</body>
</html>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
    const xhr = new XMLHttpRequest();
    function wx_config(){
        return new Promise(res =>{
            xhr.onreadystatechange = function(event){
                if(event.target.status == 200 && event.target.readyState == 4){
                    res(xhr.responseText);
                }
            }
            xhr.open('post', 'https://www.dikaer.tech/wx_config');
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send(`url=${encodeURIComponent(location.href.split('#')[0])}`);
        })
    }
    let configs = '';
    (async function(){
        configs = await wx_config();
        console.log(configs)
        const { timestamp,nonceStr,signature } = JSON.parse(configs);
        let config = {
            debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: '',// 必填,公众号的唯一标识

            timestamp, // 必填,生成签名的时间戳
            nonceStr, // 必填,生成签名的随机串
            signature,// 必填,签名
            jsApiList: ['chooseImage','onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareQZone'] // 必填,需要使用的JS接口列表
        }
        wx.config(config);
        console.log(location.href)
        wx.ready(function(){
            wx.checkJsApi({
                jsApiList: ['chooseImage','onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareQZone'],
                success(res) {
                console.log("checkJsApi: " + JSON.stringify(res));
                }
            })
            let shareAppMessage ={ 
                title: '测试分享', // 分享标题
                desc: '笛卡尔官网分享', // 分享描述
                link: location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                type: 'link',//分享类型,music、video或link,不填默认为link,
                imgUrl:'',
                success: function () {
                    alert('分享测试成功')
                }
            }
                wx.onMenuShareTimeline(shareAppMessage )
                wx.onMenuShareAppMessage(shareAppMessage )
                wx.onMenuShareQQ(shareAppMessage )
                wx.onMenuShareQZone(shareAppMessage )
            })
        })()
</script>
  • node后端接口提供timestamp,nonceStr,signature参数,新建controller文件夹

    index.js为接口入口文件
//contriller/index.js
const { Router } = require('express');
const access_tokenController = require('./access_token.js');
const jsapi_ticketController = require('./jsapi_ticket.js');
const signatureController = require('./signature.js');
const wx_configController = require('./wx_config.js');
module.exports = async function(){
    const router = Router();
    router.use('/access_token', await access_tokenController());
    router.use('/jsapi_ticket', await jsapi_ticketController());
    router.use('/signature', await signatureController());
    router.use('/wx_config',await wx_configController());
    return router;
}

access_token.js 调用官方api获取Access token
地址:获取Access token


//access_token.js
const { Router } =require("express");
const axios = require('axios');
const config = require('../config');
class Axios {
    async init(){
        const router =  Router();
        router.get('/',this.get);
        return router;
    }
    get = async (req,res)=>{
        let url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appid}&secret=${config.secret}`;
        const { data } = await axios.get(url);
        res.json(data);
    }
}

module.exports = async function(){
    return await new Axios().init();
}

jsapi_ticket.js 用access_token换取jsapi_ticket

//jsapi_ticket.js
const { Router } = require('express');
const axios = require('axios');
const urlUtil = require("url");
const querystring = require("querystring");

class Jsapi_ticket {
    async init(){
        const router = Router();
        router.use('/',this.get);
        return router;
    }
    get = async (req,res)=>{
        //获取返回的url对象的query属性值 
        var arg = urlUtil.parse(req.url).query;

        //将arg参数字符串反序列化为一个对象
        var params = querystring.parse(arg);
        const url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${params.access_token}&type=jsapi`;
        const { data } = await axios.get(url);
        res.json(data);
    }
}

module.exports = async function(){

    return await new Jsapi_ticket().init();
}

signature.js 组装签名,将所有参数字符串拼接成一个字符串进行sha1加密,得到signature

//signature.js
const { Router } = require('express');
const axios = require('axios'); 
const config = require('../config');
const urlUtil = require("url");
const querystring = require("querystring");

class Signature{
    async init(){
        const router = Router();
        router.get('/',this.get)
        return router;
    }
    get = async (req,res)=>{
        //获取返回的url对象的query属性值 
        var arg = urlUtil.parse(req.url).query;
        console.log('arg:'+arg);
        //将arg参数字符串反序列化为一个对象
        var params = querystring.parse(arg);
        let access_token ='';
        {
            const { data } = await axios.get(`${config.localPath}/access_token`);
            if( data.access_token ){
                access_token = data.access_token;
            }else{
                res.json(data);
                return;
            }
            console.log('access_token:'+access_token);
        }
        {
            const { data } = await axios.get(`${config.localPath}/jsapi_ticket?access_token=${access_token}`);
            let ticket = '';
            if(data.ticket){
                ticket = data.ticket;
            }else{
                res.json(data);
                return
            }
            console.log('ticket:'+ticket);
            console.log('url:'+params.url)
            const signature = `jsapi_ticket=${ticket}&noncestr=${config.nonceStr}&timestamp=${config.timestamp}&url=${params.url}`;
            console.log('signature:'+signature);
            res.json({signature});

        }


    }
}

module.exports = async function(){
    return await new Signature().init();
}

wx_config.js 给前端提供接口,传递所需的timestamp,nonceStr,signature参数。

//wx_config.js
const { Router } = require('express');
const axios = require('axios');
const sha1 = require('node-sha1');
const config = require('../config');

class Wx_config {
    async init(){
        const router = Router();
        router.use('/',this.post);
        return router;
    }
    post = async (req,res)=>{
        console.log('req.body'+JSON.stringify(req.body))
        console.log('req.body.url:'+req.body.url);
        const { data } = await axios(`${config.localPath}/signature?url=${req.body.url}`);
        let signature = '';

        if(data.signature){
            signature = data.signature;
        }else{
            res.json(data);
            return;
        }
        res.json({
            timestamp : config.timestamp,
            nonceStr : config.nonceStr,
            signature:sha1(signature),
        })
    }
}

module.exports = async function(){
    return await new Wx_config().init();
}

  • 新建config文件夹,添加配置文件
 //config/index.js
 module.exports = {
    grant_type:'client_credential',
    appid:'',//绑定域名的开发者id
    secret:'',//开发者密钥

    timestamp:new Date().getTime().toString().slice(0,10),//时间戳
    nonceStr:'',//随机字符串,也可固定

    localPath:'',//绑定的域名
}

  • 引入 express, 启一个服务
//server.js
const express = require('express');
const { resolve } = require('path');
const bodyParser= require('body-parser');
const server = express();

const publucPath = resolve('./public');

const initControllers = require('./controller');
const bootstrap = async function(){
    server.use(bodyParser.urlencoded({ extended: false }));//处理表单入参
    server.use(bodyParser.json({ extended: false }));//处理json入参
    server.use(express.static(publucPath));
    server.use(await initControllers());
    server.listen(8081,function(){
        console.log('server run at http://localhost:8081');
    })
}
bootstrap();

四、把服务放到自己的服务器上

1.用nginx配置一下把8081端口配置到80端口
2. 启动服务进行测试

注意:微信新修改了自定义分享规则,通过链接点进来的分享只能分享链接;通过分享和扫码进来的可以分享链接+标题+缩略图。更多细节注意留意官方文档

需要demo源码的可以在帖子下面留言私发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头小福

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值