摘要

关于微信开发的话题,例子确实已经有不少,但大部分都是人云亦云,很多小细节或者需要注意的地方却大多没有讲清楚,这令很多刚开始开发的人感觉大很迷茫。而我今天要说的话题,主要着眼于两个方面。

一:如何存储获取用户信息及调用第三方接口所需要的token.

二 : 第三方页面授权,如何减少从微信服务器获取用户openid的次数以及减少获取用户信息的次数,加速第三方页面的加载速速。

(注:演示所使用的是java语言,其他语言可与此类似)

下面我将开始讲述第一个问题。

如何存储获取用户信息及调用第三方接口所需要的token?

从微信的官方文档上,我们知道,获取token的次数为1天2000次,每两小时token失效一次,对于那种一天没有几个人访问的微信公众号而言,他们可能只是简单的每次调用高级接口都会去获取一遍token.众所周知,这种做法极其的耗费时间。从网上其他网友给出的存储方案大概有如下几种:

数据库:通过微信接口获取到 Token 之后,将 Token存储到数据库,每次需要时从数据库取出。采用定时任务的方法每隔一个固定的时间去获取一次token.

NoSQl:这里以 Redis 为例子。通过微信接口获取到 Token 之后,存入 Redis,可以通过设置redis的过期时间,每次需要token时从redis中取出来,若没有,则证明Token 已过期可重新获取(当然也可采用上面的定时任务的方式定期获取)。

文件存储:这个比较适合单一公众号的情况。通过微信接口获取到 Token 之后,存入文件,采用定时任务的方法每隔一个固定的时间去获取一次token.

(固定的时间:一般设为1小时为宜,如1小时后因网络原因,请求获取token失败,则原有的token还可以在使用1小时,这种方式将错误降低了一半)

大致有这三种方案。当然对于那些将token存储在session或者cookie里面的,这里我只能呵呵一笑了。

基于以上三种方式,我个人比较推崇的一个顺序是NoSQl>数据库>文件存储。

下面我分别来说说他们的优缺点:

采用数据库和文件存储,对于单节点并且用户请求数不是很多的web项目而言,是可以的正常运行的,但是对于分布式多节点的项目,采用这两种方式是行不通的。而我今天要说的第三种通过Redis方法存储,一方面它可以提升获取token的速度,另一方面当分布式项目的多个节点要公用同一个token的时候,我们可以方便的取到。

第三方页面授权,如何减少从微信服务器获取用户openid的次数以及减少获取用户信息的次数,加速第三方页面的加载速速?

从诸多的博客中,我们了解到,第三方页面授权获取用户信息,我们要调用两次微信接口。

第一次:构造应用授权的url,通过返回的code,换取用户的openid.

第二次:通过用户的openid与token获取用户信息。

对于页面比较多的应用,每个页面请求时都需要调用两个方法,于用户而言这是极其耗费时间的。

然而诸多的博客只是告诉我们改如何处理用户信息,诸如将用户信息先拉取下来存储到自己的数据库,然后每次需要时从自己的数据库中通过openid来获取。殊不知这种博客只说了一点,他们没有考虑到的问题是:

用户若修改了自己的信息,该如何同步到自己的表里面.

用户的信息是获取到了,但是每次用户访问网页,标识用户身份的openid依旧每次都要去调用接口获取。(获取用户信息的次数微信API规定为500000次)

那么接下来我要说的这个就是如何解决上面两个问题,处理过程大致如下:

a.添加拦截器,拦截需要授权页面的controller

拦截器:

packagecom.fdc.home.dec.wx.filter;

importcom.alibaba.dubbo.common.utils.StringUtils;importcom.fdc.platform.common.yfutil.PropertyReader;importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;

importjavax.servlet.http.Cookie;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.util.Arrays;

/**

Created by pl on 2017/1/13.

*/

