微信网页授权+分享踩过的坑

贾蘅
• 阅读 22545

页面用浏览器自带返回和安卓物理返回死循环的话,直接看高潮部分

背景

折磨我两个工作日加周末一天的问题,我觉得还是有必要记录一下,为什么程序员总是加班,就是遇到这些意想不到的问题

需求

领导:我想做两个页面,放在微信里面可以访问
我:简单啊,用H5实现
产品设计中...
产品:好了,看看没问题就开始开发吧
我:什么时候多了一个需要获取用户信息(产品总是给人惊喜不端)

没有试过微信授权这一块,首先内心三连问,能不能拒绝,能不能改需求,能不能通过熟悉的秘方实现;然而并没有什么用(笑哭表情)

开发中

业务功能没什么难点,模拟一个用户信息,很快就开发完成了...

微信网页授权

官方文档:https://mp.weixin.qq.com/wiki...

1.登录自己的服务号,查看已有的权限

微信网页授权+分享踩过的坑

注意:这里只能是服务号,订阅号没有权限,服务号只能由企业和组织申请

2.公众号设置

微信网页授权+分享踩过的坑

注意:授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.htmlhttp://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.comhttp://music.qq.comhttp://qq.com无法进行OAuth2.0...

微信网页授权+分享踩过的坑
注意:下载这个文件放在域名对应的根目录下

3.链接的生成

"https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"

微信网页授权+分享踩过的坑

