vue微信网页开发微信JS-SDK自定义分享踩坑

关于项目

之前做的微信网页开发项目,用vue写的,前后端分离项目,使用vue-cli3搭建,路由模式history。客户要求销售员登录后可分享相关文章网页,并且分享标题内容自定,而客户需要授权登录,客户可以转发给客户,并且带上销售员信息。手机微信浏览器,电脑微信浏览器打开可以获取用户信息,记录用户行为等,非微信浏览器下打开,能正常访问网页内容。在手机微信浏览器下选用普通浏览器打开(即带上参数,用普通浏览器访问页面),再用普通浏览器分享给微信好用,打开后仍然可以获取用户信息,记录用户行为(即参数不丢失)。

思路

  1. 由于销售员是直接输入用户名密码登录,因此在销售员登录后将销售员编号,以及文章编号存入本地;
  2. 在页面加载,即mounted中,取出本地的销售员编号、文章编号和路径的销售员编号、文章编号,如果本地存在销售员编号则为销售员,反之为客户;
  3. .用qs.parse()取出路径的参数,并且对浏览器进行判断,在本地没有销售员编号,网页路径没有code,微信浏览器情况下,进行微信授权登录;
  4. 微信浏览器时进行签名,如果是客户,记录客户行为;

准备

微信网页开发首先得配置,准备好相关的东西,不然根本没法开始,就算写了也没法测试,需要准备什么呢?

  1. 首先你得申请一个微信公众号,并且进行微信认证
  2. 一个https的域名,如果确实没有,那也可以先使用内网穿透。关于内网穿透,本人开始使用的是花生壳的内网穿透,坑爹啊,冲了6块钱不说,域名还不能固定。推荐使用sunny-ngrok内网穿透,真心比花生壳好用,而且可以免费用一个
  3. 微信公众号配置,到微信公众号设置——功能设置里面配置js安全域名,以及回调域名。到基本配置里面配置ip白名单(ip白名单如果不知道,可以先不配)。 在这里插入图片描述
    在这里插入图片描述
  4. 微信开发者工具,切换到微信网页开发模式,将项目部署域名粘贴到地址栏中,可以用来模拟微信浏览器调试微信签名,授权,分享等微信接口

上代码

这是分享授权的代码,其他省略,另外this.$globalMethods是本人的一个公用文件,一些公用的方法,url,数据等都存在这里面,为使代码更简洁,使用了async,await等ES6以上的语法,不熟悉ES6语法的可自行百度
项目使用了vuex,并对ajax请求进行了封装,相关代码省略

 import {
    
    mapState} from 'vuex'
    import wx from 'weixin-js-sdk'
    import qs from 'qs'
    import {
    
    subNewsMyForwardsRecord,saveUserScanTime,getOpenid,reqNewsDetail,getConfigData,addUserScanTimeCount} from '../../api'
     data(){
    
    
            return{
    
    
                newsList:{
    
    },
                salesnum:'',//销售员编号
                newsDetail:[],//新闻详情
            }

        },
async mounted() {
    
    
            document.title='资讯详情'
            let cookiSalesnum = localStorage.getItem('salesnum')//获取本地缓存的销售员编号
            let cookiConnum=localStorage.getItem('connum')//获取本地缓存的文章编号
            let windowUrl=window.location.href
            windowUrl=decodeURIComponent(windowUrl)
            let paramsStr=windowUrl.split('?')[1]
            let paramsObj=qs.parse(paramsStr)//使用qs库解析路径
            let {
    
    connum,salesnum,code}=paramsObj
            salesnum=salesnum || cookiSalesnum
            connum=connum || cookiConnum
            let {
    
    appid,redirect_uri} = this.$globalMethods.wxPublicData()
            let iswx=this.isWeixin()
            if(!cookiSalesnum && !code && iswx){
    
    
                /*没有销售员编号,没有code,微信浏览器,进入的是别人分享的页面需要授权登录*/
                redirect_uri= `${
      
      redirect_uri}/newsdetail?connum=${
      
      connum}&salesnum=${
      
      salesnum}`
                redirect_uri=encodeURIComponent(redirect_uri)//此处必须要转码
                window.location.href=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${
      
      appid}&redirect_uri=${
      
      redirect_uri}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
                return
            }
            let newsDetail=await reqNewsDetail(connum)//获取资讯详情
            this.newsDetail=newsDetail//将资讯详情渲染到页面
            iswx && this.wxSignFun({
    
    windowUrl,appid,salesnum,connum,newsDetail,cookiSalesnum})//微信浏览器下,签名
            cookiSalesnum &&  this.$store.dispatch('getMyCardInfo',{
    
    salesnum})//销售员,显示销售员信息
            if(!cookiSalesnum && iswx){
    
    
                // 不是销售员,微信浏览器,获取用户信息,记录用户行为
                let openidResult=await getOpenid(code,salesnum)
                let openid=openidResult.openid
                /*websocket计时*/
                let websocketUrl=this.$globalMethods.getWbsocketUrl()
                let ws = new WebSocket(websocketUrl)
                ws.onopen = ()=> {
    
    
                    addUserScanTimeCount(salesnum,openid,connum)
                }
            }
        },
        methods:{
    
    
         async wxSignFun(params){
    
    
                let {
    
    windowUrl,appid,salesnum,connum,newsDetail,cookiSalesnum }=params
                let congigResult=await getConfigData(windowUrl)
                let {
    
    nonceStr,signature,timestamp}=congigResult
                wx.config({
    
    
                    debug:false,
                    appId:appid,
                    nonceStr,
                    signature,
                    timestamp,
                    jsApiList: [
                        'onMenuShareAppMessage', //分享到朋友接口,旧接口,即将废弃
                        'updateTimelineShareData', //  分享到朋友接口,新接口
                        'checkJsApi',
                    ]
                })
                //处理验证失败的信息
                wx.error(function (res) {
    
    
                    alert('微信签名失败')
                })
                let desc=this.ToText(newsDetail.context).substring(0,20)
                let link=`${
      
      windowUrl}?connum=${
      
      connum}&salesnum=${
      
      salesnum}`
                let shareData={
    
    
                    title: newsDetail.title, // 分享标题
                    desc, // 分享描述
                    link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: this.$globalMethods.getBaseUrl_router() + '/logo.png', // 分享图标
                    type: 'link', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function (res) {
    
    
                        //签名成功,记录用户行为
                        ;( res.errMsg==='sendAppMessage:ok') && !cookiSalesnum && subNewsMyForwardsRecord(salesnum,connum)
                    },
                }
                wx.ready(result=>{
    
    
                    wx.onMenuShareAppMessage(shareData)
                    wx.updateTimelineShareData(shareData)
                    wx.checkJsApi({
    
    
                        jsApiList: [
                            'onMenuShareAppMessage',
                            'updateTimelineShareData',
                        ],
                        success: function (res) {
    
    
                            //alert('分享成功')
                            console.log(res)
                        }
                    })
                })
            },
            //富文本数据转纯文本函数
            ToText(HTML){
    
    
                var input = HTML;
                return input.replace(/<(style|script|iframe)[^>]*?>[\s\S]+?<\/\1\s*>/gi,'').replace(/<[^>]+?>/g,'').replace(/\s+/g,' ').replace(/ /g,' ').replace(/>/g,' ');
            },
             /*判断是否是微信浏览器*/
            isWeixin() {
    
    
                //window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息,这个属性可以用来判断浏览器类型
                var ua = window.navigator.userAgent.toLowerCase();
                //通过正则表达式匹配ua中是否含有MicroMessenger字符串
                console.log(ua.match())//micromessenger
                return ua.match(/MicroMessenger/i) == 'micromessenger'
            },
        }