public class OAuth2Interceptor extendsHandlerInterceptorAdapter {

public static String indexUrl = PropertyReader.getValue("indexUrl");//从配置文件中读取域名//private static String[] arrQueController = {"newquestion", "mycenter","testCookie"};

public booleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throwsException {

Cookie[] cookies=request.getCookies();

String openId=null;//判断cookie中是否存在openid 若存在则直接跳过,不存在则获取一次

if(cookies!=null){for(Cookie cookie : cookies){if(cookie.getName().equals("openId")){

openId=cookie.getValue();

}

}

}if(StringUtils.isEmpty(openId)) {if (handler instanceofHandlerMethod) {

HandlerMethod handlerMethod=(HandlerMethod) handler;

String methodName=handlerMethod.getMethod().getName();

String uri=request.getRequestURI();//if (checkList(arrQueController, methodName)) {//System.out.println("执行了");

response.sendRedirect(indexUrl + "/oauth2Api?resultUrl=" + indexUrl +uri);return false;//}

}return true;

}else{return true;

}

}

public voidpostHandle(

HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throwsException {

}

public voidafterCompletion(

HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throwsException {

}

public booleancheckList(String[] arr, String targetValue) {returnArrays.asList(arr).contains(targetValue);

}

}

spring-servlet.xml (拦截两个指定的controller:testCookie,testCookie1)

b.用户首次访问,调用微信接口获取openid和用户信息。将openid写入服务器端的cookie,将用户的信息写入redis缓存中,以openid作为redis的key。

packagecom.fdc.home.dec.wx.controller;

importcom.fdc.home.dec.service.inter.service.DecWxService;importcom.fdc.home.dec.wx.service.CheckUserInfo;importcom.fdc.home.dec.wx.utils.JSONHelper;importcom.fdc.home.dec.wx.utils.WxUtils;importcom.fdc.home.dec.wx.vo.token.WeixinOauth2Token;importcom.fdc.home.dec.wx.vo.user.WeixinUserInfo;importcom.fdc.platform.common.yfutil.PropertyReader;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;

importjavax.servlet.http.Cookie;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.HttpSession;importjava.io.IOException;

/**

Created by pl on 2017/1/13.

*/@Controllerpublic classOAuth2Controller {

@Autowired

privateDecWxService decWxService;//判断用户是否登录的公用方法

CheckUserInfo checkUserInfo = newCheckUserInfo();//从配置文件获取appid

public static String appid = PropertyReader.getValue("appid");//从配置文件获取appsecret

public static String appsecret = PropertyReader.getValue("appsecret");//从配置文件获取主域名

public static String indexUrl = PropertyReader.getValue("indexUrl");public static String wtoken = PropertyReader.getValue("wholetoken");

/**

组装授权url

@paramrequest

@paramresultUrl

@return

*/@RequestMapping(value="/oauth2Api")publicString oauth2API(HttpServletRequest request, @RequestParam String resultUrl) {

String redirectUrl= "";if (resultUrl != null) {

String backUrl=indexUrl+"/oauth2MeUrl?oauth2url="+resultUrl;//组装授权url

redirectUrl =WxUtils.oAuth2Url(appid, backUrl);

}return "redirect:" +redirectUrl;

}

/**

获取用户信息

@paramrequest

@paramresponse

@paramcode

@paramoauth2url

@return

@throwsIOException*/@RequestMapping(value= "/oauth2MeUrl")public String oauth2MeUrl(HttpServletRequest request,HttpServletResponse response, @RequestParam String code, @RequestParam String oauth2url) throwsIOException {

request.setCharacterEncoding("utf-8");

response.setCharacterEncoding("utf-8");

HttpSession session=request.getSession();

session.setAttribute("code",code);//用户同意授权

if (!"authdeny".equals(code)) {//获取网页授权access_token

WeixinOauth2Token weixinOauth2Token =WxUtils.getOauth2AccessToken(appid, appsecret, code);//网页授权接口访问凭证

String accessToken =weixinOauth2Token.getAccessToken();//用户标识

String openId =weixinOauth2Token.getOpenId();

String wholetoken=decWxService.getToken(wtoken);//获取微信用户openid存储在cookie中的信息

Cookie userCookie=new Cookie("openId",openId);

userCookie.setMaxAge(-1);

userCookie.setPath("/");

response.addCookie(userCookie);

WeixinUserInfo weixinUserInfo=WxUtils.getWeixinUserInfo(wholetoken, openId);//将用户信息写入redis

decWxService.setToken(openId, JSONHelper.beanToJson(weixinUserInfo));

}else{return "redirect:"+indexUrl+"/error404";

}return "redirect:" +oauth2url;

}

}

(注:WxUtils中封装各种请求微信服务器的接口,具体可自行百度)

以上两步基本可以解决用户授权的问题。基于此需要说明的是:

开发中要设置cookie过期时间,设置为负数,表明当用户关闭浏览器的时候自动清空cookie,但在实际的测试中,微信浏览器并不会立刻清理cookie,你可以自行清理cookie.每次用户访问时直接从cookie中获取openid,若没有,才会调用微信接口获取。在获取openid的同时,更新redis缓存中的用户信息,这样达到及时同步用户信息的效果,也减少了对微信服务器的访问。

有部分网页在博客中提到微信浏览器没有cookie和session,基于这类问题,还请自己动手验证吗,微信浏览器是有cookie和session的(请区分服务端session和客户端session),这里之所以没有将openid存储在session中,其主要是考虑到分布式多点项目中session比较难以处理。

比较重要的一点是,当用户更换微信登录时,cookie会自动清除,登录成功后,会重新获取新登录的用户的openid。

公众号openid实时存储mysql_微信--高效解决token及授权用户openid的持久化处理办法...相关推荐

  1. 微信公众号开发教程(六)获取微信用户信息-网页授权

    作者:陈惠,叩丁狼教育高级讲师.原创文章,转载请注明出处. 在学习网页授权之前,我们先来了解下这次的需求: 我们的应用中有一个用来显示个人信息的页面,当微信用户在微信app中打开这个页面,希望可以获取 ...

  2. url 微信公众号开发 配置失效_微信公众号开发之授权登录

    一.UnionId和openId 微信登录最重要的两个返回信息,一个是UnionId,一个是OpenId.两者之间有着必然的联系. UnionID机制的作用说明:如果开发者拥有多个移动应用.网站应用和 ...

  3. php微信公众号支付实例教程,php微信支付之公众号支付功能

    这篇文章主要为大家详细介绍了php微信支付之公众号支付功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 网上的很多PHP微信扫码支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后 ...

  4. 【微信公众号发红包转账】微信公众号上手机网页接收请求,通过公众号给用户发红包 开发流程...

    有了微信支付 的开发做铺垫,相关的微信其他业务处理起来逻辑就能清晰很多. 准备好这两个架包 ------------------------------------------------------ ...

  5. 关于微信公众号页面获取code进行微信授权登录

    关于微信公众号页面获取code进行微信授权登录 前言 提示:本文章为个人平时开发中的一些坑,对于新手可以耐心看一下,如果您感觉可以的话,请点个小星星再走吧,多谢了~~~ 提示:以下是本篇文章正文内容( ...

  6. 分享公众号抽奖的作用_微信公众号抽奖活动怎么弄

    公众号线上抽奖相比于现场抽奖有很多好处,除了成本更低,宣传范围更广,能够吸引更多的参与,还有一大好处就是,线上抽奖比线下更容易挖掘潜在客户.抽奖活动可以手机客户的手机号,年龄,消费信息等.对流量转化和 ...

  7. java微信公众号面试题_使用微信公众号开发模拟面试功能

    最近在整理我在大厂面试以及平时工作中遇到的问题,记录在 shfshanyue/Daily-Question 中,但觉得对于时时回顾,常常复习仍然做的不够. 于是在微信公众号中开发了随机生成模拟面试的功 ...

  8. 【微信公众号开发】八、微信JS发起支付

    重要声明:本文章仅仅代表了作者个人对此观点的理解和表述.读者请查阅时持自己的意见进行讨论. 目录 本系列博文还包含了下面的博客: [微信公众号开发]一.运作及配置流程简介 [微信公众号开发]二.解析微 ...

  9. 微信(jspai版本即公众号h5版)支付-微信下单支付及企业转账到零钱

    微信(jspai版本即公众号h5版)支付-微信下单支付及企业转账到零钱 一.后端前置条件 二.配置h5 devServer 三.后端开发代码 四.前端开发代码(uniapp) 一.后端前置条件 准备好 ...

最新文章

  1. 浏览器控制台执行代码_JavaScript 和 浏览器那些事
  2. Mysql导入数据时-data truncated for column..
  3. diy一个android手机版下载,原神个人自制版
  4. 分部类和方法的学习以及在LINQ中的应用(原创)
  5. MySQL 获取物理表的主键字段
  6. 计算机端口详解(总结)
  7. .gpx文件转geojson
  8. chrome清除缓存快捷键
  9. 从数字艺术品到 NFT
  10. 小白新手web开发简单总结(三)-一个简单的Web开发项目
  11. 谷歌gmail注册入口_Gmail,日历和其他Google Apps即将出现的外观如下
  12. 使用pynput监听键盘组合键
  13. Mybatis-There is no getter for property named 'tj' in 'class
  14. Linux网络容灾,关于异地容灾的感触
  15. 如何真正做好客户管理
  16. 西门子TIA博途仿真器PLCSIM使用教程
  17. 关于网页中显示生僻字的方法
  18. 局部搜索、模拟退火和遗传算法求解TSP问题
  19. 关于有刷直流电机,你需要了解这些
  20. 移动端 简易的table表格

热门文章

  1. Git应用之eclipse解决冲突代码
  2. C语言为什么被const声明的变量不是一个常量表达式
  3. MRC与ARC混合编程的编译器标记
  4. 剑指offer——圆圈中最后剩下的数字
  5. IE6 透明遮挡falsh解决方案
  6. SAP NetWeaver 平台介绍
  7. 用SSAS将多个FLV和MP3合成一个FLV文件
  8. 为什么php md5,为什么php md5()总是与python的不同哈希.md5()如果使用汉字?
  9. 炉石整活拔线方法_酒馆战棋:整活如何简单“拔线”?瓦娘在线教学,却3本得死神?...
  10. 02:陶陶摘苹果【一维数组】