您的位置:首页 > 移动开发 > 微信开发

js控制URL地址的改变,以微信服务号的授权获取用户的昵称和头像为例

2016-09-20 17:54 1316 查看
当遇到某个场景需改变当前的URL的时候,有以下几种方法

window.location = "http://service.gaotianyue.com/moon/index.html?openid="+openid;

window.history.pushState({},0,'http://service.gaotianyue.com/moon/index.html?openid='+openid);
window.history.replaceState({},0,'http://service.gaotianyue.com/moon/index.html?openid='+openid);

第一种,是重定向,浏览器会求再次请求(例如微信内置浏览器读条两次)。按回退键会再次请求,总之需要按两次才能退出页面

第二种,URL地址静默变化了,没有重新请求,需要按两次退出页面,第一次回退是到URL变化之前的页面,不读条。第二次退出页面。

第三种(用这个),打开页面只读条一次,只是URL地址变化了 ,回退一次就退出页面。

应用场景,

比如某个活动,发给微信用户moon/index.html,用户打开地址后需要跳转到微信授权接口,腾讯回调到你的服务器,你的服务器通过,微信的接口,获得了openid,nickname,头像,然后让微信用户重定向到moon/index.html?openid=XXX,然后前端使用openid来通过ajax来获取昵称和头像。

这个流程有个小问题,用户每次打开moon/index.html的时候,进度条要读好几次(跳转到后台授权,跳转到腾讯授权,跳转到moon/index.html?openid=XXX,然后用openid请求昵称和头像)。

解决的方式是用本地存储记录openid

var openid = s.getQuery("openid");
if(!openid){//尝试从本地缓存中获取
if(localStorage.opid){
openid = localStorage.opid;
}else{
window.location = 'http://service.gaotianyue.com/moon/shouquan';
return;
}
}


但是这个活动,有个进一步的需求,当你分享出去后,要知道是谁分享给你的。


经过测试,分享出去的链接,再次打开后,会有个installedApp=0这个参数,这样的话,我们可以判断这个参数是否存在,

从打开别人的分享链接

moon/index.html?openid=YY&installedApp=0

然后层层授权后返回

moon/index.html?openid=XX&srcopenid=YY

这就要保证别人发过来的链接是moon/index.html?openid=YY而不是moon/index.html。

因此我们每次从本地存储取得自己的openid后,要改变自己的网页URL。这样分享出去带着自己的openid。

这里就用到了我们总结的更改URL地址的第三种方法。静默改变自己的URL,但是重新请求。而且打开别人分享过来的链接后,也可以判断本地存储,

从打开别人的分享链接

moon/index.html?openid=YY&installedApp=0

直接修改URL为

moon/index.html?openid=XX&srcopenid=YY

这样不用任何跳转就能知道此页面是从谁分享过来的,是谁打开的。

因为腾讯授权获取头像,需要3步,一步是和客户端跳转获取一个code传到你的后台,一步是获取token和openid,还有次是获取昵称和头像。每个接口140毫秒左右,加上你一开始请求后台来控制跳转,这3~4步比较费时,用户感觉你的微信在反复读条。所以本文的处理还是减少了不少开销。之后不管是打开别人的分享链接还是打开主页,都是

只有一次请求,读条一次。
另外静默改变URL后,你右击微信右上角的。。。选择copyURL,拷贝的是moon/index.html,而不是moon/index.html?openid=XX。这不影响我们的逻辑,而且也正好避免了用户用这种分享出去后暴露自己的信息的情况。

下面是示例代码。

服务器:

@RequestMapping("/shouquan")
public void sq(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String code = req.getParameter("code");// 如果无此参数,但是有state参数说明用户没有授权
String srcOpenid = req.getParameter("state");// 提前放在腾讯回调的参数,放的是发朋友圈者的openid
LogCore.BASE.debug("code={},state={},code is null?{},state is null?{}", code, srcOpenid, null == code,null == srcOpenid);
/** code非空说明是授权传腾讯后过来的 */
if (Util.nonNull(code)) {
String[] tokenOpenid = OauthManager.inst().getAccessTokenAndOpenid(Constant.DEFAULT_APP_ID,Constant.DEFAULT_APP_SECRET, code);
String accTokn = tokenOpenid[0];
String openidSq = tokenOpenid[1];// 授权后的自己的openid
// 通过缓存实现减少授权请求
String[] infos = MoonManager.inst().getNickNamePic(openidSq);
if (Util.isEmpty(infos)) {// 缓存中没有
String[] accProfile = OauthManager.inst().getAccountProfile(accTokn, openidSq);
// 授权失败的情况[null, null, {"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: EMvfbA0407ns86 ]"}]
String profileSq = accProfile[2];// 全部信息的json字符串
if (profileSq.contains("errcode")) { // 静默授权获取用户信息失败
shouquan(resp, SNSAPI_USERINFO, srcOpenid);// 强制授权
LogCore.BASE.info("force the auth start!{}", openidSq);
return;
}
MoonManager.inst().setNickNameAndPic(openidSq, accProfile);
}else{
LogCore.BASE.info("hit the cache success!openid={},nickname={}", openidSq, infos[0]);
}
if (Util.isEmpty(srcOpenid) || MoonManager.inst().isHasHelped(openidSq, srcOpenid)) {
resp.sendRedirect(Util.format("/moon/index.html?openid={}", openidSq));
return;
}
// 如果是分享过来的
resp.sendRedirect(Util.format("/moon/index.html?openid={}&srcopenid={}", openidSq, srcOpenid));
return;
}
/**以下说明是客户端请求的授权 */
String openid = req.getParameter("openid");// 带此参数说明是客户端请求的,
shouquan(resp, SNSAPI_BASE, openid);// openid可能为null,即用户点进空白页面后授权
}
/*以放在客户端*/
private void shouquan(HttpServletResponse resp, String scope_, String stateP) {
String redirect_uri = URLEncoder.encode(WECHAT_SIGNON_CALL_BACK_URL);
String response_type = "code";
String path = null;
String url = null;
if (Util.isEmpty(stateP) || "null".equals(stateP)) {// 防止客户端获取空的openid后请求授权
path = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}&response_type={}&scope={}#wechat_redirect";
url = Util.format(path, Constant.DEFAULT_APP_ID, redirect_uri, response_type, scope_);
} else {
path = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}&response_type={}&scope={}&state={}#wechat_redirect";
url = Util.format(path, Constant.DEFAULT_APP_ID, redirect_uri, response_type, scope_, stateP);
}
try {
resp.sendRedirect(url);
} catch (IOException e) {
LogCore.BASE.error("shouquan,scope={},", scope_, e);
}
}


前端代码;

window.onload = function() {
var isappinstalled = s.getQuery("isappinstalled");
var openid = s.getQuery("openid");
var srcopenid = s.getQuery("srcopenid");
//index.html?openid=XX&installedapp=0,说明是别人分享过来的,不过这时候仍可能之前保存有openid
if(isappinstalled){
if(localStorage.opid){
srcopenid = openid;
openid = localStorage.opid;
window.history.replaceState({},0,'http://service.gaotianyue.com/moon/index.html?openid='+openid);

}else{
window.location = "http://service.gaotianyue.com/moon/signon?openid=" + openid;
return;
}
}
if(!openid){//尝试从本地缓存中获取
if(localStorage.opid){
openid = localStorage.opid;
window.history.replaceState({},0,'http://service.gaotianyue.com/moon/index.html?openid='+openid);
}else{
window.location = 'http://service.gaotianyue.com/moon/signon';
return;
}
}
if (openid == srcopenid) {
srcopenid = null;
};
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  优化 微信 url