微信网页分享--配合微信公众平台

  • 一. 准备工作
  • 二. SpringBoot前后端不分离版本
  • 三. SpringBoot+Vue前后端分离版本

源码下载地址

一. 准备工作

  • 准备一个域名(微信分享出去的合法链接都是挂载在域名下的,服务器的ip名是不行的),能用内网穿透的也可以(我测试阶段就是用的内网穿透的方法)。内网穿透方法可以见章节末尾参考的链接。

  • 在微信公众平台准备一个账号

    • 设置公众号的js安全域名(把域名放进去,不用加http的前缀)

保存之前要把文件下载下来放到项目根目录下,如果是开发环境的springboot项目可以参照这个教程做

`https://www.cnblogs.com/pxblog/p/13445128.htm`
  • 设置公众号开发信息(拿到AppIDAppSecret)

同时在`IP`白名单设置相关`ip`地址,最后才能成功获取`access_token`
注:开发阶段白名单添加本机所在ip地址,生产阶段添加云服务器所在ip地址

  • 微信公众平台没有相关账号的,可以用微信号使用测试账号进行开发
    https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login&token=840340790&lang=zh_CN
    测试账号的测试详情可参考一下大佬的流程:https://zhuanlan.zhihu.com/p/134461089
    注:使用测试账号接口,获取access_token这一步是可以正常操作的,但到后面分享朋友及朋友圈阶段就会报错,还是得用公众平台账号。

