做了一個網站,放到線上,用微信打開,點擊分享,可是分享後發給朋友的連結卡是微信預設自帶的,如下:
這標題,描述以及圖片是預設自帶的,醜不說,分享給別人還以為是盜號網站呢,而接入微信的JSSDK後,分享可以自訂內容,如下:
我承認,雖然這分享的標題和內容也不正經,但這不妨礙我表達我們可以透過微信JSSDK定義分享內容,接下來我們將一步一步從零實作JSSDK從後端Node.js的存取。
介面設定資訊
修改介面設定資訊
#URL位址必須是你伺服器上的位址,此位址要能通過瀏覽器的位址欄訪問到(沒有伺服器?沒關係,一會兒我們搭建一個)
假設我這裡填寫的伺服器位址是"http://www.your_server_name.com/wxJssdk"
#此時點擊提交是會提示配置失敗的,因為在提交的時候,微信是會請求你的伺服器地址,而你的當前配置的地址並不能訪問,所以會提示配置失敗。不過別急,我們先來搭建一個簡單的Node伺服器,讓微信能夠存取該伺服器。 | 搭建簡單的Node伺服器 |
---|---|
現在我們在地址欄中訪問,如果頁面顯示“請求成功了了了”,則進入到下一步,如果沒有成功的話,檢查一下你的伺服器是否開啟Node伺服器,如: | |
此時保存微信測試公眾號後台的介面配置訊息,仍然會提示配置失敗,這是因為我們沒有按照它的要求返回。 | 根據微信測試公眾號請求資訊返回對應內容 |
描述 |
微信服务器会通过GET请求,来请求我们所配置的接口,并带上以上表格的信息,而我们必须按照以下要求,将微信发送的信息进行要求校验,以确保是微信发送的信息,其中校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
const express = require('express')const app = express()const sha1 = require('sha1')app.get('/wxJssdk', (req, res) => { let wx = req.query let token = 'jegfjaeghfuccawegfgjdbh' let timestamp = wx.timestamp let nonce = wx.nonce // 1)将token、timestamp、nonce三个参数进行字典序排序 let list = [token, timestamp, nonce].sort() // 2)将三个参数字符串拼接成一个字符串进行sha1加密 let str = list.join('') let result = sha1(str) // 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 if (result === wx.signature) {res.send(wx.echostr) // 返回微信传来的echostr,表示校验成功,此处不能返回其它 } else {res.send(false) }})
此时我们重启Node服务器,再次保存接口配置信息即可配置成功。
微信JSSDK使用步骤
根据微信JSSDK说明文档,我们需要完成如下:
填写安全域名
登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”,即要调用接口的域名,不包含协议
前端引入JS
在需要调用JS接口的页面引入此JS文件,(支持https):
填写接口的配置信息
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2});
调用接口
做你前端该做的,调用微信分享接口,或微信提供的其它接口,whatever you need,当然,这并不是我们所要讲的重点,我们接下来要看一下微信的配置信息从哪获取
在Node服务器中生成jssdk所需要的配置信息
从上一节可以看到,调用微信JSSDK需要以下信息
appId
timestamp
nonceStr
signature
jsApiList
其中:
第1项appId是测试公众号后台的appId,我们已知
第2项时间戳我们也可以自己生成
第3项nonceStr可以随意填写,你可以理解为密钥
第4项signature则需要我们按要求生成
第5项是所需要接口的接口名
生成signature
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
为了保证我们appid,appsecret,nonceStr等信息不在前端曝露,我们以下步骤将在服务器上进行操作,以免他人盗用信息获取(注:微信请求有每日次数限制,一旦超出,则无法使用,具体请求次数限制在微信公众号后台中可查看)
生成access_token
根据微信开发文档[获取access_token文档说明],我们需要将微信测试公众号后台的appid和和appsecret以GET的请求方式向 发起请求获取token,请求成功后我们会获得下返回JSON转化的字符串
{"access_token":"ACCESS_TOKEN","expires_in":7200}
具体请求代码如下:
const request = require('request')const grant_type = 'client_credential'const appid = 'your app id'const secret = 'your app secret'request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => { let access_toekn = JSON.parse(body).access_token})
获取jsapi_ticket
const request = require('request')const grant_type = 'client_credential'const appid = 'your app id'const secret = 'your app secret'request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => { let access_toekn = JSON.parse(body).access_token request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => { let jsapi_ticket = JSON.parse(body).ticket })})
生成签名
生成签名的步骤和最开始的/wxJssdk
的算法是一致的,具体如下:
let jsapi_ticket = jsapi_ticket // 上一步从获取的jsapi_ticketlet nonce_str = '123456' // 密钥,字符串任意,可以随机生成let timestamp = new Date().getTime() // 时间戳let url = req.query.url // 使用接口的url链接,不包含#后的内容// 将请求以上字符串,先按字典排序,再以'&'拼接,如下:其中j > n > t > u,此处直接手动排序let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '×tamp=' + timestamp + '&url=' + url// 用sha1加密let signature = sha1(str)
连接后的代码为:
const request = require('request')const grant_type = 'client_credential'const appid = 'your app id'const secret = 'your app secret'request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => { let access_toekn = JSON.parse(body).access_token request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => { let jsapi_ticket = JSON.parse(body).ticket let nonce_str = '123456' // 密钥,字符串任意,可以随机生成 let timestamp = new Date().getTime() // 时间戳 let url = req.query.url // 使用接口的url链接,不包含#后的内容 // 将请求以上字符串,先按字典排序,再以'&'拼接,如下:其中j > n > t > u,此处直接手动排序 let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '×tamp=' + timestamp + '&url=' + url // 用sha1加密 let signature = sha1(str) })})
曝露接口,返回给前端
app.post('/wxJssdk/getJssdk', (req, res) => { const request = require('request') const grant_type = 'client_credential' const appid = 'your app id' const secret = 'your app secret' request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => {let access_toekn = JSON.parse(body).access_tokenrequest('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => { let jsapi_ticket = JSON.parse(body).ticket let nonce_str = '123456' // 密钥,字符串任意,可以随机生成 let timestamp = new Date().getTime() // 时间戳 let url = req.query.url // 使用接口的url链接,不包含#后的内容 // 将请求以上字符串,先按字典排序,再以'&'拼接,如下:其中j > n > t > u,此处直接手动排序 let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '×tamp=' + timestamp + '&url=' + url // 用sha1加密 let signature = sha1(str) res.send({ appId: appid, timestamp: timpstamp, nonceStr: nonce_str, signature: signature, })}) })})
前端请求后端接口,获取配置信息
获取配置
axios.post('/wxJssdk/getJssdk', {url: location.href}).then((response) => { var data = response.data wx.config({debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: data.appId, // 必填,公众号的唯一标识timestamp: data.timestamp, // 必填,生成签名的时间戳nonceStr: data.nonceStr, // 必填,生成签名的随机串signature: data.signature,// 必填,签名,见附录1jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });})
做你想做的,比如,自定义分享
if (wx) { axios.post('/wxJssdk/getJssdk', {url: location.href}).then((response) => {var data = response.datawx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: data.appId, // 必填,公众号的唯一标识 timestamp: data.timestamp, // 必填,生成签名的时间戳 nonceStr: data.nonceStr, // 必填,生成签名的随机串 signature: data.signature,// 必填,签名,见附录1 jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2});wx.ready(function () { wx.onMenuShareTimeline({ title: wxShare.title, desc: wxShare.desc, link: wxShare.link, imgUrl: wxShare.imgUrl }); wx.onMenuShareAppMessage({ title: wxShare.title, desc: wxShare.desc, link: wxShare.link, imgUrl: wxShare.imgUrl}); })wx.error(function (res) { // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。}) })}
至此,后端配置好了,我们已经能够正常使用微信的接口了,但是微信每日接口请求是有上限的,通过2000次/天,因此如果网站上线后,一量当天访问量超过2000次你的接口将失效,而且每次都请求微信接口两次,造成请求时间浪费,所以我们需要将以上获取信息缓存在后端,避免造成接口失效以及多次请求微信后台。
缓存access_token及jsapi_ticket
此处直接上代码,利用node_cache包进行缓存
const request = require('request')const express = require('express')const app = express()const sha1 = require('sha1')const waterfall = require('async/waterfall')const NodeCache = require('node-cache')const cache = new NodeCache({stdTTL: 3600, checkperiod: 3600}) //3600秒后过过期app.get('/wxJssdk', (req, res) => { let wx = req.query // 1)将token、timestamp、nonce三个参数进行字典序排序 let token = 'jegfjaeghfuyawegfgjdbh' let timestamp = wx.timestamp let nonce = wx.nonce // 2)将三个参数字符串拼接成一个字符串进行sha1加密 let list = [token, timestamp, nonce] let result = sha1(list.sort().join('')) // 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 if (result === wx.signature) {res.send(wx.echostr) } else {res.send(false) }})app.get('/wxJssdk/getJssdk', (req, res) => { let grant_type = 'client_credential' let appid = 'your app id' let secret = 'your app secret' // appscret let steps = [] // 第一步,获取access_token steps.push((cb) => { let steps1 = []// 第1.1步,从缓存中读取access_tokensteps1.push((cb1) => { let access_token = cache.get('access_token', (err, access_token) => {cb1(err, access_token) })})// 第1.2步,缓存中有access_token则直接返回,如果没有,则从服务器中读取access_tokensteps1.push((access_token, cb1) => { if (access_token) {cb1(null, access_token, 'from_cache') } else {request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => { cb1(err, JSON.parse(body).access_token, 'from_server')}) }})// 第1.3步,如果是新从服务器取的access_token,则缓存起来,否则直接返回steps1.push((access_token, from_where, cb1) => { if (from_where === 'from_cache') {console.log(' === 成功从缓存中读取access_token: ' + access_token + ' ===')cb1(null, access_token) } else if (from_where === 'from_server') {cache.set('access_token', access_token, (err, success) => { if (!err && success) {console.log(' === 缓存已过期,从服务器中读取access_token: ' + access_token + ' ===')cb1(null, access_token) } else {cb1(err || 'cache设置access_token时,出现未知错误') }}) } else {cb1('1.3获取from_where时,from_where值为空') }})waterfall(steps1, (err, access_token) => { cb(err, access_token)}) }) // 第二步,获取ticket steps.push((access_token, cb) => {let steps1 = []// 第2.1步,从缓存中读取ticketsteps1.push((cb1) => { let ticket = cache.get('ticket', (err, ticket) => {cb1(err, ticket) })})// 第2.2步,缓存中有ticket则直接返回,如果没有,则从服务器中读取ticketsteps1.push((ticket, cb1) => { if (ticket) {cb1(null, ticket, 'from_cache') } else {request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => { cb1(err, JSON.parse(body).ticket, 'from_server')}) }})// 第2.3步,如果新从服务器取的ticket,则缓存起来,否则直接返回steps1.push((ticket, from_where, cb1) => { if (from_where === 'from_cache') {console.log(' === 成功从缓存中读取ticket: ' + ticket + ' ===')cb1(null, ticket) } else if (from_where === 'from_server') {cache.set('ticket', ticket, (err, success) => { if (!err && success) {console.log(' === 缓存已过期,从服务器中读取ticket: ' + ticket + ' ===');cb1(null, ticket) } else {cb1(err || 'cache设置ticket时,出现未知错误') }}) } else {cb1('2.3获取from_where时,from_where值为空') }})waterfall(steps1, (err, ticket) => { cb(err, ticket)}) }) // 第三步,生成签名 steps.push((ticket, cb) => {let jsapi_ticket = ticketlet nonce_str = '123456'let timestamp = new Date().getTime()let url = req.query.urllet str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '×tamp=' + timestamp + '&url=' + urllet signature = sha1(str)cb(null, { appId: appid, timestamp: timestamp, nonceStr: nonce_str, signature: signature, ticket: ticket}) }) waterfall(steps, (err, data) => {if (err) { res.send({status: 'error', data: err})} else { res.send({status: 'success', data: data})} })})app.use('/wxJssdk/public', express.static('public'))app.listen(80, err => { if(!err) console.log('connect succeed')})
以上是實作Node.js在微信JS-SDK後端接口的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE

Python和JavaScript在性能和效率方面的差異主要體現在:1)Python作為解釋型語言,運行速度較慢,但開發效率高,適合快速原型開發;2)JavaScript在瀏覽器中受限於單線程,但在Node.js中可利用多線程和異步I/O提升性能,兩者在實際項目中各有優勢。

JavaScript起源於1995年,由布蘭登·艾克創造,實現語言為C語言。 1.C語言為JavaScript提供了高性能和系統級編程能力。 2.JavaScript的內存管理和性能優化依賴於C語言。 3.C語言的跨平台特性幫助JavaScript在不同操作系統上高效運行。

JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

Atom編輯器mac版下載
最受歡迎的的開源編輯器