之前面试,有个面试官问我微信扫码登录的原理,当时我没具体的看过,就说了一下自己的猜想。
用户访问网页版登录界面,登录页面动态生成一个登录链接,应该带有token之类的,这时候网页开始不停的给服务器发送请求,轮训用户是否已经扫码成功。用户用微信客户端扫码,扫码之后微信客户端向服务器发送一个请求,告诉服务器用户扫码成功,此时可以update一个标志,在网页版微信下次轮询登录状态时,获取到扫码成功的命令。
当时我是这么回答的,然后面试官问我,网页端怎么去轮询呢,我就说了用ajax去请求,设定一个超时时间,如果在指定时间内未获取扫码结果,超时返回。然后面试官说不对,说我肯定用过。当时我就开始想,还有更牛逼的技术么。回来就看微信的网页版js代码。摘录在下面了。
从浏览器数据包上看,微信网页版会每隔27秒就会发送一个登录扫码的请求。具体的js代码在https://res.wx.qq.com/zh_CN/htmledition/v2/js/webwxApp2e4e03.js
这个js文件中,下面摘除部分主要代码。
function a(i) {
switch (i.code) {
case 200:
t.newLoginPage(i.redirect_uri).then(function(t) {
var r = t.match(/<ret>(.*)<\/ret>/),
a = t.match(/<script>(.*)<\/script>/),
i = t.match(/<skey>(.*)<\/skey>/),
c = t.match(/<wxsid>(.*)<\/wxsid>/),
s = t.match(/<wxuin>(.*)<\/wxuin>/),
l = t.match(/<pass_ticket>(.*)<\/pass_ticket>/),
u = t.match(/<redirecturl>(.*)<\/redirecturl>/);
return u ? void(window.location.href = u[1]) : (e.$emit("newLoginPage", {
Ret: r && r[1],
SKey: i && i[1],
Sid: c && c[1],
Uin: s && s[1],
Passticket: l && l[1],
Code: a
}), void(o.getCookie("webwx_data_ticket") || n.report(n.ReportType.cookieError, {
text: "webwx_data_ticket 票据丢失",
cookie: document.cookie
})))
});
break;
case 201:
e.isScan = !0,
n.report(n.ReportType.timing, {
timing: {
scan: Date.now()
}
}),
t.checkLogin(r).then(a);
break;
case 408:
t.checkLogin(r).then(a);
break;
case 400:
case 500:
case 0:
document.location.reload()
}
e.code = i.code,
e.userAvatar = i.userAvatar,
o.log("get code", i.code)
}
case 块,通过判断不同的返回码,做出不同的操作,200 代表扫码成功,408代表未扫码,继续检查。下面是checkLogin(r)
的代码
checkLogin: function(e, o) {
var n = t.defer(),
o = o || 0;
return window.code = 0,
$.ajax({
url: r.API_login + "?loginicon=true&uuid=" + e + "&tip=" + o + "&r=" + ~new Date,
dataType: "script",
timeout: 35e3
}).done(function() {
if (new RegExp("/" + location.host + "/"), window.redirect_uri && window.redirect_uri.indexOf("/" + location.host + "/") < 0) return void(location.href = window.redirect_uri);
var e = {
code: window.code,
redirect_uri: window.redirect_uri,
userAvatar: window.userAvatar
};
n.resolve(e)
}),
n.promise
}
我对前端不是很了解,难道这不是ajax长链接请求,超时重新请求的意思么?