array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 微信获取openID - 爱码网
gscq073240

 

在进行微信开发中,你时常会因为获取某些值或者配置什么设置而陷入莫名其妙的坑中,我也一样。明明觉得对的,却始终不成功,这篇文章主要总结一下我陷入的坑。

微信获取openID


在进行微信开发中,你可能会想获取用户的openID,作为用户在公众号中的唯一凭证。
官方文档中对openID是这样介绍的:为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个UnionID,可以在用户管理-获取用户基本信息(UnionID机制)文档了解详情。
也许你会在用户打开我们的网页时获取到用户的openID。
那问题来了,我们到底该怎么获取到这个openID呢?
你可以参考这地址下的文档:http://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html
获取openID的基本流程图:

这里写图片描述

  • 首先你需要获取Code

    每次获取的code只能使用一次,5分钟未被使用自动过期。
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=你要回调的的地址&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

在上面的链接中通过设置scope的值可以改变获取方式,snsapi_base(不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)。

当打开此链接时页面将跳转至 redirect_uri/?code=CODE&state=STATE。。这时上面的code便会被赋予值,这值便是我们想要的code。
- 通过Code获取openID

获取code后,请求以下链接获取access_token:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

如果成功返回json数据,上面便带有我们想要的openID。本人在后台开发中用到是SpringMVC技术,将就点看吧。

参考如下实例代码:

 @RequestMapping("startRegister")
    public void thCarStartRegister(Map<String, Object> map, HttpServletRequest request,Writer out) throws IOException{
        String wxcode = request.getParameter("code");
        if (wxcode != null && !"".equals(wxcode)) {// 判断微信的code是否有值
            // 微信获取用户openID
            String openID = (String) JSON.parseObject(ThcHttpUtils.thcGet(WeiXinUtils.getWXAccessUri(wxcode), ""))
            out.wirte(openID);
        } else {//没有code值重新重定向下
            return "redirect:" + WeiXinUtils.getWXCodeUri(THCarData.THCAR_URL + "startRegister");
        }
    }



    public static String getWXAccessUri(String wxcode) {
        String uri = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APPID + "&secret=" + SECRET + "&code="
                + wxcode + "&grant_type=authorization_code";
        return uri;
    }

这样便能取得openID,用于我们对用户的唯一身份凭证。上面写得比较粗糙,希望对你有帮助。

在使用微信的js时,对配置的设置


可以说这东西真麻烦,一不小心你就陷入坑中。一定要详细再详细的看文档。

文档参考地址:https://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html

基本实现总结

1.引入js文件:在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js

2.配置js

$(function wxconfig(){
    wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: \'\', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: \'\', // 必填,生成签名的随机串
    signature: \'\',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
    });
    wx.ready(function(){
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
    });
    wx.error(function(res){
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
    });
});


具体的了解请详情文档。这里需要特别强调的是wx.config的配置。

很有可能你会出现如下错误:

出现config:fail错误

这是由于传入的config参数不全导致,请确保传入正确的appId、timestamp、nonceStr、signature和需要使用的jsApiList

invalid signature签名错误

建议按如下顺序检查:

1.确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。

2.确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。

