本文講述C#開發微信門戶及應用使用微信JSSDK實現簽到功能的介紹
隨著微信開逐步開放更多JSSDK的接口,我們可以利用自訂網頁的方式來調用更多微信的接口,實現我們更加豐富的界面功能和效果,例如我們可以在頁面中調用各種手機的硬體來獲取信息,如攝像頭拍照,GPS信息、掃描二維碼等等,本篇介紹如何利用這些JSSDK介面實現簽到的功能,其中簽到需要報送地理座標和地址,調用攝影機即時拍照,以及獲取當前用戶的相關資訊等等。
1、JSSDK的說明
微信JS-SDK是微信公眾平台提供給網頁開發者的基於微信內的網頁開發工具包。透過使用微信JS-SDK,網頁開發者可藉助微信有效地使用拍照、選圖、語音、位置等手機系統的能力,同時可以直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,為微信使用者提供更優質的網頁體驗。
目前JSSDK支援的介面分類包括以下幾類:基礎介面、分享介面、影像介面、音訊介面、智慧型介面、裝置資訊、地理位置、搖晃週邊、介面操作、微信掃一掃、微信小店、微信卡券、微信支付,隨著微信功能的全部整合,估計更多的介面會陸續開放出來。
在微信的後台進入【開發者文件】模組,我們可以看到對應的JSSDK的功能分類和介紹,如下所示。
從右側我們可以詳細看到各個介面的使用說明,基本上JSSDK的使用方法都類似,因此調試通過並掌握其中一兩個,其他的也就依葫蘆畫瓢,照著做就可以了。
1)JSSDK使用步驟
步驟一:綁定網域名稱
#先登入微信公眾平台進入「公眾號設定」的「功能設定」裡填寫「JS接口安全域名」。如下圖所示,在公眾平台進行設定。
備註:登入後可在「開發者中心」查看對應的介面權限。
步驟二:引入JS檔案
在需要呼叫JS介面的頁面引入如下JS文件,(支援https):http://res.wx.qq .com/open/js/jweixin-1.0.0.js
如需使用搖搖週邊功能,請引入http://res.wx.qq.com/open/js/jweixin-1.1 .0.js
備註:支援使用AMD/CMD 標準模組載入方法載入
#當然,我們一般編輯頁面,為了方便實現更多的效果,可能還會引入其他JS,如JQuery的類別庫等等。還有,我們還可以基於WeUI的jquery-weui類別庫,實現更豐富的功能,如下是我們案例程式碼裡面的JS引用。
<script src="~/Content/wechat/jquery-weui/lib/jquery-2.1.4.js"></script> <script src="~/Content/wechat/jquery-weui/js/jquery-weui.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.1.0.js"></script>
步驟三:透過config介面注入權限驗證設定
所有需要使用JS-SDK的頁面必須先註入設定訊息,否則將無法呼叫(同一個url只需呼叫一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支援pushState的H5新特性,所以使用pushState來實現web app的頁面會導致簽名失敗,此問題會在Android6 .2中修復)。
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
以上的設定就是JSSDK的核心所在,裡面需要配置好對應的appid,還有timestamp,nonceStr這些都沒有特別之處,最值得注意的是signature的實作機制,這樣我們在後台產生好對應的值,賦給JS頁面就可以了,這樣也是最安全的做法。
如下程式碼是我們實際專案裡面,在Asp.net的視圖頁裡面的HTML程式碼,如下所示。
<script language="javascript"> var appid = '@ViewBag.appid'; var noncestr = '@ViewBag.noncestr'; var signature = '@ViewBag.signature'; var timestamp = '@ViewBag.timestamp'; wx.config({ debug: false, appId: appid, // 必填,公众号的唯一标识 timestamp: timestamp, // 必填,生成签名的时间戳 nonceStr: noncestr, // 必填,生成签名的随机串 signature: signature, // 必填,签名,见附录1 jsApiList: [ 'checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'translateVoice', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'onVoicePlayEnd', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard' ] });
步驟四:透過ready接口處理成功驗證
wx.ready(function(){ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口, //则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 });
這個ready的接口,也就是在頁面順利加載完畢後的處理內容了,一般我們需要做很多操作,都是需要在頁面載入完畢後才能呼叫相關的物件進行賦值、處理等操作。
例如我們在頁面ready後,取得對應的GPS座標等操作,可以用下面的JS程式碼實現。
wx.ready(function () { wx.getLocation({ type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 $("#lblLoacation").text(latitude + "," + longitude); } }); });
步驟五:透過error介面處理失敗驗證
wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看, // 也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 });
這個error介面也就是用來處理例外訊息的,一般情況下可以在這裡提示使用者出現的錯誤。
2)、簽章演算法
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg timestamp=1414587457 url=http://mp.weixin.qq.com?params=value
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
2.签名用的url必须是调用JS接口页面的完整URL。
3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
如出现invalid signature 等错误详见附录5常见错误及解决办法。
以上就是JSSDK总体的使用流程,虽然看起来比较抽象,但是基本上也就是这些步骤了。
上面的过程是具体的参数处理逻辑,我们要对应到C#代码的签名实现,需要对几个变量进行处理,下面是对应的生成noncestr、timestamp、以及签名等操作的代码。
/// <summary> /// 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 /// </summary> /// <returns>时间戳</returns> private static string GetTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /// <summary> /// 生成随机串,随机串包含字母或数字 /// </summary> /// <returns>随机串</returns> private static string GetNonceStr() { return Guid.NewGuid().ToString().Replace("-", ""); }
还有我们要实现JSSDK签名的处理,必须先根据几个变量,构建好URL字符串,具体的处理过程,我们可以把它们逐一放在一个Hashtable里面,如下代码所示。
/// <summary> /// 获取JSSDK所需要的参数信息,返回Hashtable结合 /// </summary> /// <param name="appId">微信AppID</param> /// <param name="jsTicket">根据Token获取到的JSSDK ticket</param> /// <param name="url">页面URL</param> /// <returns></returns> public static Hashtable GetParameters(string appId, string jsTicket, string url) { string timestamp = GetTimeStamp(); string nonceStr = GetNonceStr(); // 这里参数的顺序要按照 key 值 ASCII 码升序排序 string rawstring = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + ""; string signature = GetSignature(rawstring); Hashtable signPackage = new Hashtable(); signPackage.Add("appid", appId); signPackage.Add("noncestr", nonceStr); signPackage.Add("timestamp", timestamp); signPackage.Add("url", url); signPackage.Add("signature", signature); signPackage.Add("jsapi_ticket", jsTicket); signPackage.Add("rawstring", rawstring); return signPackage; }
我们注意到URL参数的字符串组合:
string rawstring = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + "";
这里我们拼接好URL参数后,就需要使用签名的规则来实现签名的处理了,签名的代码如下所示,注释代码和上面代码等同。
/// <summary> /// 使用SHA1哈希加密算法生成签名 /// </summary> /// <param name="rawstring">待处理的字符串</param> /// <returns></returns> private static string GetSignature(string rawstring) { return FormsAuthentication.HashPasswordForStoringInConfigFile(rawstring, "SHA1").ToLower(); ////下面和上面代码等价 //SHA1 sha1 = new SHA1CryptoServiceProvider(); //byte[] bytes_sha1_in = System.Text.UTF8Encoding.Default.GetBytes(rawstring); //byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in); //string signature = BitConverter.ToString(bytes_sha1_out); //signature = signature.Replace("-", "").ToLower(); //return signature; }
这样我们有了对应的值后,我们就可以把它们的参数全部放在集合里面了供使用。
/// <summary> /// 获取用于JS-SDK的相关参数列表(该方法对accessToken和JSTicket都进行了指定时间的缓存处理,多次调用不会重复生成) /// 集合里面包括jsapi_ticket、noncestr、timestamp、url、signature、appid、rawstring /// </summary> /// <param name="appid">应用ID</param> /// <param name="appSecret">开发者凭据</param> /// <param name="url">页面URL</param> /// <returns></returns> public Hashtable GetJSAPI_Parameters(string appid, string appSecret, string url) { string accessToken = GetAccessToken(appid, appSecret); string jsTicket = GetJSAPI_Ticket(accessToken); return JSSDKHelper.GetParameters(appid, jsTicket, url); }
下面我们通过具体的代码案例来介绍使用的过程。
2、签到功能的实现处理
其实签到,都可以在微信公众号和企业号实现,微信的企业号可能实现更佳一些,不过他们使用JSSDK的接口操作是一样的,我们可以拓展过去就可以了。这里介绍微信公众号JSSDK实现签到的功能处理。
签到的功能,我们希望记录用户的GPS位置信息,还有就是利用拍照功能,拍一个照片同时上传到服务器,这样我们就可以实现整个业务效果了。
首先我们来设计签到的界面,代码及效果如下所示。
界面预览效果如下所示:
我们来看看微信JSSDK里面对于【获取地理位置接口】的说明:
wx.getLocation({ type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 } });
以及图形接口里面【拍照或从手机相册中选图接口】的说明:
wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片 } });
上传图片到微信服务器接口如下所示。
wx.uploadImage({ localId: '', // 需要上传的图片的本地ID,由chooseImage接口获得 isShowProgressTips: 1, // 默认为1,显示进度提示 success: function (res) { var serverId = res.serverId; // 返回图片的服务器端ID } });
备注:上传图片有效期3天,可用微信多媒体接口下载图片到自己的服务器,此处获得的 serverId 即 media_id。
根据这几个接口,我们来对它们进行包装,以实现我们的业务需求。根据我们的需要,我们对JSSDK接口进行了调用,如下所示。
<script language="javascript"> var appid = '@ViewBag.appid'; var noncestr = '@ViewBag.noncestr'; var signature = '@ViewBag.signature'; var timestamp = '@ViewBag.timestamp'; wx.config({ debug: false, appId: appid, // 必填,公众号的唯一标识 timestamp: timestamp, // 必填,生成签名的时间戳 nonceStr: noncestr, // 必填,生成签名的随机串 signature: signature, // 必填,签名,见附录1 jsApiList: [ 'checkJsApi', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation' ] }); wx.ready(function () { wx.getLocation({ type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 $("#lblLoacation").text(latitude + "," + longitude); //解析坐标地址 var location = latitude + "," + longitude; $.ajax({ type: 'GET', url: '/JSSDKTest/GetAddress?location=' + location, //async: false, //同步 //dataType: 'json', success: function (json) { $("#lblAddress").text(json); }, error: function (xhr, status, error) { $.messager.alert("提示", "操作失败" + xhr.responseText); //xhr.responseText } }); } }); wx.getNetworkType({ success: function (res) { var networkType = res.networkType; // 返回网络类型2g,3g,4g,wifi $("#lblNetwork").text(networkType); } }); chooseImage(); }); </script>
其中的chooseImage()是我们在页面开始的时候,让用户拍照的操作,具体JS代码如下所示。
//拍照显示 var localIds; function chooseImage() { wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片 $("#imgUpload").attr("src", localIds); } }); }
但用户使用摄像头拍照后,就会返回一个res.localIds集合,因为我们拍照一个,那么可以把它直接赋值给图片对象,让它显示当前拍照的图片。
拍照完成,我们单击【签到】应该把图片和相关的坐标等信息上传到服务器的,图片首先是保存在微信服务器的,上传图片有效期3天,可用微信多媒体接口下载图片到自己的服务器,此处获得的 serverId 即 media_id。
为了实现我们自己的业务数据,我们需要把图片集相关信息存储在自己的服务器,这样才可以实现信息的保存,最后提示【签到操作成功】,具体过程如下所示。
//上传图片 var serverId; function upload() { wx.uploadImage({ localId: localIds[0], success: function (res) { serverId = res.serverId; //提交数据到服务器 //提示信息 $.toast("签到操作成功"); }, fail: function (res) { alert(JSON.stringify(res)); } }); }
另外,我们为了实现单击图片控件,实现重新拍照的操作,以及签到的事件处理,我们对控件的单击处理进行了绑定,如下代码所示。
document.querySelector('#imgUpload').onclick = function () { chooseImage(); }; $(document).on("click", "#btnSignIn", function () { if (localIds == undefined || localIds== null) { $.toast('请先拍照', "forbidden"); return; } //调用上传图片获得媒体ID upload(); });
以上是C#開發微信入口網站及應用程式使用微信JSSDK實現簽到功能的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!