以访问www.qq.com/#/detail.html为例,上面第2步的网页授权域名设置成 www.qq.com
REDIRECT_URI为encodeURIComponent('http://www.qq.com/#/detail.ht...
SCOPE为snsapi_base或snsapi_userinfo,区别是只获取用户id,还是获取更多用户信息
state随便写吧,以123为例(没有看出具体有什么用)
其它参数不变

注意:为什么要用encodeURIComponent,你想想,你在url里面直接写url,怎么能直接把它解析成参数

4.放在微信里访问

把第3步上面生成的链接,做为聊天消息,拷贝到微信里面,点击打开,此时我们用alert(location.href)就会发现,地址变成了"http://www.qq.com/?code=生成的随机code&state=上面写的123#/detail.html"

// 获取url参数
export function getQueryVariable(variable) {
  const query = window.location.search.substring(1)
  const vars = query.split("&")
  for (let i=0; i<vars.length; i++) {
    const pair = vars[i].split("=")
    if(pair[0] === variable) return pair[1]
  }
  return undefined
}

// 获取code的值
const code = getQueryVariable('code')

注意:code只能用一次,而且还有时间限制,code插入的位置尤其要注意,不是在
/#/后面,所以用vue或react的路由组件中获取路由参数方式是不可行的,老老实实的写原生js获取

5.通过code获取用户id

微信网页授权+分享踩过的坑

code获取到了以后前端就无能为力了,接下来的步骤只能交给后台了(数据安全性考虑,比如AppSecret不能暴露给前端),自古以来,前端的地位略低于后端,nodejs的出现极大的拯救了前端,虽然后面的事情前端做不了,但我们可以用nodejs或者是类似于postman这种的工具,把后面的接口模拟跑通,然后直接告诉后端,你该调什么接口,用什么参数,后端文档都不用看;当然你也可以做个小白纸,什么都抛给后端,让后端指挥你怎么做(在一个团队中,各个角色的重要性,就看能做的事情)

网页授权就这么搞完了,是不是很简单(笑哭表情),可以愉快的玩耍了

当我把这个链接通过微信右上角分享给同事一起测试时,啪啪打脸了...,呈现的现象
1.通过code获取用户id,报错了
2.分享标题,描述,图标好丑,我能不能改(好像没有分享这个需求,但不分享的话,用户怎么看,我要不要做,没有这个需求,我要不要把锅丢给产品,我好方,但仅有的一点点职业素养告诉我,我还是做吧,做为一个合格的程序员,必备的技能不就是脑补一些产品没想到需求吗(笑哭表情))

分析原因:

1.打印出分享的地址alert(location.href),为http://www.qq.com/?code=上一...

解决思路:
1.自定义分享地址,此时的思路是,地址改成https://open.weixin.qq.com/co... 这种
2.自定义标题,描述和图片
3.最终方案看下面

微信网页分享

官方文档:https://mp.weixin.qq.com/wiki...

1.还是先配置相应的权限

微信网页授权+分享踩过的坑

2.生成签名(后端做的,前端可以选择跳过)

微信网页授权+分享踩过的坑

这个时候就不得不吐槽微信的文档了,残缺了,在第一步就卡住了,只能求助网友,后面我发现

微信网页授权+分享踩过的坑

这里有,IP白名单也要设置,否则是拿不到access_token的,其它的签名怎么生成的后端照着文档做就行了

注意点:网页授权和分享是两个完全独立的模块,分享的access_token和授权返回的access_token是完全不一样的概念

3.前端配置

yarn add weixin-js-sdk

此时我的版本是"weixin-js-sdk": "^1.4.0-test", 微信客户端的版本是7.0.4,竟然遇到一个大坑

微信网页授权+分享踩过的坑

微信官方让我用最新的接口,我试了很久都没有调通,总以为是自己的姿势不对,后面实在不行了,我试了一下老接口,竟然通了,竟然通了,竟然通了,我想崩溃了

上代码

wx.config({
    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,在pc端时会打印出来,不需要的话可以将true改成false。
    appId: data.appid,  // 必填,公众号的唯一标识
    timestamp: data.timestamp,  // 必填,生成签名的时间戳
    nonceStr: data.nonceStr,  // 必填,生成签名的随机串
    signature: data.signature,  // 必填,签名
    jsApiList: ['onMenuShareAppMessage','onMenuShareTimeline','onMenuShareQQ','onMenuShareQZone']
  })

  wx.ready(function () {
    //分享到朋友圈
    wx.onMenuShareTimeline({
      title, // 分享标题
      link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
      imgUrl, // 分享图标
    })
    //分享给朋友
    wx.onMenuShareAppMessage({
      title, // 分享标题
      desc, // 分享描述
      link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
      imgUrl, // 分享图标
    })
    //分享到QQ
    wx.onMenuShareQQ({
      title, // 分享标题
      desc, // 分享描述
      link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
      imgUrl, // 分享图标
    })

    //分享到QQ空间
    wx.onMenuShareQZone({
      title, // 分享标题
      desc, // 分享描述
      link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
      imgUrl, // 分享图标
    })
  })

注意:
1.data是后台返回的签名信息
2.分享链接,该链接域名必须与当前页面对应的公众号JS安全域名一致,公众号里面配置的是www.qq.com,这里分享的地址只能是以www.qq.com开头的,和我们理想的https://open.weixin.qq.com/co... 开头差距很大(怎么授权,好方)

如果只是单纯的自定义分享,到这里就结束了,如果既要分享又要授权,又有问题需要解决了

4.重定向

  1. 初始打开地址为:http://www.qq.com/#/detail.ht...
  2. 进入页面之后。location.href = 'https://open.weixin.qq.com/co... (下面都称为重定向)
  3. 页面地址变成了http://www.qq.com/?code=生成...
  4. 用的是同一个页面,所以需要判断url有没有code,来决定是否要执行第2步,否则会死循环

文章写到这里,已经解决了授权+分享,是不是感觉故事很平稳,一部好的电影怎么能这么快结束

高潮(大坑来了)

现象

微信中打开页面,用安卓的物理返回键,点一下返回不了,需要连续快速点两下才能退出

分析原因

打开的页面是不带code的地址,经过重定向后,生成了带code的地址,此时浏览器的历史记录中会有两条记录,从带code的地址返回到不带code的地址,页面判断没有带code,又会重定向到带code的页面,产生了死循环

解决方案

1.不让它产生多一条的记录

首先想到的是location.replace(url), 发现把url替换成授权的地址时(https://open.weixin.qq.com/co...

结果:失败

2.代码控制清除一条历史记录

const params = getQueryParams()
const code = sessionStorage.getItem('code')
if (!params.code && !code) {
  let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${yourAppId}&redirect_uri=${encodeURIComponent(location.href)}&response_type=code&scope=snsapi_base&state=1#wechat_redirect`
   window.location.replace(url)
} else if(!code){
   sessionStorage.setItem('code', params.code)
   history.back()
}

搜索了一大圈,看见了这段代码(来自:https://www.cnblogs.com/wonyu...
sessionStorage(只在当前会话有效),用当前会话窗口储存的code,来判断不带code的页面要不要重定向

看似很完美的代码,还是逃不过微信的大坑,通过链接进入时,偶尔会遇到页面空白

原因:

上面用到的历史记录返回,页面不刷新(偶尔),我尝试过强制微信浏览器刷新,甚至怀疑是vue的坑,然后用原生写了一段js来操作dom,并没有什么用

最后发现返回的时候,js都能正常的执行,UI不重新渲染,UI不重新渲染,UI不重新渲染,偶尔出现,不是必现,我再次好方

结果:偶尔失败

3.返回两次,才能退出

借鉴上面的思路,判断当前会话窗口储存的code是否有值,有值就不重定向

结果:解决了偶尔不渲染的问题和死循环的问题,但对于有轻微强迫症的我来说,需要点两次才能返回还是挺难接受的

本来属于愉快的周末,就在微信这个大坑里结束了,关上电脑,沉思一会(想想如何说服测试同学这个问题解决不了,是微信的坑(笑哭表情))

结尾

处女座最大的悲哀就是心里不能放事情,总感觉不踏实,休息也休息不好(悲哀)

突然想到前段时间开发的app,自己控制过android的返回,微信会不会也提供了自定义返回呢,经过一大堆的搜索,发现js就有能监听浏览器返回的事件(有些知识点不用,慢慢就忘了),兜兜转转了一大圈,至少用我的周末帮大家证明了网上说的很多方式行不通,哈哈哈,终极解决,上代码(vue的思路)

  created () { // 当前需要直接退出的页面
    window.history.pushState(null, null)
    window.addEventListener("popstate", this.popstate, false)
  },
  destroyed: function () { // 记得清除,不然单页面,其它页面也可以用
    window.removeEventListener("popstate", this.popstate, false)
  },
  methods: {
    popstate () {
      wx.closeWindow() // 微信网页退出
    }
  }

注意:为什么要多window.history.pushState('_android_back', null, location.href)这句代码,因为popstate只能监听pushState创建的

备注:微信的文档会更新,当你使用时(看一下这篇文章的出生时间),最好参考官方文档,如果你觉得有一点帮助了你,请点个赞(程序员写文章不容易,最烦写这种随时可能过时的文章,哈哈哈)

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
vue h5 对接支付宝,微信支付,微信js支付
vueh5实现支付(支付宝,微信)h5端实现支付难度不大,只是有些小的点需要注意下,其他的看文档撸就行了。支付宝很简单,后端返回一个html,前端插入调用就行了,微信支付分两种:1、微信内支付(jsapi,微信内浏览器)2、微信外支付(h5支付)。一、支付宝支付//前端啥都不用管,交给后端去干,返回html调用点击就好了/
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Easter79 Easter79
3年前
thinkcmf+jsapi 实现微信支付
首先从小程序端接收订单号、金额等参数,然后后台进行统一下单,把微信支付的订单号返回,在把订单号发送给前台,前台拉起支付,返回参数后更改支付状态。。。回调publicfunctionnotify(){$wechatDb::name('wechat')where('status',1)find();
梦
4年前
微信小程序new Date()转换时间异常问题
微信小程序苹果手机页面上显示时间异常,安卓机正常问题image(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b691e1230e2f15efbd81fe11ef734d4f.png)错误代码vardate'2021030617:00:00'vardateT
Stella981 Stella981
3年前
Android 微信分享后留在微信,没有回调的问题解决方案
网上有很多关于微信分享后没有回调的问题,大多数讲的都是一些配置不对、WXEntryActivity类的包名不对等所引起的错误。但我今天要讲的问题不是因为这些集成不当引起的问题,而是微信分享SDK本身存在的问题(或者这并不是微信SDK的bug,而是微信本身就是这样设计的)。这个问题就是,当我们分享成功后,微信会弹出一个弹窗,让用户选择“留在微信”或者“返回ap
Easter79 Easter79
3年前
Taro小程序自定义顶部导航栏
微信自带的顶部导航栏是无法支持自定义icon和增加元素的,在开发小程序的时候自带的根本满足不了需求,分享一个封装好的组件,支持自定义icon、扩展dom,适配安卓、ios、h5,全面屏。我用的是京东的Taro多端编译框架写的小程序,原生的也可以适用,用到的微信/taro的api做调整就行,实现效果如下。!在这里插入图片描述(https://i
Wesley13 Wesley13
3年前
h5 接入微信支付
我们公司,现在用ping做h5接入,用的是h5"壹收款"准备:如果公司,现在还没有公众号的话,支付宝。可以把这些工作,给ping来做这些事情 1.注册微信公众号,开通支付功能。2.注册ping (如果是自己开开通的微信支付,要填写相关信息)3.微信设置网页授权获取用户基本信
LibraHeresy LibraHeresy
2年前
企业微信使用微信 jssdk 实现转发分享功能
前言又接到一个看似简单,实则难受的需求,实现企业微信环境转发H5页面到微信好友和朋友圈,并保留卡片形式。需求简单明了,但是和微信沾边的,都不是一条好走的路。一上手就发现问题了,企微的jssdk它不更新了。兜兜转转发现,好像企微和微信的jssdk统一用@we
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(