有了前两篇关于微信网页项目与前后端分环境开发的思考,帅华君将在本篇介绍通过修改本地DNS解析来绕过微信服务器的验证,并通过Nodejs搭建本地服务作为中间件转发API请求到远程服务器,获得用于配置JS-SDK的一系列参数,从而正常调用JS-SDK提供的丰富API。
准备工作
两个域名
以帅华君的个站为例, 帅华君使用 shuaihua.cc 二级域名用来作为微信的安全域名,模拟真实项目中普通用户访问的域名,需要在微信公众平台后台或微信测试账号相应位置设置此域名。
www.shuaihua.cc 三级域名用来作为提供远程API接口的域名,模拟真实项目中专门用于提供接口的域名,普通用户基本不会访问,当然,既然该三级域名是用来提供API的,所以作为API使用更语义化的三级域名命名应该类似于Github的 api.github.com。不过这两个域名用来模拟真实的情况没有问题。

修改DNS
mac系统hosts文件所在目录为 /private/etc/hosts,将该文件拖拽直桌面,使用任意文本编辑器打开,根据上方的规定,将 shuaihua.cc 二级域名劫持到 127.0.0.1,保存后将文件拖拽回原位置即可:

如此,启动本地Nodejs搭建的本地服务,当在浏览器中输入 shuaihua.cc 便可访问到本地服务器,也就成功把帅华君个站真正的DNS解析服务器劫持在摇篮里了。有害或者无害并不是绝对的,这是我想要的,所以是无害,而病毒恶意修改hosts则是有害,有害或无害要看是主动或是被动。

写着写着就领悟到了关于一切对立面的真实含义:就像蛋壳从里面打破是新生,是有益,从外面打破是毁灭,是有害!人亦如此。
微信网页授权
获取CODE
上一篇文章介绍了如何通过微信授权获取用户信息,请求地址如下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
上面帅华君已经将 shuaihua.cc 设置为JS接口和OAuth2.0网页授权回调页面安全域名,因此请求参数中的 redirect_uri 设置为URI以 http://shuaihua.cc/ 起头的回调路径即可。
以帅华君申请的微信测试公众号为例,绑定开发者后,在开发者工具内访问如下地址:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxa0bb1e90533c6981&redirect_uri=http%3A%2F%2Fshuaihua.cc%2F&response_type=code&scope=snsapi_base&state=123#wechat_redirect
微信验证成功后自动将页面重定向到如下地址:

前端获取到code值之后,向后台发起Ajax请求,后端使用APPID/SECRET/CODE三个参数获取到用户与公众号产生的唯一OPENID,获取到OPENID,随后使用ACCESS_TOKEN和OPENID获得微信用户基本信息,再接下来就是项目的具体业务了。
获取OPENID
帅华君快速写了一个获取url查询参数的函数,当然真是项目中尽量不要重复造轮子。
const getQuery = () => {
let search = window.location.search.replace(/\?/g,'')
if(!search) return
let query = search.split('&')
let res = {}
for(let i=0; i<query.length; i++){
let _q = query[i].split('=')
res[_q[0]] = _q[1]
}
return res
}
向提供API的三级域名 www.shuaihua.cc 发送请求获取openid,需要传入code值:
let QUERY = getQuery()
if(QUERY){
if(QUERY.code){
cco.ajax({
url: `/api/getwepage_test_openid/?code=${QUERY.code}`,
method: 'GET',
onReceived: client => {
console.log(client)
}
})
}
}
你可能会疑惑,上方代码片段中Ajax请求的完整路径是:
http://shuaihua.cc/api/getwepage_test_openid/?code=061hWRHj1vJaBv05H1Kj1MPXHj1hWRH1
可是提供API的路径难道不应该是 :
http://www.shuaihua.cc/api/getwepage_test_openid/?code=061hWRHj1vJaBv05H1Kj1MPXHj1hWRH1
这是因为因为帅华君使用Nodejs搭建的本地服务器除了提供静态文件服务外,还有一个很重要的任务,就是转发API接口,规则是,所有以 /api/ 开始的路径都将转发到 http://www.shuaihua.cc,而提供API的域名并不受本地DNS解析劫持的影响,仍然可以访问远程服务器,这也是为什么最一开始帅华君说需要准备两个域名。
远程服务器返回如下信息,成功获取用户的OPENID:

用户基本信息
由于CODE只能使用一次,因此相同的URI下,该接口不能重复调用,除非重新将用户引导至微信网页授权页面,获取新的CODE值。
获取到OPENID之后便可以如法炮制发送Ajax请求获取用户信息,后面就涉及到具体项目的具体业务,大同小异,不作赘述。

配置JS-SDK
有了上面的基础,接下来配置微信JS-SDK就顺水推舟了。
上面提到已经在微信测试账号后台将 shuaihua.cc 设置为了JS接口安全域名,因此直接,调后端写好的接口即可,唯一的参数是当前的URI(不包含锚标记)。
cco.ajax({
url: `/api/getwepage_test_jsconfig/?url=${encodeURIComponent('http://shuaihua.cc/')}`,
method: 'GET',
onReceived: client => {
let res = client.response
console.log(res)
wx.config({
debug: true,
appId: res.appid,
timestamp: res.timestamp,
nonceStr: res.noncestr,
signature: res.signature,
jsApiList: [
'updateAppMessageShareData','updateTimelineShareData',
'onMenuShareWeibo','onMenuShareQZone','startRecord',
'stopRecord','onVoiceRecordEnd','playVoice','pauseVoice',
'stopVoice','onVoicePlayEnd','uploadVoice','downloadVoice',
'chooseImage','previewImage','uploadImage','downloadImage',
'translateVoice','getNetworkType','openLocation','getLocation',
'hideOptionMenu','showOptionMenu','hideMenuItems','showMenuItems',
'hideAllNonBaseMenuItem','showAllNonBaseMenuItem','closeWindow',
'scanQRCode','chooseWXPay','openProductSpecificView','addCard',
'chooseCard','openCard'
]
})
}
})
为了方便,帅华君把所有的API全部包含进来了,调用上方示例代码中的 wx.config({...}) 后,程序也会向微信服务器验证,只有微信为服务返回的全部参数与我们的全部参数完全一致,才能使用JS-SDK提供的丰富接口。
微信服务器验证成功后会执行向 wx.ready() 传递的回调函数,验证是否验证成功,有成功就有失败,wx.error() 用来当验证失败是执行传入的回调函数。直接抛出以下代码:
wx.ready(function () {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
var localIds = res.localIds;
}
});
})
上方代码示例,使用JS-SDK选择图片的接口,在微信开发者工具中,直接弹窗提示该接口他调用成功返回的对象信息。

本文未涉及如何在本地部署需要支持HTTPs协议的方案,只有留个裂缝,阳光才能透进来,抛砖引玉,各抒己见吧。
本文完