微信公众号开发--微信JS-SDK扫一扫功能
首先请阅读微信JS-SDK说明文档,了解微信JS的相关说明。
根据官方的使用步骤,关键的有以下几步
- 绑定域名(很关键)
- 引入JS文件(很简单)
- 通过config接口注入权限验证配置(很重要)
- 通过ready接口处理成功验证(还没用到)
- 通过error接口处理失败验证(还没用到)
绑定域名
1首先到微信公众号设置里面添加js安全域名
比如我的域名是带有二级目录的:dev.xxx.com/muyang
那么在填入的时候域名为:dev.xxx.com/muyang
2.扫码调用页面时提交的url地址,一定要跟扫码页面的url保持一直,多或者少一个“/”都不行
例如,我扫码页面地址:dev.xxx.com/muyang/cat/
那么提交给签名的url地址也必须要是: dev.xxx.com/muyang/cat/
否则会报错:
{“errMsg”:”config:invalid SignPackage”}
所以,域名配置的时候一定要注意
1. 域名不要以http:开头
2. 域名不要配置到具体的页面
配置成功的提示如下
开发:
1,在页面引入:<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
并且开启debug: true,bug提示模式
jsApiList:调用为扫码模块:scanQRCode
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>行李查询</title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Bootstrap 3.3.7 --> <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> <style> html,body{ height:100%; font-size:14px; font-family:"Microsoft YaHei","Helvetica",sans-serif } .login-box-body, .register-box-body { width:90%; background: #fff; padding: 20px; border: 1px #D5D5D5 solid; color: #666; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; margin: 0 auto; } .login-box, .register-box { width: 360px; position: absolute; left: 50%; margin-left: -180px; top: 50%; margin-top: -200px; text-align: center; } .login-logo{ padding-right:20px; background:url("<?php echo $base_url;?>/images/sao.png") no-repeat scroll left center transparent; height: 30px; padding-left: 35px; } * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } a,a:link{ text-decoration: none; color: #808080; } .col-xs-12{width:100%} .has-feedback img{ width:150px;height:50px; } </style> </head> <body class="hold-transition login-page " style="background:url(<?php echo $base_url;?>img/loginbg.png) left top no-repeat;background-size:cover;overflow:hidden;position:relative"> <div class="login-box "> <!-- /.login-logo --> <div class="login-box-body "> <div class="login-logo " style="color:#4f4f4f;font-size:20px;position:relative; color: #808080;"> <a id="scanQRCode" url="<?php echo $base_url;?>/index/result">扫一扫行李牌条形码查询</a> </div> <!-- /.login-box-body --> </div> <!-- /.login-box --> </div> <div id="wm_id"></div> <!-- jQuery 2.2.3 --> <script> wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: ‘<?php echo $jsApi[‘appId‘];?>‘, // 必填,公众号的唯一标识 timestamp: ‘<?php echo $jsApi[‘timestamp‘];?>‘, // 必填,生成签名的时间戳 nonceStr: ‘<?php echo $jsApi[‘nonceStr‘];?>‘, // 必填,生成签名的随机串 signature: ‘<?php echo $jsApi[‘signature‘];?>‘,// 必填,签名,见附录1 jsApiList: [‘scanQRCode‘] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); // wx.error(function(res) { // alert("出错了:" + res.errMsg); // }); wx.ready(function() { // wx.checkJsApi({ // jsApiList : [‘scanQRCode‘], // success : function(res) { // alert("检验:" + res.errMsg); // } // }); //扫描二维码 document.querySelector(‘#scanQRCode‘).onclick = function() { wx.scanQRCode({ needResult : 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, scanType : [ "qrCode", "barCode" ], // 可以指定扫二维码还是一维码,默认二者都有 success : function(res) { var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果 document.getElementById("wm_id").value = result;//将扫描的结果赋予到jsp对应值上 if(result.length > 0) { var QRCodeStr = result.split(",") //alert(‘<?php echo $base_url;?>/index/result?code=‘+QRCodeStr[1]); window.location.href=‘<?php echo $base_url;?>/index/result?code=‘+QRCodeStr[1]; }else{ alert("扫描失败::扫描码=" + result); } } }); };//end_document_scanQRCode });//end_ready </script> </body> </html>
通过config接口注入权限验证配置
这一步非常重要,也是最关键的一步,这一部分
先看官方的示例
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: ‘‘, // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: ‘‘, // 必填,生成签名的随机串 signature: ‘‘,// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
这里需要从服务器端网页面传递的参数有timestamp、nonceStr和signature而appId和jsApiList都是固定的,这里直接写在页面中。
首先,编写服务器端代码,生成timestamp、nonceStr和signature。
在生成timestamp、nonceStr和signature的时候有两个参数需要获取
一个是access_token,另一个是jsapi_ticket。
access_token的获取需要AppId和AppSecret,获取地址如下,发送GET请求
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
通过HttpClient发送http请求就可以获取到access_token
得到access_token之后,采用http GET方式请求获得jsapi_ticket
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
注意,access_token和jsapi_ticket得有效期为7200秒,开发者必须在自己的服务全局缓存
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
我的获取ticket/jsapi , token的php代码
用redis缓存,把token,jsapi_ticket存储起来
/****************************js api 相关*********************************/ public function getToken() { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . WxConfig::$APPID . "&secret=" . WxConfig::$APPSECRET); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_USERAGENT, ‘Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)‘); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $tmpInfo = curl_exec($ch); if (curl_errno($ch)) { //echo ‘access_token curl error‘ . PHP_EOL; } if(empty($tmpInfo)){ //echo "no back"; } $tmpInfo = json_decode($tmpInfo); if (isset($tmpInfo->errcode)) { // 获取token失败 //echo ‘access_token error‘ . PHP_EOL; } else { //echo ‘access_token ok‘ . PHP_EOL; $this->redis->setex(WxConfig::$APPID."_token", 7200, $tmpInfo->access_token); } } private function getJsapiTicket($access_token) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" . $access_token); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_USERAGENT, ‘Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)‘); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $tmpInfo = curl_exec($ch); if (curl_errno($ch)) { //echo ‘js api ticket curl error‘ . PHP_EOL; } $tmpInfo = json_decode($tmpInfo); if (isset($tmpInfo->errcode) && $tmpInfo->errcode != 0) { // 获取token失败 //echo ‘js api ticket error‘ . PHP_EOL; } else { //echo ‘js api ticket ok‘ . PHP_EOL; $this->redis->setex(WxConfig::$APPID."_jsapi", 7200, $tmpInfo->ticket); } } /** * 获取指定长度的随机字符串 * @param number $length * @return string */ private function createNonceStr($length = 16) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } /** * 获取js api config方法的签名 * @return String */ public function getSignPackage() { //jsapi $jsapitTicket = $this->redis->get(WxConfig::$APPID."_jsapi"); $url = $this->config->baseUrl.‘/‘; $timestamp = time(); $nonceStr = $this->createNonceStr(); // 这里参数的顺序要按照 key 值 ASCII 码升序排序 $string = "jsapi_ticket=$jsapitTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; $signature = sha1($string); $signpackage = array( "appId" => WxConfig::$APPID, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signpackage; } /****************************js api 相关*********************************/
然后自动判断token/jsapi_ticket是否过期:
$access_token = $this->redis->get(WxConfig::$APPID."_token"); if(empty($access_token)) { //已过期 $access_token = ‘‘; $this->getToken(); $access_token = $this->redis->get(WxConfig::$APPID."_token"); $this->getJsapiTicket($access_token); }else if(!empty($access_token)) { $this->getJsapiTicket($access_token); }