微信公众号开发--微信JS-SDK扫一扫功能

首先请阅读微信JS-SDK说明文档,了解微信JS的相关说明。 
根据官方的使用步骤,关键的有以下几步

  1. 绑定域名(很关键
  2. 引入JS文件(很简单)
  3. 通过config接口注入权限验证配置(很重要
  4. 通过ready接口处理成功验证(还没用到)
  5. 通过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&timestamp=$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);
        }

  

04-19 01:18