3.确认url是页面完整的url(请在当前页面alert(location.href.split(‘#’)[0])确认),包括’http(s)://’部分,以及’?’后面的GET参数部分,但不包括’#’hash后面的部分。

4.确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。

5.确保一定缓存access_token和jsapi_ticket。

6.确保你获取用来签名的url是动态获取的,如上面的http://xxx.xxx.com/startRegister就是一个冬天的url。 如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去’#’hash部分的链接(可用location.href.split(‘#’)[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。

7.一定要确保你进行配置的页面url与签名所用的url地址一致。如上面的配置是在http://xx.xx.com/startRegister这页面上配置的,那么你用于加密的url也要与此相同。

the permission value is offline verifying 错误

这个错误是因为config没有正确执行,或者是调用的JSAPI没有传入config的jsApiList参数中。建议按如下顺序检查:

确认config正确通过。
如果是在页面加载好时就调用了JSAPI,则必须写在wx.ready的回调中。
确认config的jsApiList参数包含了这个JSAPI。

permission denied 错误

该公众号没有权限使用这个JSAPI,或者是调用的JSAPI没有传入config的jsApiList参数中(部分接口需要认证之后才能使用)。

function not exist 错误

当前客户端版本不支持该接口,请升级到新版体验。

本人实例代码:

前台部分

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

$(function share() {
        wx.config({
            debug:true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId : \'${WXConfig.appId}\', // 必填,企业号的唯一标识,此处填写企业号corpid
            timestamp:${WXConfig.timestamp}, // 必填,生成签名的时间
            nonceStr : \'${WXConfig.nonceStr}\', // 必填,生成签名的随机串
            signature : \'${WXConfig.signature}\',// 必填,签名,见附录1
            jsApiList:${WXConfig.jsApiList} // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
        });
        wx.ready(function() {
            alert("readyOK");
            // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
        });
        wx.error(function(res) {
            alert("err:" + res.val());
            // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
        });
    });

后台部分

@RequestMapping(value = "/sharePage")
    public String thCarSharePage(Map<String, Object> map) throws Exception {
        String nonceStr = THCarUtils.getARandomString();
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        String signature = WeiXinUtils.getWXSignature(WeiXinUtils.WEIXIN_JSAPI_TICKET, nonceStr, timestamp, SHARE_URL);
        WXJSConfig config = new WXJSConfig(WeiXinUtils.APPID, SHARE_URL, timestamp, nonceStr, signature,
                "[\'onMenuShareTimeline\', \'onMenuShareAppMessage\']");
        map.put("WXConfig", config);
        return "share/sharePage";
    }

其中WXJSConfig是自己封装的类,里面的属性与配置一致,我就不给出了。

看到这,你可能又会因为获取ACCESS_TOKEN和JSAPI_TICKET而犯愁。在官方文档中对应这两个值给出了限制,意味着你每天获取它们的次数是有上限的,我们不可以每次请求都获取一次,我们需要对它们进行缓存,你可以将其保存在数据库中,也可以直接放在内存中。下面是个人的方式,仅供参考,可能不是很合理。

public class WeiXinUtils {

public static String WEIXIN_TOKEN = "";// 注意微信TOKEN值得有效期为2小时。每日上限调用2000此,所有我们设每个小时调用一次
public static String WEIXIN_JSAPI_TICKET = "";
public static final String APPID = "wxe2b46f1dbc599123";
private static final String SECRET = "87j3a7f8f5n86764b78d8769298187c33";
private static final long TIME = 6000000;// 毫秒 ,100分钟
// private static final long TIME = 10000;
private static int i = 0;
private static boolean haveStart = false;

static {
    System.out.println("start get token");
    if (!haveStart) {// 确保只调用一次
        startChangeWXToken();
        haveStart = true;
    }
}

/**
 * 定时获取获取微信的Token值
 */
public static void startChangeWXToken() {
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            WeiXinUtils.WEIXIN_TOKEN = JSON
                    .parseObject(ThcHttpUtils.thcGet("https://api.weixin.qq.com/cgi-bin/token",
                            "grant_type=client_credential&appid=" + APPID + "&secret=" + SECRET))
                    .getString("access_token");
            startChangejsapiTicket();
        }
    };
    Timer timer = new Timer();
    timer.schedule(task, 0, TIME);
}

/**
 * 定时获取JSAPI_TICKET
 */
private static void startChangejsapiTicket() {
    boolean isOK = false;
    while (!isOK) {
        if (WEIXIN_TOKEN != null && !WEIXIN_TOKEN.isEmpty()) {
            WeiXinUtils.WEIXIN_JSAPI_TICKET = JSON
                    .parseObject(ThcHttpUtils.thcGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket",
                            "access_token=" + WEIXIN_TOKEN + "&type=jsapi"))
                    .getString("ticket");
            isOK = true;
        }
    }

}
}

上面的APPID与SECRET是虚构的。上面通过定时器的方式每100分钟会调用一次方法,更新TOKEN与TICKET的值。
为了让项目部署到服务器上就是其有值,本人使用了静态块的方式,并在bean中进行声明。

<bean id="WXUtils" class="com.lihetech.thcar.util.WeiXinUtils"/>

上面这些是个人在微信开发过程中的小小总结。写的比较粗糙,希望对你由帮助。您在开发中你要确保相关公众号是正常的,相关权限有开通。所使用的域名与你在公众号中设置的一致。

 

分类:

技术点:

相关文章: