首页 > 上网技巧 > 电脑小技巧 > 微信公众号H5开发调用微信 js-sdk的那些事

微信公众号H5开发调用微信 js-sdk的那些事

时间:2019-05-10 09:52 作者:QQ地带 我要评论

需求
如果你在开发微信H5页面,并且需要调用微信的js接口,特意总结了一下调用的过程
 
步骤
 一,绑定安全域名
登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”
注意:
   1.  需要从公众号管理平台中?#30053;?/u>校验凭证txt文本内容,然后上传至填写域名或路径指向的web服务器(或虚拟主机)的目录(若填写域名,将文件放置在域名根目录下,例如 wx.qq.com/MP_verify_1FKXuKnjqdNephyv.txt ;若填写路径,将文件放置在路径目录下,例如 wx.qq.com/mp/MP_verify_1FKXuKnjqdNephyv.txt ),并确保可以访问。
   2.  绑定域名的时候只填域名部分,必须经过 ICP备案,不需要http://协议前缀,不需要访问页面路径
    正确示例: www.baidu.com
    错误示例 :http://www.baidu.com , www.baidu.com/index
 
二、引入微信js-sdk文件
    在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.4.0.js
 
    如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持https)
 
三、获取wx.config()?#38382;?/div>
   在调用微信js-sdk接口之前,需要进行wx.config进行权限验证,如下是验证需要的?#38382;?/div>
 
wx.config({
    debug: true, // 开启调?#38405;?#24335;,调用的所有api的返回值会在客户端alert出来,若要查看传入的?#38382;?#21487;以在pc端打开,?#38382;?#20449;息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
});
 
    签名生成的步骤和jsApiList 列表微信文档中?#26657;?#35814;见链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 通过官方文档,我们知道,生成签名需要一个随机字符串nonceStr,一个时间戳timestamp,一个凭证jsapi_ticket,还有一个调用接口页面的url(包括http或https协议头和页面路径),随后还需要一个sha1?#29992;?#30340;算法
    这里,我只给大家分享一下生成签名的一些代码(java)
1. 首先,我们需要通过微信公众号的接口获取accessToken,调用微信接口来获取jsapi_ticket; 这时,我们需要的就是能够发送请求的工具,封装了一个HttpReq类:
 
public class HttpReq {
 
    public static String doGet(String url) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String result = "";
        try {
            // 通过址默认配置创建一个httpClient实例
            httpClient = HttpClients.createDefault();
            // 创建httpGet远程连接实例
            HttpGet httpGet = new HttpGet(url);
            // 设置请求头信息,鉴权
//            httpGet.setHeader("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
            // 设?#38376;?#32622;请求?#38382;?/div>
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 连接主机服务超时时间
                    .setConnectionRequestTimeout(35000)// 请求超时时间
                    .setSocketTimeout(60000)// 数据读取超时时间
                    .build();
            // 为httpGet实例设?#38376;?#32622;
            httpGet.setConfig(requestConfig);
            // 执行get请求得到返回对象
            response = httpClient.execute(httpGet);
            // 通过返回对象获取返回数据
            HttpEntity entity = response.getEntity();
            // 通过EntityUtils中的toString方法将结果转换为字符串
            result = EntityUtils.toString(entity);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
 
 
    public static String doPost(String url, Map<String, Object> paramMap) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        String result = "";
        // 创建httpClient实例
        httpClient = HttpClients.createDefault();
        // 创建httpPost远程连接实例
        HttpPost httpPost = new HttpPost(url);
        // 配置请求?#38382;?#23454;例
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 设置连接主机服务超时时间
                .setConnectionRequestTimeout(35000)// 设置连接请求超时时间
                .setSocketTimeout(60000)// 设置读取数据连接超时时间
                .build();
        // 为httpPost实例设?#38376;?#32622;
        httpPost.setConfig(requestConfig);
        // 设置请求头
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
        // 封装post请求?#38382;?/div>
        if (null != paramMap && paramMap.size() > 0) {
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            // 通过map集成entrySet方法获取entity
            Set<Map.Entry<String, Object>> entrySet = paramMap.entrySet();
            // 循环遍历,获取迭代器
            Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> mapEntry = iterator.next();
                nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString()));
            }
 
            // 为httpPost设置封装好的请求?#38382;?/div>
            try {
                httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        try {
            // httpClient对象执行post请求,并返回响应?#38382;?#23545;象
            httpResponse = httpClient.execute(httpPost);
            // 从响应对象中获取响应内容
            HttpEntity entity = httpResponse.getEntity();
            result = EntityUtils.toString(entity);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != httpResponse) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}
