18年年底公司上线了一个AI识别柑橘病虫害的小程序。19年初Boss又说,要开发一个柑橘日报网站,通过给种植柑橘的目标用户推送柑橘类的技术文章来达到给小程序引流的目的。当时听了,脑子立刻就冒出了这样的想法:这他妈不就是爬取数据,后台做数据展示、以及文章个性化推送了吗?像我这暴脾气,说干就干。在产品原型搞完成之后,对照产品原型规划了一下这个网站开发的思路,就开始开干。
说点什么



回到主题



1.获得Access Token:
接口调用请求说明
Method: GET
Params:
grant_type: client_credential(写死不变)
appid: 第三方用户唯一凭证
secret: 第三方用户唯一凭证密钥,既appsecret
Url: https://api.weixin.qq.com/cgi-bin/token?
grant_type=client_credential&appid=APPID&secret=APPSECRET
正常就会返回如下格式:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
2.获取jsapi_ticket:
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,必须在自己的服务全局缓存jsapi_ticket 。这里使用redis来实现。
接口调用请求说明
Method: GET
Params:
access_token: ACCESS_TOKEN # 上一步获取的access_token
Url: https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
正常返回Json数据格式如下:
{
"errcode":0,
"errmsg":"ok",
"ticket":"dHSM05e5u5s0m9E8NYzWKVZVbTPXNKd8-41ZN5OfkWITDGgO3MhKoysdshFKAnr2fwJvdVtaUgWv",
"expires_in":7200
}
3. 签名算法实现
签名生成规则如下:签名参数包括:noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前请求传递过来的url) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
假设当前需要的签名参数如下:
noncestr = wgWedZYTm3WPwzz0ccnW
jsapi_ticket = dHSM05e5u5s0m9E8NYzWKVZVbTPXNKd8-41ZN5OfkWITDGgO3MhKoysdshFKAnr2fwJvdVtaUgWv
timestamp = 1550401085
url = http://mp.weixin.qq.com?params=value
jsapi_ticket=dHSM05e5u5s0m9E8NYzWKVZVbTPXNKd8-41ZN5OfkWITDGgO3MhKoysdshFKAnr2fwJvdVtaUgWv&
noncestr=wgWedZYTm3WPwzz0ccnW×tamp=1550401085&
url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature
ca0874ef9c0790fde62f999e9590c27e50ceb3dd
到这里,通过文档介绍,相信大家已经知道分享文章给微信好友的开发业务已经熟悉了。
后台业务流程如下所示:
接下来就是展示后台的代码,最好是结合流程图和代码一起看:
def share_article():
"""主要是处理分享文章"""
try:
request_data = request.get_json()
except Exception as e:
current_app.logger.error("request error {}".format(e))
return define_make_response(str(dict(status=0, msg="请求错误", data=[])))
url = request_data.get("url")
if not url:
return define_make_response(str(dict(status=0, msg="参数错误", data=[])))
# 微信服务器获取access_token
try:
ticket_flag = redis_store.get("ticket_flag")
except Exception as e:
current_app.logger.error("redis error: {}".format(e))
return define_make_response(str(dict(status=0, msg="redis查询失败", data=[])))
if not ticket_flag:
response = get_access_token()
if not response[0]:
current_app.logger.error("获取access_token失败:{}".format(response[1]))
return define_make_response(str(dict(status=0, msg="获取微信access_token失败", data=[])))
# 获取jsapi_ticket
jsapi_ticket = get_jsapi_ticket(response[1])
if not jsapi_ticket[0]:
return define_make_response(str(dict(status=0, msg="获取ticket失败", data=[])))
# 设置签名ticket
ticket = jsapi_ticket[1]
else:
ticket = ticket_flag.decode("utf8")
noncestr = generate_noncestr()
timestamp = int(time.time())
sign_str = "jsapi_ticket={}&noncestr={}×tamp={}&url={}".format(ticket, noncestr, timestamp, url)
sha = sha1()
sha.update(sign_str.encode("utf8"))
signature = sha.hexdigest()
try:
redis_store.setex("ticket_flag", TICKET_EXPIRES, ticket)
except Exception as e:
current_app.logger.error("redis error: {}".format(e))
return define_make_response(str(dict(status=0, msg="redis保存参数失败", data=[])))
data = [{"signature": signature, "noncestr": noncestr, "timestamp": timestamp, "appId": APP_ID}]
return define_make_response(str(dict(status=1, msg="", data=data)))
到此为止,文档解析和后台代码分享已经完成。要是还有什么疑虑或者问题,欢迎大家私下交流。
Python全家桶