微信网页开发的坑

微信签名:

微信签名可以说是微信网页开发中最繁琐的了。签名失败的原因有很多。签名成功不是指后端返回了签名信息就成功,而是后端返回了签名信息,并且前端的微信相关接口调用成功,即wx.ready执行,才算是成功

  1. 微信公众号没有做相关的配置或者配置出错
  2. ip白名单没有配置,如果在开发者调试工具中报错为某ip不在白名单内,那就把这个ip配到公众号后台白名单即可
  3. 后端签名算法错误,这里要注意,签名算法加密方式是MD5或HMAC-SHA256。另外排序规则等也容易出错,可仔细阅读微信开发文档。
  4. 前后端appid不一致,appid不是项目公众号的appid。这其实是一个低级错误,但是又是存在的,有些童鞋手里项目好多个,结果搞错了相关的appid,签名肯定失败
  5. 签名url错误。注意签名的url一定用window.location.href来取,另外,项目必须部署以后才能测试签名,不管域名是已经申请好的https域名,还是内网穿透的https域名都行,直接在开发工具地址栏输入localhost:8080,签名肯定失败.
  6. 如果用vue开发,路由模式一定选用history 模式,不可使用hash模式,用hash模式就算成功返回签名信息,分享的时候还是会失败,因为hash模式的地址里带有#号,而微信签名的url是不能有#号的,这会导致分享接口调用失败
  7. 子页面的签名。本人的项目里面,有多个签名页面,而且是从父级页面跳转到子级页面后才签名,这里有个地方要注意,跳转的时候请用window.location.href来进行子页面的跳转,用this. r o u t e r . r e p l a c e 或 者 t h i s . router.replace或者this. router.replacethis.router.push等vue的跳转方式,在安卓机签名可以成功,但是在苹果机ios系统下,就会失败,这和ios的路由缓存机制有关
 window.location.href=`${
      
      this.$globalMethods.getBaseUrl_router()}/newsdetail`//需要签名的子页面的正确跳转方式

本人亦探索过用vue路由守卫解决ios的这个问题,但最终测试时发现无效,因此放弃

微信授权

微信授权相对来说简单很多,按照微信给定的链接拼接号参数,使用window.location.href跳转即可,需要携带的参数,拼接到rederect_uri上。

 redirect_uri= `${
      
      redirect_uri}/newsdetail?connum=${
      
      connum}&salesnum=${
      
      salesnum}`
               redirect_uri=encodeURIComponent(redirect_uri)
               window.location.href=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${
      
      appid}&redirect_uri=${
      
      redirect_uri}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`

这里要强调的一点是,如果想在分享是携带多个参数,那么redirect_uri必须转码,使用encodeURIComponent来进行转码,如果不转码,无论你在rederect_uri上拼接多少个参数,你会发现最终都只会剩下一个参数(这里容我吐槽下微信,是不是应该改成如果不转码,直接授权登录失败??)

分享页面的标题

由于vue开发是单页面应用,如果想让分享出去的页面单独显示自己的标题,最有效的办法就是在mounted里面写上这句

 document.title='你的自定义标题'//

本人踩坑时亦尝试过路由守卫,但是在ios上还是不尽人意,而且还比较麻烦

扫描二维码关注公众号,回复: 12459886 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_41000974/article/details/103754255