使用get或者post请求都可以调用,返回的结果是String类型,如果需要解析成JSONObject,需要使用JSONObject.parseObject();
 
获取到jsapi_ticket后,需要做一个变量的缓存(因为微信给我们提供的这个接口有调用?#38382;?#38480;制),这里我采用设置一个全局过期时间,如果过期了,就重新发送请求获取,(因为只有一个变量需要缓存,就没有使用其他框架来做缓存)大家也可以参考一下:
 
/**jsapi_ticket*/
private static String jsapiTicket;
 
/**jsapi_ticket过期时间*/
private static long jsapiTicketExpires;
 
    /**设置jsapiTicket*/
    private int setJsapiTicket(){
        long curTime = System.currentTimeMillis();
        if(curTime < jsapiTicketExpires && jsapiTicket != null){
            System.out.println("jsapiTicket 没有过期,不再重新获取!");
            return 1;
        }
        JSONObject accessTokenRes = getAccessToken(); //获取AccessToken的方法需要大家自己发送请求(涉及到业务方隐私)
        if(accessTokenRes == null){
            System.out.println("获取 accessToken 失败!");
            return 0;
        }
        String accessToken = accessTokenRes.getString("access_token");
        try{
            String res = HttpReq.doGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ accessToken +"&type=jsapi");
            JSONObject result = JSON.parseObject(res);
            if(result.getString("errmsg").equals("ok")){
                jsapiTicket = result.getString("ticket");
                jsapiTicketExpires = curTime + 7200*1000;
            }
 
        }catch (Exception e){
            System.out.println("error on get JsapiTicket ", e);
            return 0;
        }
        return 1;
    }
在获取全局变量jsapiTicket之前,需要进行一次setJsapiTicket,并根据其返回状态码进?#20449;?#26029;是否发送请求
 
/**设置jsapiTicket*/
int setTicketRes = setJsapiTicket();
if( setTicketRes == 0 || jsapiTicket == null){
  System.out.println("获取 jsapiTicket 失败!");
  return null;
}
String jsapi_ticket = jsapiTicket; //获取jsapi_ticket
2. 获取到jsapi_ticket之后,我们需要自己生成一个长度为16的随机字符串(官方文档里的随机字符串长度为16,所以这里生成长度为16的),具体生成代码如下:
 
public class RandomStr {
 
    private static char ch[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
            'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
            'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
            'x', 'y', 'z', '0', '1' };//最后又重复两个0和1,因为需要凑足数组长度为64
 
    private static Random random = new Random();
 
    //生成指定长度的随机字符串
    public static  String createRandomString(int length) {
        if (length > 0) {
            int index = 0;
            char[] temp = new char[length];
            int num = random.nextInt();
            for (int i = 0; i < length % 5; i++) {
                temp[index++] = ch[num & 63];//取后面六位,记得对应的二进制?#19988;?#34917;码?#38382;?#23384;在的。
                num >>= 6;//63的二进制为:111111
                // 为什么要右移6位?因为数组里面一共有64个?#34892;?#23383;符。为什么要除5取余?因为一个int型要用4个字节表示,也就是32位。
            }
            for (int i = 0; i < length / 5; i++) {
                num = random.nextInt();
                for (int j = 0; j < 5; j++) {
                    temp[index++] = ch[num & 63];
                    num >>= 6;
                }
            }
            return new String(temp, 0, length);
        }
        else if (length == 0) {
            return "";
        }
        else {
            throw new IllegalArgumentException();
        }
    }
 
