微信开放的JS-SDK面向网页开发者提供了基于微信内的网页开发工具包,最直接的好处就是我们可以使用微信分享、扫一扫、卡券、支付等微信特有的能力。7月份的时候,因为这个分享的证书获取问题深深的栽了一坑,后面看到“config:ok”的时候真的算是石头落地,瞬间感觉世界很美好..

这篇文章是微信开发的很多前置条件,包括了服务端基于JAVA的获取和缓存全局的access_token,获取和缓存全局的jsapi_ticket,以及前端配置授权组件封装,调用分享组件封装。

配置授权思路:首先根据access_token获取jsapi_ticket,在通过获取到的jsapi_ticket以及随机生成的字符串、时间戳,再加上需要授权的页面地址url,进行SHA-1加密,返回加密字符串,最后根据加密串调用微信提供的config接口。

配置JS接口安全域名

公众平台--公众号设置--功能设置--js接口安全域名

获取、缓存全局的access_token

  /**
* 微信全局票据 ---->>>> access_token
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public String getBaseAccessToken() throws ClientProtocolException, IOException{ try {
String value = redisService.get("WEIXIN_BASE_ACCESS_TOKEN");
if (!StringUtils.isEmpty(value)) {
LOGGER.info("Get base access_token from redis is successful.value:{}",value);
return value;
}else{
synchronized (this) {
//缓存中没有、或已经失效
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+WX_APPID+"&secret="+ WX_APPSECRET;
String rs = apiService.doGet(url); JSONObject obj_content = JSONObject.parseObject(rs);
String accessToken = obj_content.getString("access_token");
Integer time = Integer.parseInt(obj_content.getString("expires_in").toString()); //写缓存
redisService.set("WEIXIN_BASE_ACCESS_TOKEN", accessToken, time - 3600);
LOGGER.info("Set base access_token to redis is successful.parameters time:{},realtime",time,time-3600);
return accessToken;
}
}
} catch (Exception e) {
LOGGER.error("Get base access_token from redis is error.");
}
return null;
}

先从缓存中取key为“WX_BASE_ACCESS_TOKEN” ,如果命中直接返回值,反之通过httpclient发送GET请求调用微信提供的接口获取全局的access_token,同时将取到的值写入缓存。

获取、缓存全局的jsapi_ticket

  /**
* jsapi_ticket是公众号用于调用微信JS接口的临时票据
* @return
* @throws IOException
* @throws ClientProtocolException
*/
public String getJsapiTicket() throws ClientProtocolException, IOException{
try {
String value = redisService.get("WEIXIN_JS_API_TICKET");
if (!StringUtils.isEmpty(value)) {
return value;
}else{
synchronized (this) {
//缓存中没有、或已经失效
//获取全局的access_token,唯一票据
String accessToken = getBaseAccessToken(); String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ accessToken +"&type=jsapi"; String rs = apiService.doGet(url); JSONObject obj_content = JSONObject.parseObject(rs);
String jsapi_ticket = obj_content.getString("ticket");
Integer time = Integer.parseInt(obj_content.getString("expires_in").toString()); //写缓存
redisService.set("WEIXIN_JS_API_TICKET", jsapi_ticket, time - 3600); return jsapi_ticket;
}
}
} catch (Exception e) {
LOGGER.error("Get js_api_ticket from redis is error:{}",e);
} return null;
}

由于获取jsapi_ticket微信有100000次限制,所以必须用上缓存。同理获取access_token,我这里为了保险起见缓存失效时间设置为官方提供的时间再减去一个小时。

jssdk加密串获取restful

1.Controller

  /**
* 微信分享证书获取
* @param
* @return signature
* @throws IOException
*/
@RequestMapping(value = "/signature", method = RequestMethod.GET)
public @ResponseBody String createSignature(
@RequestParam String url) throws IOException{ LOGGER.info("RestFul of createSignature parameters url:{}",url); try {
String rs = wechatService.createSignature(url);
LOGGER.info("RestFul of signature is successful.",rs); return rs;
} catch (Exception e) {
LOGGER.error("RestFul of signature is error.",e);
} return null;
}

2.Service

  /**
* 根据jsapi_ticket等参数进行SHA1加密
* @param nonceStr 随机字符串
* @param timestamp 当前时间戳
* @param url 当前页面url
*/
public String createSignature(String url) throws ClientProtocolException, IOException{
String nonceStr = create_nonce_str();
String timestamp = create_timestamp(); String signature = "jsapi_ticket="+getJsapiTicket();
signature += "&noncestr="+nonceStr;
signature += "&timestamp="+timestamp;
signature += "&url="+url; try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(signature.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
} catch (Exception e) {
LOGGER.error("Signature for SHA-1 is error:{}",e);
} Map<String, String> map = new HashMap<String, String>();
map.put("timestamp", timestamp);
map.put("nonceStr", nonceStr);
map.put("signature", signature);
map.put("appid", WX_APPID);
return JSON.toJSONString(map, true);
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
WX_APPID为公众号appid,通过spring@value注解从配置文件获取,这里不细说。

3.生成随机字符串

private static String create_nonce_str() {
return UUID.randomUUID().toString();
}

4.时间格式化

private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}

