微信真坑观挎,鼓搗了一天松捉,眼睛都瞎了,最后發(fā)現(xiàn)個(gè)人微信公眾賬號(hào)沒有權(quán)限蔑歌,尼瑪震叙。掀鹅。。
1. 注冊(cè)微信公眾平臺(tái)
為了能夠使用微信的接口媒楼,需要注冊(cè)開發(fā)者賬號(hào)身份淫半, 這個(gè)自行百度
2.搭建一個(gè)服務(wù)器
我們需要一個(gè)服務(wù)器,來獲取訪問微信API的簽名匣砖,這里使用NodeJS服務(wù)器:
const request = require('request')
var express = require('express');
var app = express();
const sha1 = require('sha1')
const waterfall = require('async/waterfall')
const NodeCache = require('node-cache')
const cache = new NodeCache({stdTTL: 3600, checkperiod: 3600})
// app.get('/wxJssdk', function (req, res) {
// let wx = req.query
// // 1)將token科吭、timestamp、nonce三個(gè)參數(shù)進(jìn)行字典序排序
// let token = 'jegfjaeghfuyawegfgjdbh'
// let timestamp = wx.timestamp
// let nonce = wx.nonce
// // 2)將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行sha1加密
// let list = [token, timestamp, nonce]
// let result = sha1(list.sort().join(''))
// // 3)開發(fā)者獲得加密后的字符串可與signature對(duì)比猴鲫,標(biāo)識(shí)該請(qǐng)求來源于微信
// if (result === wx.signature) {
// res.send(wx.echostr)
// } else {
// res.send(false)
// }
// })
app.get('/wxJssdk/getJssdk', function (req, res) {
let grant_type = 'client_credential'
let appid = 'xxxx'
let secret = 'xxxx' // appscret
let steps = []
// 第一步对人,獲取access_token
steps.push((cb) => {
let steps1 = []
// 第1.1步,從緩存中讀取access_token
steps1.push((cb1) => {
let access_token = cache.get('access_token', (err, access_token) => {
cb1(err, access_token)
})
})
// 第1.2步拂共,緩存中有access_token則直接返回牺弄,如果沒有,則從服務(wù)器中讀取access_token
steps1.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步宜狐,如果是新從服務(wù)器取的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(' === 緩存已過期抚恒,從服務(wù)器中讀取access_token: ' + access_token + ' ===')
cb1(null, access_token)
} else {
cb1(err || 'cache設(shè)置access_token時(shí)咱台,出現(xiàn)未知錯(cuò)誤')
}
})
} else {
cb1('1.3獲取from_where時(shí),from_where值為空')
}
})
waterfall(steps1, (err, access_token) => {
cb(err, access_token)
})
})
// 第二步俭驮,獲取ticket
steps.push((access_token, cb) => {
let steps1 = []
// 第2.1步回溺,從緩存中讀取ticket
steps1.push((cb1) => {
let ticket = cache.get('ticket', (err, ticket) => {
cb1(err, ticket)
})
})
// 第2.2步,緩存中有ticket則直接返回混萝,如果沒有遗遵,則從服務(wù)器中讀取ticket
steps1.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步,如果新從服務(wù)器取的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(' === 緩存已過期,從服務(wù)器中讀取ticket: ' + ticket + ' ===');
cb1(null, ticket)
} else {
cb1(err || 'cache設(shè)置ticket時(shí)崭倘,出現(xiàn)未知錯(cuò)誤')
}
})
} else {
cb1('2.3獲取from_where時(shí)翼岁,from_where值為空')
}
})
waterfall(steps1, (err, ticket) => {
cb(err, ticket)
})
})
// 第三步维哈,生成簽名
steps.push((ticket, cb) => {
let jsapi_ticket = ticket
let nonce_str = '123456'
let timestamp = Math.floor((new Date().getTime())/1000)
let url = req.query.url
let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '×tamp=' + timestamp + '&url=' + url
console.log('signature ' + str)
let signature = sha1(str)
console.log('==> ' + signature)
cb(null, {
appId: appid,
timestamp: timestamp,
nonceStr: nonce_str,
signature: signature,
ticket: ticket
})
})
waterfall(steps, (err, data) => {
res.setHeader("Content-Type", "text/json");
res.setHeader("Access-Control-Allow-Origin", "*");
if (err) {
res.send({status: 'error', data: err})
} else {
res.send({status: 'success', data: data})
}
})
})
app.use('/wxJssdk/public', express.static('public'))
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
})
出處是:https://www.jb51.net/article/118729.htm
一定要注意,生成簽名的部分打log登澜,然后和微信公眾平臺(tái)上的簽名驗(yàn)證工具對(duì)比一下阔挠,比如時(shí)間戳位數(shù),url對(duì)不對(duì)等
3. 在H5中導(dǎo)入
<script src="./js/jquery-1.11.1.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script>
var currentUrl = encodeURIComponent(location.href.split('#')[0])
$.get('http://xxxx.com/wxJssdk/getJssdk?url=' + currentUrl, function (data, status) {
wx.config({
debug: false, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶端alert出來脑蠕,若要查看傳入的參數(shù)购撼,可以在pc端打開,參數(shù)信息會(huì)通過log打出谴仙,僅在pc端時(shí)才會(huì)打印迂求。
appId: data.data.appId, // 必填,公眾號(hào)的唯一標(biāo)識(shí)
timestamp: data.data.timestamp, // 必填晃跺,生成簽名的時(shí)間戳
nonceStr: data.data.nonceStr, // 必填揩局,生成簽名的隨機(jī)串
signature: data.data.signature,// 必填,簽名
jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage'] // 必填掀虎,需要使用的JS接口列表
});
console.log('wx finish');
wx.ready(function(){
console.log('wx ready');
// alert('wx ready')
wx.error(function(res){
// config 信息驗(yàn)證失敗會(huì)執(zhí)行 error 函數(shù)凌盯,如簽名過期導(dǎo)致驗(yàn)證失敗,具體錯(cuò)誤信息可以打開 config 的 debug 模式查看烹玉,也可以在返回的 res 參數(shù)中查看驰怎,對(duì)于 SPA 可以在這里更新簽名。
console.log("errorMSG:"+res);
});
wx.checkJsApi({
jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage'], // 需要檢測的JS接口列表二打,所有JS接口列表見附錄2,
success: function(res) {
// 以鍵值對(duì)的形式返回县忌,可用的api值true,不可用為false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
console.log('res'+ res);
}
});
var shareParam = {
title: '劉彥博李茜婷的結(jié)婚請(qǐng)柬', // 分享標(biāo)題
// desc: '邀請(qǐng)您的參加', // 分享描述
link: 'http://www.realank.com/wedding/', // 分享鏈接继效,該鏈接域名或路徑必須與當(dāng)前頁面對(duì)應(yīng)的公眾號(hào)JS安全域名一致
imgUrl: 'http://www.realank.com/wedding/headimgwx.jpg', // 分享圖標(biāo)
// type: 'link', // 分享類型,music症杏、video或link,不填默認(rèn)為link
// dataUrl: '', // 如果type是music或video瑞信,則要提供數(shù)據(jù)鏈接厉颤,默認(rèn)為空
trigger: function (res) {
console.log('用戶點(diǎn)擊發(fā)送給朋友');
},
success: function (res) {
console.log('已分享');
},
cancel: function (res) {
console.log('已取消');
},
fail: function (res) {
console.log(JSON.stringify(res));
}
};
wx.onMenuShareTimeline(shareParam);
wx.onMenuShareAppMessage(shareParam);
});
})
</script>
這里使用的是ajax請(qǐng)求的,請(qǐng)求簽名的時(shí)候喧伞,需要加上一個(gè)url參數(shù)走芋,取當(dāng)前url一定要使用encodeURIComponent(location.href.split('#')[0])方法啊绩郎,忘記從哪個(gè)網(wǎng)站上看到的了潘鲫,試了好幾個(gè)小時(shí),因?yàn)檫@個(gè)大哥茅塞頓開肋杖,好人啊
然后在微信web開發(fā)者工具中測試就能通過溉仑,但是真機(jī)沒法通過,因?yàn)?strong>個(gè)人微信公眾號(hào)沒有權(quán)限W粗病W蔷埂怨喘!