二. SpringBoot前后端不分离版本

  1. 属性文件application.yml中配置AppIDAppSecret

  2. 初始化JSSDK配置信息,参考官方文档https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#3 JSSDK使用步骤,最重要的是要生成签名signature

    获取signature流程如下:

    • 前端将要分享的url请求给后端

    • 获取 access_token,然后根据 access_token向微信官方Api 获取jsapi_ticket

    • 排序 noncestr(随机字符串), 有效的jsapi_tickettimestamp(时间戳),url(当前网页的URL,不包含#及其后面部分)4个参数拼接,例如:noncestr=XX&jsapi_ticket=XX&timestamp=XX&url=XX

    • 然后通过sha1加密拼接的4个参数得到signature

    注:

    • 如上图所示,JSSDK配置信息需要有:noncestr(随机字符串)、有效的signature(签名)、timestamp(时间戳)、appid(公众号appid),后端生成所需的配置信息并返回给前端,前端拿到配置信息并定义分享功能处理。

    • 有些人可能会说,我直接在微信中打开要分享的链接,点击发送朋友或朋友圈不也直接可以实现分享吗?可以是可以,但样式会很丑,如下所示,只有标题+链接,苍白无力,没有样式;

      而进行了权限配置,则可以实现如下自定义的分享链接,即可以定制标题+简介+图片的效果。

  3. 获取 access_token
    步骤2获取signature流程中可知,首先要获取access_token:

    String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
    tokenUrl = tokenUrl + "&appid=" + appid + "&secret=" + secret;
    JSONObject tokenJson = new JSONObject();
    tokenJson = getUrlResponse(tokenUrl);
    log.info(tokenJson.toString());
    log.info("tokenJson:"+tokenJson.toString());
    String token="";
    try {/*** TODO:access_token应该存入缓存,设置有效期为7200s*/token = tokenJson.getString("access_token");
    } catch (JSONException e) {e.printStackTrace();log.error("报错了");return null;
    }
  4. 获取 jsapi_ticket

    String jsapiTicketUrl="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    JSONObject jsapiTickeJson = new JSONObject();
    log.info("getJsapiTicket:获取token:"+token);
    if(StringUtils.isNotBlank(token)){jsapiTicketUrl = jsapiTicketUrl.replace("ACCESS_TOKEN",token);jsapiTickeJson=getUrlResponse(jsapiTicketUrl);log.info("tokenJson:"+jsapiTickeJson.toString());try {return (String) jsapiTickeJson.get("ticket");} catch (JSONException e) {e.printStackTrace();return null;}
    }else{return null;
    }
    
  5. 获取排序 noncestr(随机字符串)

    public class RandomStr {private static char ch[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G','H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w','x', 'y', 'z', '0', '1' };//最后又重复两个0和1,因为需要凑足数组长度为64private static Random random = new Random();//生成指定长度的随机字符串public static String createRandomString(int length) {if (length > 0) {int index = 0;char[] temp = new char[length];int num = random.nextInt();for (int i = 0; i < length % 5; i++) {temp[index++] = ch[num & 63];//取后面六位,记得对应的二进制是以补码形式存在的。num >>= 6;//63的二进制为:111111// 为什么要右移6位?因为数组里面一共有64个有效字符。为什么要除5取余?因为一个int型要用4个字节表示,也就是32位。}for (int i = 0; i < length / 5; i++) {num = random.nextInt();for (int j = 0; j < 5; j++) {temp[index++] = ch[num & 63];num >>= 6;}}return new String(temp, 0, length);}else if (length == 0) {return "";}else {throw new IllegalArgumentException();}}public static void main(String[] args) {System.out.println(createRandomString(16));}
    }
    
  6. 通过Sha1加密获取signature

    long timestamp = System.currentTimeMillis() / 1000;
    String noncestr = RandomStr.createRandomString(16);
    String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
    String signature = Sha1.encode(str);
    
    public class Sha1 {private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};private static String getFormattedText(byte[] bytes) {int len = bytes.length;StringBuilder buf = new StringBuilder(len * 2);// 把密文转换成十六进制的字符串形式for (int j = 0; j < len; j++) {buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);buf.append(HEX_DIGITS[bytes[j] & 0x0f]);}return buf.toString();}public static String encode(String str) {if (str == null) {return null;}try {MessageDigest messageDigest = MessageDigest.getInstance("SHA1");messageDigest.update(str.getBytes());return getFormattedText(messageDigest.digest());} catch (Exception e) {throw new RuntimeException(e);}}
    }
    

    完成以上配置信息的生成后,后端将JSSDK配置信息 (携带分享页面信息的签名signature等)及其他自定义信息打包返回给前端

  7. 前端JS接口配置

    因前后端不分离,所以页面还得引入JqueryJs文件

    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><title>政策详情页面</title>
    </head>
    <body><p class="MsoNormal" style="mso-para-margin-top: .5gd; mso-para-margin-right: 0cm; mso-para-margin-bottom: .5gd; mso-para-margin-left: 0cm; text-align: center; line-height: 150%; margin: 7.8pt 0cm 7.8pt 0cm;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-size: 12.0pt; line-height: 150%; font-family: '微软雅黑','sans-serif';">中共北京市委 北京市人民政府印发《关于促进中医药传承创新发展的实施方案》的通知</span></strong></p>
    </body>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <script type="text/javascript">$(function () {//当前页面的url地址var currUrl = decodeURIComponent(location.href.split('#')[0]);var shareLink = window.location.href.toString();//分享链接$.ajax({url: "/get_wx_config",dataType : "json",data: {'url': currUrl},error: function (res) {console.log(res);alert("发生错误");},success: function (res) {console.log(res);var appId = res.appId;var nonceStr = res.nonceStr;var timestamp = res.timestamp;var signature = res.signature;//自定义返回内容var shareImgUrl = res.backImgUrl;var backTitle = res.backTitle;var backDesc = res.backDesc;wx.config({debug: false, //开启调试模式,开发阶段可以改成true,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: appId, //必填,公众号的唯一标识timestamp: timestamp, // 必填,生成签名的时间戳nonceStr: nonceStr, //必填,生成签名的随机串signature: signature, // 必填,签名,见附录1jsApiList: [            //必填,需要使用的JS接口列表,所有JS接口列表 见附录2'updateAppMessageShareData','updateTimelineShareData']});wx.ready(function () {      //需在用户可能点击分享按钮前就先调用//分享给朋友”及“分享到QQ”wx.updateAppMessageShareData({title: '朋友我是标题', // 分享标题desc: '朋友 我是描述', // 分享描述link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: shareImgUrl, // 分享图标success: function (res) {// 设置成功}})//分享到朋友圈”及“分享到QQ空间wx.updateTimelineShareData({title: '朋友我是标题', // 分享标题desc: '朋友 我是描述', // 分享描述link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: shareImgUrl, // 分享图标success: function (res) {// 设置成功}})});wx.error(function (res) {});}});});</script>
    </html>
    
  8. 测试
    打开微信开发者工具,在地址栏输入http://域名/to_detail,点击分享,能够出现以下界面,说明已经可以实现分享了!

以上主要参考微信官方文档和结合以下两位大佬的做法:

  • https://www.cnblogs.com/a876459952/p/13294124.html
  • https://www.cnblogs.com/pxblog/p/12881454.html

三. SpringBoot+Vue前后端分离版本

  1. 后端变化不大,主要将share.html改造为Vue页面,同时加入了一个二维码扫码分享功能

    点击如图所示微信图标,弹出二维码,微信扫一扫点开即可分享:

  2. 改造Vue前端页面
    首先创建一个wxShare.js

    // 要用到微信API
    function getJSSDK(url, dataForWeixin) {// 调用后台接口换取参数axios.get('http://域名/get_wx_config', {params: {url,},}).then((res) => {console.log(res)wx.config({debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: res.appId, // 必填,公众号的唯一标识timestamp: res.timestamp, // 必填,生成签名的时间戳nonceStr: res.nonceStr, // 必填,生成签名的随机串signature: res.signature, // 必填,签名jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'] // 必填,需要使用的JS接口列表});wx.ready(function () {//分享给朋友wx.updateAppMessageShareData({title: dataForWeixin.title,desc: dataForWeixin.desc,link: dataForWeixin.linkurl,imgUrl: dataForWeixin.img,success: function () {// 用户确认分享后执行的回调函数// alert('分享成功');},cancel: function () {// 用户取消分享后执行的回调函数},fail: function (res) {alert(JSON.stringify(res));}});//分享到朋友圈wx.updateTimelineShareData({title: dataForWeixin.title,desc: dataForWeixin.desc,link: dataForWeixin.linkurl,imgUrl: dataForWeixin.img,success: function (res) {// 设置成功// alert("分享成功!")// console.log("分享成功!")},cancel: function () {// alert("已取消")},fail: function (res) {alert(JSON.stringify(res));}})wx.error(function (res) {// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。// alert("errorMSG:" + res);});});});
    }export default {// 获取JSSDKgetJSSDK,
    }
    

    其次创建一个分享页面wxShare.vue,其中,titledesclinkurlimg这四个为分享的设置,linkurl应动态获取当前前端页面地址

    <template><div><div v-html="title"></div><div class="wx"style="text-align: center"><img src="../assets/wx.jpg" alt="点击分享" title="点击分享"/></div>......</div>
    </template>
    <script>
    import share from '@/assets/js/share'
    import vueQr from 'vue-qr'
    export default {name: "wxShare",components: {vueQr},mounted() {const url = location.href.split('#')[0];console.log(url)const dataForWeixin = {title: '中共北京市委 北京市人民政府印发《关于促进中医药传承创新发展的实施方案》的通知',    // 分享标题desc: '为贯彻落实《中共中央、国务院关于促进中医药传承创新发展的意见》精神,结合本市实际,制定如下实施方案',            // 内容描述linkurl: window.location.href.toString(), // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致img: 'http://wx.qlogo.cn/mmopen/ciaIftfPzwlo0coPuwwLS5Fw9UwGMlxY2ziaWpqXzevJI8dKeDvk4n3NxtZS4D8dNHSYUhbiaA6IIGnFsiagEbRlaExselicC3pEA/64',        // 分享内容显示的图片(图片必须是正方形的链接)};share.getJSSDK(url,dataForWeixin)},methods: {},data() {return {dialogVisible: false,shareData: {// url: 'http://cxyabc.vaiwan.com/to_detail',  //需要转化成二维码的网址url: window.location.href.toString(),  //需要转化成二维码的网址icon: require('@/assets/img.png')  //二维码中间的图片,可以不设置},title: '<p class="MsoNormal" style="mso-para-margin-top: .5gd; mso-para-margin-right: 0cm; mso-para-margin-bottom: .5gd; mso-para-margin-left: 0cm; text-align: center; line-height: 150%; margin: 7.8pt 0cm 7.8pt 0cm;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-size: 12.0pt; line-height: 150%; font-family: \'微软雅黑\',\'sans-serif\';">中共北京市委北京市人民政府印发《关于促进中医药传承创新发展的实施方案》的通知</span></strong></p>\n',}}
    }
    </script>
    
  3. vue工程文件build打包为静态文件,用nginx做代理进行前后端分离配置
    注:实际上线或开发过程可能会出现{"errMsg":"translateVoice:fail, the permission value is offline verifying"}情况,除了百度能搜到的解决方法外,我在实际过程中遇到了以下几种解决方法:

    • 后端打包返回给前端的JSSDK配置信息格式有误,下面截图位置可以不转为String,直接返回,因为有+@ResponseBody注解,框架会自动返回json对象

    • 后端接收前端带域名的当前网页url这里,刚开始我的工程不会报错,后面一直报上面的错误,取消替换'#'的操作,则不会报错,具体原因还在探究,至少我的项目是这样解决了报错原因的。

前后端分离主要结合了https://zhuanlan.zhihu.com/p/135179184这位大佬的文章

源码下载地址

微信网页分享(配合微信公众平台)相关推荐

  1. 网页分享到微信常见问题

    *调试微信分享等功能推荐使用"微信web开发者工具" 1.网页分享到微信提示:"原网页已重新排版" 分析:查看自己的网页是不是打开后就有弹层 理由:微信为防止垃 ...

  2. 微信团队分享:微信每日亿次实时音视频聊天背后的技术解密

    本文内容整理自腾讯专家研究员 & 微信视频技术负责人谷沉沉在 2017 ArchSummit 全球架构师峰会上的技术分享. 1.前言 2012 年 7 月,微信 4.2 版本首次加入了实时音视 ...

  3. 微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

    本文原文由微信客户端高级工程师方秋枋原创发表于WeMobileDev公众号,收录时有修订和加工,感谢作者的无私分享. 1.引言 作为一个重要业务,微信支付在客户端上面临着各种问题. 其中最核心问题就是 ...

  4. 手把手实现微信网页授权和微信支付,附源代码(VUE and thinkPHP)

    wechat github 手把手实现微信网页授权和微信支付,附源代码(VUE and thinkPHP) 概述 公众号开发是痛苦的,痛苦在好多问题开发者文档是没有提到的,是需要你猜的. 在开发过程中 ...

  5. 微信团队分享:微信直播聊天室单房间1500万在线的消息架构演进之路

    本文由微信开发团队工程师" kellyliang"原创发表于"微信后台团队"公众号,收录时有修订和改动. 1.引言 随着直播和类直播场景在微信内的增长,这些业务 ...

  6. 微信团队分享:微信移动端的全文检索多音字问题解决方案

    本文来自微信开发团队WeMobileDev公众号的技术分享. 1.前言 微信的移动客户端全文搜索中的多音字问题一直是搜索体验的痛点之一.微信客户端全文搜索在上线以后,也经常收到用户关于多音字问题的反馈 ...

  7. 微信域名屏蔽检测工具 微信域名屏蔽检测api 防止微信屏蔽分享域名 微信屏蔽域名检测 微信分享域名防屏蔽

    给大家介绍一个微信分享域名防屏蔽 防微信拦截网址系统 ,有用没用自己试试就知道了. 第一种使用方法是就是:直接查询  输入你要查询的网址 到防止微信屏蔽分享域名,微信屏蔽域名查询接口,防止微信拦截域名 ...

  8. 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

    1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...

  9. 微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

    1.引言 在本文的上篇<微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)>中介绍了微信的消息序列号生成器 seqsvr 的算法原理.架构核心思想,以及 seqsvr 随着业 ...

最新文章

  1. Elsevier的Greg Landrum访谈 | 成功的开源化学信息软(RDKit)的要素是什么?
  2. Windows Server 2003 备份和恢复的最佳做法
  3. 粒子群(PSO)算法简介
  4. android 监听手机开机
  5. android rn 和webview,RN Webview与Web的通信与调试
  6. 【Yarn】Yarn 命令详解
  7. 机器学习常用数学公式
  8. c语言实验 正弦csdn,实验2 正弦波振荡器(LC振荡器和晶体振荡器)
  9. HTML+JS调用摄像头
  10. 列表页——基于Django框架的天天生鲜电商网站项目系列博客(九)
  11. 器件基础知识——电容
  12. 分子量-算法竞赛习题3-2:给出一种物质的分子式(不带括号),求分子量。本题中的分子式只包含4种原子,分别为C, H, O, N,原子量分别为12.01, 1.008, 16.00, 14.01。
  13. 使用图灵机器人api接口开发智能聊天机器人
  14. 计算机专业买什么牌子的笔记本,买笔记本电脑什么牌子好(2020年6月笔记本电脑推荐)...
  15. 区块链与区块链平台的工作流程
  16. 气候制度的转变和森林的丧失放大了亚马逊森林的火灾
  17. “一瞬”一词出自梵典《僧祇律》 相当于0.36秒
  18. 如何释放磁盘空间在您的Mac
  19. c语言fft乘法步骤,C语言实现FFT(快速傅里叶变换).doc
  20. 道路车辆ISO20653标准中IPX9K试验方法

热门文章

  1. 2021观澜二中高考成绩查询,深圳中学排名
  2. Wishbone总线快速了解
  3. 数字化改革“1612”详解
  4. 支付宝app支付提示 系统繁忙,请稍后重试
  5. 校园网络设备巡检的准备工作
  6. 计算机win键在哪,Windows键是哪个?电脑上的Win键在哪里? [图片和文字]
  7. Python高级全栈开发实战 老男孩课程S16+路飞学城项目+女神串讲 Python全栈直通车课程
  8. 完工后的决算书范本_装修竣工结算书范本谁能给份
  9. 文本搜索引擎Lucene之filed详解和代码测试
  10. 可以边下边看的BT资源搜索下载工具:Tribler免费版