到此为止后台全部完成,其实没有太多的解释,仔细读一遍代码,可读性应该还行!

封装获取授权组件,实现分享方法

require.config({
urlArgs: "v=20161116" ,
baseUrl : "/static",
paths: {
jweixin: 'component/jweixin/jweixin-1.0.0',
share: 'component/wechat/share'//微信分享组件
}
})

首先通过调用后台接口获取加密字符串,调用微信提供的wx.config()方法

  //jsSDK授权
$.signature = function(wx,opts,currentUrl,callback){ $.ajax({
data: {url: currentUrl},
type: "GET",
url: WX_ROOT + "wechat/signature",
success: function (json) {
if (json) {
var data = JSON.parse(json); wx.config({
debug: false,
appId: data.appid,
timestamp: data.timestamp,
nonceStr: data.nonceStr,
signature: data.signature,
jsApiList: [
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone'
]
}); wechatShare.options.isSignature = true; callback && callback(opts,wx);
}
}
});
}

建议:开发环境建议开启调式模式,方便打印日志定位问题debug: true

所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,我这里用一个全局变量isSignature缓存了是否已经配置授权,然后执行回调。如实现分享接口:

  //分享
$.share = function(opts,wx) {
var options = {
currentUrl: window.location.href.split('#')[0],
imgUrl: null,
title: '达农保险',
desc: null,
shareUrl: null
} $.extend(true, options, opts || {}); //判断是否已经授权
if(!wechatShare.options.isSignature){
$.signature(wx,opts,options.currentUrl,$.share)
}else{
wx.ready(function(){
//分享到朋友圈
wx.onMenuShareTimeline({
title: options.title,
link: options.shareUrl,
imgUrl: options.imgUrl,
success: function () {
//分享统计,分享来源 1 朋友圈 2分享给朋友 3分享到QQ 4分享到QQ空间 }
}); //分享给朋友
wx.onMenuShareAppMessage({
title: options.title,
desc: options.desc,
link: options.shareUrl,
imgUrl: options.imgUrl
});
});
} }

我先确认是否已经配置授权,如果没有授权则调用$.signature()回调函数里传入$.share,有点类似递归调用,当再次回到share方法的时候isSignature已经是true了,则执行wx.ready()方法,再调需要调用的接口,微信开放提供了很多接口给我们,分享只是其中一个。只有想不到的,没有实现不了的....

注意:currentUrl 必须是动态获取的,通过window.location.href方法,因为页面分享,微信客户端会在你的链接末尾加入其它参数,所以需要再将url用‘#’割一下,取第一个,如果有中文最好是用encodeURIComponent转义一下,保证签名获取成功。如果报invalid signature,大部分原因是传入的url,和加密算法的问题,仔细检查!

调用:

var ua = navigator.userAgent.toLowerCase(),
isWechat = ua.indexOf('micromessenger') != -1;//判断是否为微信浏览器
var shareData = {
    title: ‘测试分享’,
    desc: ‘这里是描述,分享到朋友圈不会显示’,
    link: APP_ROOT + '/base/downloadApp,//分享后打开的链接,必须在配置的安全域名下
    imgUrl: PIC_PATH + (self.data.shareListData[0].imgSmall || '/static/img/coupon/getTicPic.png'),//分享后显示的图片
    success: function(){
                      setTimeout(function(){
              //运营数据统计
             },0)//伪异步方式调用
}
        }
//微信浏览器分享加载
if(isWechat){
 require(['jweixin'],function(wx){
    require(['share'],function(){
$.share(shareData,wx);
    })
  })
}   

完整js:https://github.com/helijun/component/blob/master/wechat/share.js

常用问题总结:

最开始做这个分享功能的时候,因为一个证书获取失败的原因(invalid signature)真的是断断续续困了好几天,有的时候真的是毫无头绪了。反复检查代码,逐字逐行的看,真的没有发现任何异常,通过微信提供的一个js接口签名校验工具测试也是返回ture,然而就是报证书失败!微信官方文档又有点模棱两可,到最后星期六的一个下午,静下心来,再耐心的检查了一遍后台SHA1加密算法,终于看到config true..  曙光

开发中我们总是会遇到各种各样的问题,程序员和bug永远都是好朋友同时又是敌人,我们总是徘徊在bug的边缘,有时候当遇到很奇怪的问题的时候不妨先放一下,注意力先转移一下,去阳台吹吹风,说不定在某一个时刻,问题突然就解开了..

接口签名校验工具

https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

微信JS SDK配置授权,实现分享接口的更多相关文章

  1. 微信JS SDK接入的几点注意事项

    微信JS SDK接入,主要可以先参考官网说明文档,总结起来有几个步骤: 1.绑定域名:先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”.备注:登录后可在“开发者中心”查看对 ...

  2. 实战微信JS SDK开发:贺卡制作与播放(1)

    前段时间忙于CanTK 2.0的开发,所以博客一直没有更新.CanTK 2.0主要增强了游戏和富媒体的开发,现在编码和测试基本完成了,等文档完成了再正式发布,里面有不少激动人心的功能,等发布时再一一细 ...

  3. 微信js sdk上传多张图片

    微信js sdk上传多张图片,微信上传多张图片 该案例已tp3.2商城为例 直接上代码: php代码: public function ind(){ $appid="111111111111 ...

  4. 微信开发(2):微信js sdk分享朋友圈,朋友,获取config接口注入权限验证(转)

    进行微信开发已经一阵子了,从最初的什么也不懂,到微信授权登录,分享,更改底部菜单,素材管理,等. 今天记录一下微信jssdk 的分享给朋友的功能,获取config接口注入. 官方文档走一下简单说:四步 ...

  5. 微信js SDK接口

    微信JS-SDK说明文档 http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html 一.微信登录功能 在进行微信OAut ...

  6. 微信js sdk分享开发摘记java版

    绑定域名和引入js的就不说了 废话不说直接上代码 public void share(HttpServletRequest request) throws Exception { StringBuff ...

  7. 微信JS SDK Demo 官方案例[转]

    摘要: 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用 ...

  8. 微信JS SDK Demo

    微信JS-SDK 分享到朋友圈 分享给朋友 分享到QQ 拍照或从手机相册中选图 识别音频并返回识别结果 使用微信内置地图查看位置原文:http://www.cnblogs.com/txw1958/p/ ...

  9. 微信JS SDK Demo 官方案例

    微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用微信分享 ...

随机推荐

  1. 字符串 中的split 与数组中的join

    关于基础,总是隔一段时间,就得看一次,要不不用总是忘,今天又重新看了,一下字符串对象的split,然后就想到了数组对象的join. var str='wo shi yi ge js'; var str ...

  2. MVC分页

    http://www.cnblogs.com/iamlilinfeng/p/4075292.html 目录 一.Contrl与View数据传递(多表数据) 二.分页控件介绍 三.MVC源码说明 四.源 ...

  3. 线程池 Threadpool (还需要补充)

    1.池(pool)是一种常见的提高性能的方式.有时创建和销毁一些资源是非常耗费时间的行为.我们会考虑在一个池内放一些资源,在用的时候拿,不够的时候添加,用完就归还,这样就可以避免不断的创建和销毁资源了 ...

  4. 《SQL必知必会》学习笔记(二)

    咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语句,但是实际应用中的业务逻辑往往会非常复杂,所 ...

  5. Windows下安装Oracle拖慢开机速度的解决方法

    环境:win7 + oracle R2 方法:将安装Oracle后自动开机启动的服务改为手动启动 步骤如下: 1.修改服务项 Ctrl + R,输入services.msc,打开服务列表,找到Orac ...

  6. leetcode--Maximum Subarray

    题目链接:https://leetcode.com/problems/maximum-subarray/ 算法类型:动态规划 题目分析:最大序列和 代码实现: class Solution(objec ...

  7. CSS背景background、background-position使用详解

    背景(background)是css中一个重要的的部分,也是需要知道的css的基础知识之一.这篇文章将会涉及css背景(background)的基本用法,包括诸如 background-attachm ...

  8. JavaScript - 正则表达式

    正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功:一旦有匹配不成功的字符则匹配失败. 正则表达式通常用于在文本中查找匹配的字符串.Python里数量词默 ...

  9. java程序员快速掌握python系列——概述

    这一系列主要是总结学习python过程中的方方面面(已经学完,时间大概是一周左右).当然限于个人水平java也就是够用,python短时间内也不可能深入到哪里去.所以这次的分享的目的是能够快速使用py ...

  10. SQL Server中查询数据库及表的信息语句

    /* -- 本文件主要是汇总了 Microsoft SQL Server 中有关数据库与表的相关信息查询语句. -- 下面的查询语句中一般给出两种查询方法, -- A方法访问系统表,适应于SQL 20 ...