记录前端页面狗,第一次接手Python的后台项目踩的坑

简介

故事要从2019年11月份左右说起,本人怀着学习、探知、努力追赶团队平均技术水平的心态,作为一个前端页面狗也很有必要学习一门后端语言,于是在网上找Python教程,跟着廖雪峰老师的《Python教程》走了一遍,然后三分热度一过,这学习的事情就再也没管了。大概过了两个月,刚好有一个项目适合Python练手,很荣幸接手了这个项目(本人的同事也是刚学习完Python教程自己搭建的后台,后来因为他有其他安排,换成了本人继续接着开发,如何搭建后台开发环境《Python教程》),凭着残存的记忆开始了Python、mysql的踩坑之旅…

踩坑记录

token没有到指定的过期时间,token过期问题

判断token的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def check_token(func):
def decorator(*args, **kwargs):
# 请求头携带的token信息
arguments = request.headers.get('arguments')[2:-1]
if not arguments:
return abort(401)
now = datetime.now()
try:
### WHERE 是查询条件,WHERE后面的token和expireTime是token表里面定义的字段 token=传入进来的token expireTime为过期时间sql语句查询token里面是否有请求时的token当前时间是否小于过期时间###
tokenSql = "SELECT * from token WHERE token=%s and expireTime > %s"
result = connectdbobect.selectDb(tokenSql, (arguments, str(now)))
Logger.info(result)
if result:
return func(result[0]['USER'], *args, **kwargs)
else:
return abort(401)
except Exception as e:
# 查找失败时这里也是报了401
Logger.error(e)
return abort(401)
return decorator

在每个接口获取数据之前都做了token的验证,验证token是否有效分为两点:

  1. 当前token在数据库是否能够找到
  2. 当前访问的时间是否小于token设置的过期时间 疫情期间在老家工作条件有限,网络稳定性堪忧,这么艰苦的条件下坚持开发。
    从上图可以看到报错信息是无法获取数据,为什么会无法获取数据呢?初步判断是连接中断了。
    那么我们在断开连接时重新连接服务器应该就能解决,尝试一下,代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def isConnect(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kw):
    if not self.db.open:
    print('关闭~~~')
    # 重新连接
    self.db.ping(reconnect=True)
    return func(self, *args, **kw)
    return wrapper

嗯?还是不行,同样的错误,还在警示着我,百度、bing、Google、stack overflow方法试了一大堆,并没有什么效果。拽发!拽发!拽发!只能暂时把问题记录下来,回到公司后继续解决这个问题,连上公司的网络,果然暂时没有出现问题啦,开心,页面挂着不动没过多久前端页面又出现了401错误,再次查看报错信息发现了一个pymysql的报错,如下:

1
pymysql.err.InternalError: Packet sequence number wrong - got 3 expected 1

到了这里已经蒙圈了,不知该如何解决,请教了亚里士朱德,在大神的帮助下很快找到了解决方案,首先出现这种错误的原因是因为多线程导致的,pymysql的每次连接应该只有一个线程或进程,所以解决方案是每次连接数据库时创立连接,连接结束后立刻关闭连接。(插个眼,备份)

服务器没有挂,数据库没有挂,容器也没有挂,但是获取不了数据了

话说回来,服务器上很久没去关注了,突然有一天去访问线上的页面,发现页面能加载,但是获取数据报了500错误,凭借之前解决问题的经验,先进服务器,查看日志,有错误先看日志准没错,但是我查看日志并没有发现错误,然后就想进去数据库看看,结果发现数据库的容器是启动的,但是进不去容器里面,在网上各种找资料,看到了较为类似的问题,执行了dmesg|grep memory查看OOM killer日志,发现内存不足导致进程被杀死,通过lsof -i:pid 查看进程,再通过top查看内存的使用情况,使用kill -9 杀死当前mysql数据库所占用的进程,然后重启了docker这时可以正常访问了,这个只是暂时的解决方案,后面会使用上级提到的RDS来确保数据库不被内存不足而杀死。

部署问题

  1. 在同步代码之前一定要先在本机调试没问题了,然后打包通过了在提交代码,本人使用的代码同步方式是把代码提交到GitHub上面,然后进入服务器对应的目录去拉取代码进行更新,如果更新了sql文件,一定要记得进入数据库通过source更新一下相应的sql表。
  2. 还有遇到了docker运行异常,日志文件都没有报错,依赖也都正常下载的情况,就是启动不了某个容器,这时需要重新启动docker服务。
  3. 服务器网络环境差,对某些依赖下载很慢时可以采用aliyun镜像: pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ (requirements.txt是本人的依赖文件)

开发中常见的问题

本人在当接口没有正常返回时通常根据对应的状态码去下面步骤里面找解决方案:

  1. 去找对应的接口看下sql语句写的是否符合规范。
  2. 检查前端传过来的参数是否正确。
  3. 检查token是否过期。
  4. 检查判断条件是否为期待的值。

代码优化

元组的操作改为数组操作

1
2
3
4
5
6
7
8
self.db = pymysql.connect(self.host,
self.username,
self.password,
self.database,
self.port,
cursorclass=pymysql.cursors.DictCursor,
charset='utf8',
autocommit=True)

在pymysql的connect中设置cursorclass=pymysql.cursors.DictCursor就可以使返回的数据为数组类型,是前端熟悉的数据类型,可以非常方便的处理数据。

多行字符串的处理

在python中多行字符串

1
2
3
4
5
6
7
# 例1 '''  '''
sql = '''INSERT INTO line_data (linePath, startId, endId) VALUES
(%s, %s, %s)''' % (data['linePath'], data['startId'], data['endId'])

# 例2 \反斜杠
sql = 'INSERT INTO line_data (linePath, startId, endId) VALUES\
(%s, %s, %s)' % (data['linePath'], data['startId'], data['endId'])

接口拆分

不知道有没有小伙伴跟我一样把所有接口写到了一个文件里面,然后随着接口和业务逻辑的繁杂,接口的文件变得非常大,变得很难维护。。。
使用flask的Blueprint去拆分模块register_blueprint去注册,具体操作,参考下面示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 参考
# index.py
from app import server
from app.routes.login import route_login

server.register_blueprint(route_login)

# app/routes/login.py
from flask import Blueprint
# index.py里面调用的route_login模块名
route_login = Blueprint('login', __name__)

@route_login.route('/login', methods=['POST'])
def login():
try:
# ...............

作者信息:宁文飞,人和未来大数据前端工程师