    public static void main(String[] args) {
        System.out.println(createRandomString(16));
    }
}
调用RandomStr类的静态方法createRandomString,传入你需要创建随机字符串的长度,即可生成
 
3. 生成当前时间的秒数(timestamp):
 
//生成的时间戳单位为毫秒,除以1000变为秒数
long timestamp = System.currentTimeMillis() / 1000;
4. ?#20945;?#25351;定顺序拼接字符串,然后使用sha1算法生成签名(注意:拼接的字符串必须是如下顺序  "jsapi_ticket="+ jsapi_ticket +"&noncestr="+ noncestr +"&timestamp="+ timestamp +"&url="+url)
 
long timestamp = System.currentTimeMillis() / 1000;    //当前的时间戳(秒)
String noncestr = RandomStr.createRandomString(16);    //长度为16的随机字符串
String url = "----"; //需要调用sdk的页面路径
String jsapi_ticket = jsapiTicket;    //通过调用微信接口生成的jsapi_ticket
/**?#29992;?#23383;符串*/
String str = "jsapi_ticket="+ jsapi_ticket +"&noncestr="+ noncestr +"&timestamp="+ timestamp +"&url="+url;
/**通过?#29992;?#25340;接的字符串获取签名*/
String signature = Sha1.encode(str);    //signature即为生成的签名,Sha1算法代码见下方
sha1算法的代码如下:
 
public class Sha1 {
 
    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        // 把密文转换成十六进制的字符串?#38382;?/div>
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }
 
    public static String encode(String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
            messageDigest.update(str.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
如此一来,我们需要的签名,生成签名的时间戳和随机字符串都有了,前台通过调用Controller就可以直接获取到,然后进行wx.config()即可进行授权验证;
 
四、调用wx.config()来做微信接口调用的验证
在conroller 中添加一个请求,用来调用以上代码model得到签名(signature)、生成签名的时间戳(timestamp)和字符串(nonceStr)
 
然后在前台需要调用微信接口的页面中调用,拿到对应?#38382;?#28982;后进行wx.config(),校验成功后就可以在wx.ready()的回调中调用微信的接口了;(以微信扫一扫为例)
 
$.ajax({
    type:"post",
    url:"/getWxConfig.do",  //获取wx.config 相关信息
    success:function(result){
       console.log(result)
       wx.config({
            // 开启调?#38405;?#24335;,调用的所有api的返回值会在客户端alert出来,若要查看传入的?#38382;?#21487;以在pc端打开,?#38382;?#20449;息会通过log打出,仅在pc端时才会打印。
            debug: false,
            // 必填,公众号的唯一标识
            appId: result.data.appId,
            // 必填,生成签名的时间戳
            timestamp: result.data.timestamp,
            // 必填,生成签名的随机串
            nonceStr:result.data.nonceStr,
            // 必填,签名,见附录1
            signature:result.data.signature,
            // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
            jsApiList : ['scanQRCode' ]
        });
    },
    error : function(err){
        console.error(err)
    }
})
 
/**wx.config()错误后的返回信息*/
wx.error(function(res) {
    console.log("出错了:" + res.errMsg);
});
 
/**微信准备好之后,所有调用微信接口的内容需要放到这里*/
wx.ready(function() {
    //点击按钮扫描二维码
    $('#scanQRCode').on('click',function(){
        wx.scanQRCode({
            needResult : 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
            scanType : [ "qrCode"], // 可以指定扫二维码还?#19988;?#32500;码,默认二者都有
            success : function(res) {
                console.log(res);   //扫码的结果
            }
        });
    })
});
最后,大功告成!
 

标签: 微信公众号
顶一下
(0)
0%
踩一下
(0)
0%

Google提供的广告

天天炫斗2019更新公告
拳皇98ol刷钻教程视频 双色球合买的规则 捕鱼游戏搭建 国王vs 快乐8开奖软件 巴塞罗那赫罗纳 fg美人捕鱼作弊 钻石帝国客服 海底总动员免费版 狂野女巫横扫峡谷