最近两三个月的时间,断断续续边学边做完成了一个微信公众号页面的开发工作。这是一个快递系统,主要功能有用户管理、寄收件地址管理、用户下单,订单管理,订单查询及一些宣传页面等。本文主要细数下开发过程中遇到的各种坑,也算是另外一种总结吧。

1. 开发语言及框架

Python + Flask + Bootstrap,数据库使用的是MySQL
 

2. 相关文档及Lib库

2) 微信公众号开发文档 https://mp.weixin.qq.com/wiki
4) PDF 《FlaskWeb开发:基于Python的Web应用开发实战》

3. 那些坑

3.1 微信

3.1.1 微信登陆

首先你需要仔细阅读官方文档,简单来说微信登陆有如下几步:
1) 生成微信认证跳转URL,注意有`snsapi_base`跟`snsapi_userinfo`两种方式,前者是静默授权只获取用户openid,后者需要用户手动同意获取用户基本信息
2) 获取access_token
3) 获取用户信息
 
解决微信OAuth2.0网页授权只能设置一个回调域名的问题,参考 https://github.com/HADB/GetWeixinCode

3.1.2 模版消息

登陆微信公众平台 -> 功能 -> 模版消息,选择右侧模版消息接口文档 ,即可查看详细的接口文档。
主要步骤如下:
1)获取access_token,其中token有效期为7200s,而且微信限制了每天的调用次数,这里使用functools.lru_cache维护了一个token的内存缓存
2)获取模版ID
3)请求接口
POST URL: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
POST Data: 请求包为json
 

3.2 MySQL

3.2.1 编码问题

MySQL遇到最大的坑还是编码问题,因为涉及到获取微信用户名含有各种emoji表情的问题,需要设置字符编码为utf8mb4,具体可以参考这篇文章(https://mathiasbynens.be/notes/mysql-utf8mb4),然而设置成功在Flask SQLAlchemy配置app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root@localhost:3306/test?charset=utf8mb4'后,运行报错sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (2019, "Can't initialize character set utf8mb4 (path: C:\\mysql\\\\share\\charsets\\)"),解决无果。
最终解决方案是:
1) Flask SQLAlchemy配置app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root@localhost:3306/test?charset=utf8'
2) 微信用户名写入数据库时使用repr()方法将写入原始unicode字符,读取的时候再使用eval()进行转换
 

3.2.2 SQLAlchemy查询数据转换为Dict

for u in session.query(User).all():
u = dict(u.__dict__)
u.pop('_sa_instance_state', None)
参考文章:
 

3.4 Flask

3.4.1 cookie相关

1) 设置cookie
@app.route('/set_cookie')
def set_cookie():
response=make_response('Hello World');
response.set_cookie('Name','Joo')
return response
 
2) 获取cookie
@app.route('/get_cookie')
def get_cookie():
name=request.cookies.get('Name')
return name
 
3) 删除cookie
 
设置过期时间为0
@app.route('/del_cookie')
def del_cookie():
response=make_response('delete cookie')
response.set_cookie('Name','',expires=0)
return response
 
使用delete_cookie方法
@app.route('/del_cookie')
def del_cookie():
response=make_response('delete cookie')
response.delete_cookie('Name')
return response
 

3.4.2 flask.make_response() 实例

3.4.3 详细解读Jquery各Ajax函数:$.get(),$.post(),$.ajax(),$.getJSON()

3.4.4 bootstrap对话框插件

3.4.5 Flask flash增加link

3.4.6 HTML颜色编码

3.4.7 Python缓存

微信获取access_token时有效期是7200s,而且微信限制了每天的调用频率(2000次/天),所以简单使用lru_cache在内存中维护了一个token缓冲,示例代码如下:

@lru_cache(None)
def getAccessToken():
url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}'.format(app_id, app_secret)
r = requests.get(url)
access_token = r.json().get('access_token')
time_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print '[{0}] getAccessToken Result:\t{1}'.format(time_now, r.text)
return access_token, datetime.now() def getToken():
token, t = getAccessToken()
if (datetime.now() - t).seconds > 3600:
getAccessToken.cache_clear()
token, t = getAccessToken()
return token
else:
return token

