当你要在微信中分享你的文章给好友,朋友圈的时候是要给微信发送一些数据的.比如 : 签名 等
微信签名获取的地址 : https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
微信公众平台接口调试工具地址 : https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=%E5%9F%BA%E7%A1%80%E6%94%AF%E6%8C%81&form=%E8%8E%B7%E5%8F%96access_token%E6%8E%A5%E5%8F%A3%20/token
微信 JS 接口签名校验工具地址 : https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
前期准备 : 准备已经备案的域名 , 在公众号配置白名单(放入服务器公网ip)和域名校验
微信给了我们python获取签名的代码,但是没有给 token 和 jsapi_ticket
后端 :
注意 : 要给 access_token 和 jsapi_ticket 做全局缓存 , 因为没交钱的每天只能2000次,如果不缓存就废了
# 获取 access_token def get_token(request): r = redis.Redis(connection_pool=pool, decode_responses=True) access_token = r.get("'wx:access_token") if access_token: return access_token try: appid = appid secret = secret # 请求token接口 """ https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET """ url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}".format( appid=appid, secret=secret) response = requests.get(url) access_token = response.json()['access_token'] """ r = {"access_token":"ACCESS_TOKEN","expires_in":7200} 正确 r = {"errcode":40013,"errmsg":"invalid appid"} 错误 """ # 缓存 r.setex('wx:access_token', 7200, access_token) return access_token except Exception as e: return e # 获取 jsapi_ticket def get_ticket(request, appid, secret): # 先在缓存中获取 r = redis.Redis(connection_pool=pool, decode_responses=True) ticket = r.get("wx:ticket") if ticket: # ticket = str(ticket, encoding="utf-8") return ticket else: try: token = get_token(request) print("-----token======", token) """ https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi """ ticket_url = " https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={}&type=jsapi".format(token) get_ticket = requests.get(ticket_url).content.decode("utf-8") js_ticket = json.loads(get_ticket) ticket = js_ticket.get("ticket") r.setex("wx:ticket", 7200, ticket) return ticket except Exception as e: return e # 获得签名 class Sign: def __init__(self, jsapi_ticket, url): self.ret = { 'nonceStr': self.__create_nonce_str(), 'jsapi_ticket': jsapi_ticket, 'timestamp': self.__create_timestamp(), 'url': url } # 随机字符串 def __create_nonce_str(self): import string return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(16)) # 时间戳时间 def __create_timestamp(self): return int(time.time()) # 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1 def sign(self): string = '&'.join(['%s=%s' % (key.lower(), self.ret[key]) for key in sorted(self.ret)]) self.ret['signature'] = hashlib.sha1(string.encode("utf-8")).hexdigest() return self.ret # 发送签名到前端,就行请求 def sign(request): if request.method == "POST": # 获取前端传过来的当前页面的url,并且进行解码 url = request.POST.get("url") url = parse.unquote(url) # 传给get_ticket ticket = get_ticket(request) sign = Sign(ticket, url) ret = sign.sign() reful = { "appId": appid, "signature": ret["signature"], "nonceStr": ret["nonceStr"], "timestamp": ret["timestamp"], } return JsonResponse(reful) """ 返回信息 {"debug":false,"appId":"wx1c5f000057d68bb9","timestamp":1561105606,"nonceStr":"9JzMRz","signature":"9a458696bb443de9fb235c68f31fb60d4fe6c96a"} """
前端 :
注意 : jsApiList 中 放入 translateVoice (别问为什么,我也不知道,就是不放就报错 错误 : hideMenuItems:fail, the permission value is offline verifying )
$.ajax({ url: 'http://qxds.weiyingqipai.cn/sign/', data: { // 获取当前url,并编码,后端解码 url: encodeURIComponent(location.href.split('#')[0]) }, // 同步请求 async: false, type: 'post', dataType: 'text', success: function (msg) { console.log("msg", msg); // 从后台获取并json解码 var json = JSON.parse(msg); var appid = json["appId"]; var nonceStr = json["nonceStr"]; var timestamp = json["timestamp"]; var signature = json["signature"]; console.log("-------", json["appId"], json["signature"]); var a = { debug: false, appId: appid, timestamp: timestamp, nonceStr: nonceStr, signature: signature, jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'hideOptionMenu', 'showOptionMenu', 'translateVoice'] }; wx.config(a); wx.ready(function () { console.log(a); // 发送给朋友 wx.onMenuShareAppMessage({ title: dataForWeixin.title, desc: dataForWeixin.desc, // 分享文章的url link: url, imgUrl: dataForWeixin.img, success: function () { // 分享成功之后执行这个函数 _this.shaer_tips(); }, }); // 分享到朋友圈 wx.onMenuShareTimeline({ title: dataForWeixin.title, desc: dataForWeixin.desc, link: 'http://' + url[2] + '/rukou', imgUrl: dataForWeixin.img, success: function () { _this.shaer_p_tips(); } }); }); _this.shaer_tips = function () { console.log("分享成功之后执行的这个函数==============") }; _this.shaer_p_tips = function () { }; _this.Reloadconfig = function (type) { m = type; // wx.config(window._Data.config); wx.ready(function () { if (m == 1) { wx.hideMenuItems({ menuList: ['menuItem:share:timeline'] }); wx.onMenuShareAppMessage({ title: dataForWeixin.title, desc: dataForWeixin.desc, link: 'http://' + url[1] + '/rukou', imgUrl: dataForWeixin.img, success: function () { _this.shaer_tips(); } }); } else { // 隐藏按钮 wx.hideMenuItems({ // 分享好友 menuList: ['menuItem:share:appMessage'] }); wx.showMenuItems({ // 分享朋友圈 menuList: ['menuItem:share:timeline'] }); wx.onMenuShareTimeline({ title: dataForWeixin.title, desc: dataForWeixin.desc, link: 'http://' + url[2] + '/rukou', imgUrl: dataForWeixin.img, success: function () { _this.shaer_p_tips(); } }); } }); } }, });