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

当遇到某个场景需改变当前的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;
    };
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值