参考:

 

3.4.8 修改Bootstrap使用国内源

由于默认Bootstrap使用的CDN是http://cdnjs.cloudflare.com,国内访问较慢,所以需要修改默认CDN为国内源。
找到C:\Python27\Lib\site-packages\flask_bootstrap\__init__.py(C:\Python27 为你当前Python版本路径),在文件最后找到如下代码:
        bootstrap = lwrap(
WebCDN('//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/%s/' %
BOOTSTRAP_VERSION), local) jquery = lwrap(
WebCDN('//cdnjs.cloudflare.com/ajax/libs/jquery/%s/' %
JQUERY_VERSION), local) html5shiv = lwrap(
WebCDN('//cdnjs.cloudflare.com/ajax/libs/html5shiv/%s/' %
HTML5SHIV_VERSION)) respondjs = lwrap(
WebCDN('//cdnjs.cloudflare.com/ajax/libs/respond.js/%s/' %
RESPONDJS_VERSION))
替换为国内源cdn.bootcss.com,代码如下:
        bootstrap = lwrap(
WebCDN('//cdn.bootcss.com/twitter-bootstrap/%s/' %
BOOTSTRAP_VERSION), local) jquery = lwrap(
WebCDN('//cdn.bootcss.com/jquery/%s/' %
JQUERY_VERSION), local) html5shiv = lwrap(
WebCDN('//cdn.bootcss.com/html5shiv/%s/' %
HTML5SHIV_VERSION)) respondjs = lwrap(
WebCDN('//cdn.bootcss.com/respond.js/%s/' %
RESPONDJS_VERSION))
参考资料:
 

3.4.9 flask部署

flask通常在Linux上部署方式是 flask + wsgi + nginx,windows上则是flask + iis + nginx。这里实际部署的环境是Windows Server 2007,由于项目实际访问量较小的关系,最终选用简单的flask + tornado部署方式。
在flask项目里原来的入口程序假设为run.py的同级目录添加tornado_server.py,内容如下:
# coding:utf-8

from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from run import app
http_server = HTTPServer(WSGIContainer(app)) # address为实际访问URL,port为端口号
http_server.listen(port=5000, address="127.0.0.1")
IOLoop.instance().start()
使用python tornado_server.py即可启动。
 
参考文档:

细数Python Flask微信公众号开发中遇到的那些坑的更多相关文章

  1. python之微信公众号开发(基本配置和校验)

    前言 最近有微信公众号开发的业务,以前没有用python做过微信公众号开发,记录一下自己的学习和开发历程,共勉! 公众号类型 订阅号 普通订阅号 认证订阅号 服务号 普通服务号 认证服务号 服务方式 ...

  2. 微信公众号开发中遇到的几个bug

    一.测试自定义菜单接口时中文菜单名显示为null 设置的中文菜单名,中文未经过编码和解码过程,设置的中文菜单名在最后的微信服务器返回的json格式数据中显示为null. 解决办法:将中文先用uneco ...

  3. Flask 微信公众号开发

    公众号接口 1. 公众号消息会话 目前公众号内主要有这样几类消息服务的类型,分别用于不同的场景. 群发消息 公众号可以以一定频次(订阅号为每天1次,服务号为每月4次),向用户群发消息,包括文字消息.图 ...

  4. Flask+微信公众号开发(接入指南)

    目录 一.注册公众号 二.启用开发者 三.配置服务器配置 四.开发自己的需求 五.写在最后 一.注册公众号 具体的注册过程,根据官方文档一步一步来即可.这里需注意的是订阅号还是服务号:有些比较好的开发 ...

  5. Python webpy微信公众号开发之 回复图文消息

    新建图文回复模板reply_pictext.xml: $def with (toUser,fromUser,createTime,title1,description1,picurl1,url1)&l ...

  6. .net微信公众号开发——消息与事件

    作者:王先荣    本文介绍如何处理微信公众号开发中的消息与事件,包括:(1)消息(事件)概况:(2)验证消息的真实性:(3)解析消息:(4)被动回复消息:(5)发送其他消息.    开源项目地址:h ...

  7. .net微信公众号开发——群发消息

    作者:王先荣    本文将介绍微信公众号开发中用于群发消息的类MassMessage,包括:(1)MassMessage类:(2)群发:(3)删除:(4)预览:(5)查询发送状态:(6)接收推送群发结 ...

  8. .net微信公众号开发——基础接口

    作者:王先荣    本文讲述微信公众号开发中基础接口的使用,包括以下内容:    (1)获取许可令牌(AccessToken):    (2)获取微信服务器地址:    (3)上传.下载多媒体文件:  ...

  9. C#微信公众号开发 -- (一)开发之前的准备

    本系列文章讲述的是利用C#语言开发微信公众号的实例教程,主要是服务号的开发(因为订阅号不能获取微信开发的高级接口) 想要开发微信服务公众号,首先必须要有一个认证的微信服务号,这样才能够使用微信提供的所 ...

