前言
自己开始开发的时候也在网上搜过些教程,尤以segmentfault和脚本之家的两篇文章为甚,然后两篇文章都只是讲了自己的场景和如何使用,却没有讲述其中的原理。我不喜欢只会用的程度,如果不明白为什么这么做,每一步做的理由,所以写下这篇文章,分享一下我在开发中的心得。
前期准备
你肯定不愿意每次都在手机上调试,因为不能console,所以你得准备这个渣渣开发者工具,mac下容易假死。有大佬改chrome,伪装成微信浏览器,我没试过,不知道能不能成功。
然后是natapp,或许大家会有疑问,我都有服务器了,还买这个穿透工具干啥?因为微信签证和当前浏览器URL有关(微信设置JS安全域名),你肯定不想每次打包后都拜托后台大哥传上去你再调试吧。但是本地的localhost 192.168.x.x是无效的,因此通过natapp把当前主机暴露到外网,这样可以临时设置JS安全域名到这里,就可以进行验签和授权了。
额外补充
我们知道,做Vue开发会通过express开启一个临时服务器,我试过natapp直接映射到这个服务器,前端请求会报错,content-length not match。所以我就用anywhere对打包后的文件又开了一个本地服务器,这样其实效率挺低的,希望哪位大佬告诉我解决方案。
渣渣mac
该问题存在于mac下,windows下无问题。
网页授权和分享
这俩货其实是不一样的,得分开实现,网页授权是一套机制。分享是另一套机制。我们先看看分享
微信分享
首先绑定域名,这个就填natapp的临时域名就好了。然后引入JS文件,npm上有现成的包
import wx from 'weixin-js-sdk';
,第三个就是最重要的了。debug参数开启了,你的验签信息,分享结果,成功与失败都会以alert形式的弹窗弹出来了。调试的阶段我们需要打开,接着几个参数都没太大的问题,唯一难点在于signature。签名
signature
这些参数都应该初始化过程中请求后台,由后台返回。值得注意的是signature,在附录中有详细的介绍。这个signature会和当前浏览器的URL有关,并且注册以后如果URL发生改变需要重新注册。什么意思呢?
vue-router中如果mode设置为history模式,如果进入不同路由时,URL发生了变化,此时微信认为你的URL是不合法的,因此验签失效了,你就得必须重新验签。
如果每一个路由都重新验签对于我这种强迫症是受不了的。因此我们使用hash模式,这样路由会响应#号后面的变化,真正的地址没有发生变化。因此只需要一处验签,后面都不会受到影响。
下面是我的验签代码
首先发出一段ajax请求,讲当前的URL传递给后台,后台会根据这个URL生成signature,注意这里使用的是
window.location.href.split('#')[0]
方法,不能写死。因为如果进行网页授权的话。query参数会出现在#号前面。比如http://xxx.xx.com/?xx=xx&xx=xx&/#/xxx
,这个query参数将会伴随整个页面的生命周期。并且其中的参数是动态变化的,如果写死将会导致验签失败。ajax拿到后台数据后进行验签,成功后调试模式下会有提示。接着进行分享
如果出现正确的图片和title,并且调试信息无误的话一个分享就成功了。值得注意的是,分享出去的URL必须和签名的URL一样,否则分享会失败(我试过分享授权的链接,失败了)。并且如果当前用户没有订阅的话,分享出去也只是title和一串URL地址,只有订阅用户才能分享出图片和描述。
在频繁改动appid的时候(测试需要),有的时候微信服务器会有缓存,导致正确的签名顺序也会报错误的验签,这个时候等等就好了。
目前只做了风险,验签和分享坑差不多就这些。
网页授权
这个其实很简单,就是诱导一个用户跳转到一个网页,这个网页的URL配置了一些参数,按照相关的要求由后台配好以后点进去就行了。静默授权,就是不获取用户的信息,表现就是链接跳出去又跳回来。获取信息就是用户点击一个确认授权,然后你就可以获取该用户的相关信息了。
这个示例链接是
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
其中的redirect_uri就是回调的URL,授权成功后,将转入这个页面,并且携带两个query参数,其中的code就是授权码,通过这个授权码获取该用户的openid。
这个授权码有时间限制,并且只能使用一次。将这个授权码发送给后台以后,后台请求openid,这个openid是唯一的,可以通过这个openid在数据库中绑定用户。之后的逻辑就和非微信环境没有太大区别了。
业务逻辑
整个业务逻辑就是,首先判断是不是微信环境(我们的网页要求移动端同样能用)
const isWechat = () => {
let ua = window.navigator.userAgent.toLowerCase();
return ua.match(/MicroMessenger/i) == 'micromessenger';
}
如果是微信环境,就对他进行验签。此时并未网页授权,网页授权和验签可以分开。
授权的逻辑放在开启探索这个按钮上
首先是判断当前是否存在code(因为这可能已经是授权后的页面,因此先检查是否有code,再判断是否需要跳转授权页)
const getQuery = name => {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
return null;
}
如果code存在就把code发给后台,根据后台的返回结果处理自己的业务逻辑。code不存在则通过
window.location.href=xxxxx
跳转到微信授权页,授权成功后又跳转到当前页面,此时code存在。
如果需要其他JSSDK服务,就让后台吧通过code获取的openid,accesstoken保存下来。有些用户已经使用过了网站服务,或者网站需要用户的手机号,获取code以后就跳转一个绑定页,要求用户绑定手机或者邮箱,这个地方根据自己的业务逻辑来。
因为要同时处理微信与非微信登录,所以这里的判断逻辑比较复杂,建议先草稿纸规划好,考虑到每一个情况再敲代码。不然到时候甩锅都甩不好。
结束
微信开发确实是一个不小的难题,并非代码多高深,主要难在调试的环境上。每一个域名绑定,授权都很复杂。相关的文档个人觉得也并不完善。并且最坑爹的是微信会缓存appid,这样在开发切换到生产环境的时候,微信服务器得appid并没有切换成功,导致验签失败。在你确认签名配置无误的时候,依旧发生验签失败,那么你就等等吧。
另外,未验签分享出去的title默认就是网页的title,也就是document.title。
:)就是这样