随机推荐

  1. Flask-SQLAlchemy.........>model创建表

    import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarat ...

  2. 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](五)

    前言 Hi,大家好,我是Rector 时间飞逝,一个星期又过去了,今天还是星期五,Rector在图享网继续跟大家分享系列文本:一步一步创建ASP.NET MVC5程序[Repository+Autof ...

  3. JVM GC知识回顾

    这两天刚好有朋友问到我面试中GC相关问题应该怎么答,作为java面试中热门问题,其实没有什么标准回答.这篇文章结合自己之前的总结,对GC做一个回顾. 1.分代收集 当前主流VM垃圾收集都采用" ...

  4. dubbo源码—Service Invoke

    dubbo的远程调用过程是怎么样的? dubbo远程过程调用经过了那些处理? 发起远程调用的时候究竟传了什么数据给provider? 要解决这些问题,欢迎一起探讨走进dubbo源码栏目. 在servi ...

  5. linux下,文件的权限和数字对应关系详解

    命令 chmod ABC file 其中A.B.C各为一个数字,分别表示User.Group.及Other的权限. A.B.C这三个数字如果各自转换成由"0"."1&qu ...

  6. 移动端APP列表点透事件处理方法

    关于点透事件这里不再赘述,如果不清楚的可以上网搜一搜,或者看小火柴的这篇文章. 这里是自己在做移动端时,在列表滑动的时候,遇到的点透问题.出现这个问题的来由是因为在转场的时候,各个手机的转场效果不一样 ...

  7. AtCoder Regular Contest 071

    C - 怪文書 / Dubious Document 题意:定义一种无序的子序列:在原串中随意地取字符并随意打乱顺序.求多个字符串的最长公共无序子序列. #include<cstdio> ...

  8. poj 2758 && BZOJ 2258 Checking the Text 文本校对

    Description   为了给Wind买生日礼物,Jiajia不得不找了一份检查文本的工作.这份工作很无聊:给你一段文本 要求比对从文本中某两个位置开始能匹配的最大长度是多少.但比无聊更糟糕的是, ...

  9. “玲珑杯”ACM比赛 Round #13 题解&源码

    A 题目链接:http://www.ifrog.cc/acm/problem/1111 分析:容易发现本题就是排序不等式, 将A数组与B数组分别排序之后, 答案即N∑i=1Ai×Bi 此题有坑,反正据 ...

  10. vijos 1557:bzoj:1413: [ZJOI2009]取石子游戏

    Description 在研究过Nim游戏及各种变种之后,Orez又发现了一种全新的取石子游戏,这个游戏是这样的: 有n堆石子,将这n堆石子摆成一排.游戏由两个人进行,两人轮流操作,每次操作者都可以从 ...