继续上一章所讲,上一章我们最后面说道,虽然这个是很小的程序,但还有好几个要优化的地方。先复制一下老的view.py代码。

 # coding:utf-8
from flask import Flask, request, jsonify
from model import User, db_session
import hashlib
import time
import redis app = Flask(__name__)
redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123') @app.route('/')
def hello_world():
return 'Hello World!' @app.route('/login', methods=['POST'])
def login():
phone_number = request.get_json().get('phone_number')
password = request.get_json().get('password')
user = User.query.filter_by(phone_number=phone_number).first()
if not user:
return jsonify({'code': 0, 'message': '没有此用户'}) if user.password != password:
return jsonify({'code': 0, 'message': '密码错误'}) m = hashlib.md5()
m.update(phone_number)
m.update(password)
m.update(str(int(time.time())))
token = m.hexdigest() redis_store.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1})
redis_store.set('token:%s' % token, user.phone_number)
redis_store.expire('token:%s' % token, 3600*24*30) return jsonify({'code': 1, 'message': '成功登录', 'nickname': user.nickname, 'token': token}) @app.route('/user')
def user():
token = request.headers.get('token')
if not token:
return jsonify({'code': 0, 'message': '需要验证'})
phone_number = redis_store.get('token:%s' % token)
if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'):
return jsonify({'code': 2, 'message': '验证信息错误'}) nickname = redis_store.hget('user:%s' % phone_number, 'nickname')
return jsonify({'code': 1, 'nickname': nickname, 'phone_number': phone_number}) @app.route('/logout')
def logout():
token = request.headers.get('token')
if not token:
return jsonify({'code': 0, 'message': '需要验证'})
phone_number = redis_store.get('token:%s' % token)
if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'):
return jsonify({'code': 2, 'message': '验证信息错误'}) redis_store.delete('token:%s' % token)
redis_store.hmset('user:%s' % phone_number, {'app_online': 0})
return jsonify({'code': 1, 'message': '成功注销'}) @app.teardown_request
def handle_teardown_request(exception):
db_session.remove() if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5001)

其中验证token的方法,已经重叠了,python教我们,永远不要重复自己的代码,这是很丑陋的行为。今天我们把它换成一个装饰器,然后再把redis调整一下,看看代码会不会简洁很多。

 # coding:utf-8
from flask import Flask, request, jsonify
from model import User, db_session
import hashlib
import time
import redis
from functools import wraps app = Flask(__name__)
redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123') def login_check(f):
@wraps(f)
def decorator(*args, **kwargs):
token = request.headers.get('token')
if not token:
return jsonify({'code': 0, 'message': '需要验证'}) phone_number = redis_store.get('token:%s' % token)
if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'):
return jsonify({'code': 2, 'message': '验证信息错误'}) return f(*args, **kwargs)
return decorator @app.route('/login', methods=['POST'])
def login():
phone_number = request.get_json().get('phone_number')
password = request.get_json().get('password')
user = User.query.filter_by(phone_number=phone_number).first()
if not user:
return jsonify({'code': 0, 'message': '没有此用户'}) if user.password != password:
return jsonify({'code': 0, 'message': '密码错误'}) m = hashlib.md5()
m.update(phone_number)
m.update(password)
m.update(str(int(time.time())))
token = m.hexdigest() pipeline = redis_store.pipeline()
pipeline.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1})
pipeline.set('token:%s' % token, user.phone_number)
pipeline.expire('token:%s' % token, 3600*24*30)
pipeline.execute() return jsonify({'code': 1, 'message': '成功登录', 'nickname': user.nickname, 'token': token}) @app.route('/user')
@login_check
def user():
token = request.headers.get('token')
phone_number = redis_store.get('token:%s' % token) nickname = redis_store.hget('user:%s' % phone_number, 'nickname')
return jsonify({'code': 1, 'nickname': nickname, 'phone_number': phone_number}) @app.route('/logout')
@login_check
def logout():
token = request.headers.get('token')
phone_number = redis_store.get('token:%s' % token) pipeline = redis_store.pipeline()
pipeline.delete('token:%s' % token)
pipeline.hmset('user:%s' % phone_number, {'app_online': 0})
pipeline.execute()
return jsonify({'code': 1, 'message': '成功注销'}) @app.teardown_request
def handle_teardown_request(exception):
db_session.remove() if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5001)

加了一个装饰器,是不是简洁了很多?每次需要验证的时候,只需要一个login_check就可以了,这样就变得非常简洁,而且脉络清晰。redis也改成了管道执行,pipeline,防止执行到一半,被掐断。

可是,可是,我还是觉得不简洁,看user, logout的代码中重复的地方。

token = request.headers.get('token')
phone_number = redis_store.get('token:%s' % token)

每次都有这两句,要是将来还有其他值怎么办?上面不刚说,永远不要重复自己的代码吗?

好,我们再写一个函数,看下面代码

 # coding:utf-8
from flask import Flask, request, jsonify, g
from model import User, db_session
import hashlib
import time
import redis
from functools import wraps app = Flask(__name__)
redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123') def login_check(f):
@wraps(f)
def decorator(*args, **kwargs):
token = request.headers.get('token')
if not token:
return jsonify({'code': 0, 'message': '需要验证'}) phone_number = redis_store.get('token:%s' % token)
if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'):
return jsonify({'code': 2, 'message': '验证信息错误'}) return f(*args, **kwargs)
return decorator @app.before_request
def before_request():
token = request.headers.get('token')
phone_number = redis_store.get('token:%s' % token)
if phone_number:
g.current_user = User.query.filter_by(phone_number=phone_number).first()
g.token = token
return @app.route('/login', methods=['POST'])
def login():
phone_number = request.get_json().get('phone_number')
password = request.get_json().get('password')
user = User.query.filter_by(phone_number=phone_number).first()
if not user:
return jsonify({'code': 0, 'message': '没有此用户'}) if user.password != password:
return jsonify({'code': 0, 'message': '密码错误'}) m = hashlib.md5()
m.update(phone_number)
m.update(password)
m.update(str(int(time.time())))
token = m.hexdigest() pipeline = redis_store.pipeline()
pipeline.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1})
pipeline.set('token:%s' % token, user.phone_number)
pipeline.expire('token:%s' % token, 3600*24*30)
pipeline.execute() return jsonify({'code': 1, 'message': '成功登录', 'nickname': user.nickname, 'token': token}) @app.route('/user')
@login_check
def user():
user = g.current_user nickname = redis_store.hget('user:%s' % user.phone_number, 'nickname')
return jsonify({'code': 1, 'nickname': nickname, 'phone_number': user.phone_number}) @app.route('/logout')
@login_check
def logout():
user = g.current_user pipeline = redis_store.pipeline()
pipeline.delete('token:%s' % g.token)
pipeline.hmset('user:%s' % user.phone_number, {'app_online': 0})
pipeline.execute()
return jsonify({'code': 1, 'message': '成功注销'}) @app.teardown_request
def handle_teardown_request(exception):
db_session.remove() if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5001)

我们在代码中加了一个before_request,这个函数就是在每个request发起的时候,如果已经验证了,我们把当前g.current_user和g.token设置一下,这样每次需要获取当前用户的时候,直接找g.current_user就可以了,是不是简单了太多太多?好了,今天到此为止,下一章,我们讲怎么利用alembic修改数据库。

flask开发restful api系列(2)的更多相关文章

  1. flask开发restful api系列(8)-再谈项目结构

    上一章,我们讲到,怎么用蓝图建造一个好的项目,今天我们继续深入.上一章中,我们所有的接口都写在view.py中,如果几十个,还稍微好管理一点,假如上百个,上千个,怎么找?所有接口堆在一起就显得杂乱无章 ...

  2. flask开发restful api系列(1)

    在此之前,向大家说明的是,我们整个框架用的是flask + sqlalchemy + redis.如果没有开发过web,还是先去学习一下,这边只是介绍如果从开发web转换到开发移动端.如果flask还 ...

  3. flask开发restful api系列(7)-蓝图与项目结构

    如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restful api的最明显效果就是版本控制:而 ...

  4. flask开发restful api系列(6)-配置文件

    任何一个好的程序,配置文件必不可少,而且非常重要.配置文件里存储了连接数据库,redis的用户密码,不允许有任何闪失.要有灵活性,用户可以自己配置:生产环境和开发环境要分开,最好能简单的修改一个东西, ...

  5. flask开发restful api系列(5)-短信验证码

    我们现在开发app,注册用户的时候,不再像web一样,发送到个人邮箱了,毕竟个人邮箱在移动端填写验证都很麻烦,一般都采用短信验证码的方式.今天我们就讲讲这方面的内容. 首先,先找一个平台吧.我们公司找 ...

  6. flask开发restful api系列(4)--七牛图片服务

    上一章我们讲到如何利用alembic来更新数据库,这章,我们讲如何通过七牛服务来存储图片. 像我们大多数公司一样,公司资金比较少,如果自己开发图片服务器,代价太大:如果我们用自己的网站服务器来保存图片 ...

  7. flask开发restful api系列(3)--利用alembic进行数据库更改

    上面两章,主要讲基本的配置,今天我们来做一个比较有趣的东西,为每个客户加一个头像图片.如果我们图片保存在自己的服务器,对于服务器要求有点高,每次下载的时候,都会阻塞网络接口,要是1000个人同时访问这 ...

  8. flask开发restful api

    flask开发restful api 如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restfu ...

  9. 描述怎样通过flask+redis+sqlalchemy等工具,开发restful api

    flask开发restful api系列(8)-再谈项目结构 摘要: 进一步介绍flask的项目结构,使整个项目结构一目了然.阅读全文 posted @ 2016-06-06 13:54 月儿弯弯02 ...

随机推荐

  1. Android监听事件

    ListView事件监听: setOnItemSelectedListener 鼠标滚动时触发 setOnItemClickListener 点击时触发 EditText事件监听: setOnKeyL ...

  2. Unity3D添加Admob广告

    重要提示:             貌似play2014年8月之后不会再支持admob的SDK方式的广告了.github上已经有了 Unity AdMob (Google Play Services) ...

  3. ng-class的使用

    例如: td(ng-class="{0:'text-warning',1:'text-primary'}[bj.flag]") {{bj.flag | bjFlagfilter}} ...

  4. ural 1837 Isenbaev's Number

    http://acm.timus.ru/problem.aspx?space=1&num=1837 #include <cstdio> #include <cstring&g ...

  5. Android中设置文字大小的定义类型

    在Android中所有的组件可以设置大小,但是在设置大小的时候需要指定其单位,这些单位如下: px(pixels):像素: dip(device independent pixels):依赖于设备的像 ...

  6. libCurl的C++引用

    I believe I have gotten LibCurl to work with Visual Studio 2013 now. Persistence ftw! Although, afte ...

  7. 公网IP和私有IP

    IP地址是为了区分网络中不同主机所分配的一个地址,通过IP地址可以访问到每一台主机. IP地址分为公有地址和私有地址,公有地址由Internet NIC负责(比如中国互联网信息中心http://ip. ...

  8. TCP 协议

    == 已经了解了以太网和IP了,下面我们进入传输层,开始讲解TCP协议. == 仍然先把TCP报文段的格式放在这里,然后我们看图说话: TCP报文段也分为首部和数据两部分,首部默认情况下一般是20字节 ...

  9. RequireJS进阶(三)

    进阶的前面两篇讲述了r.js如何通过命令行把所有的模块压缩为一个js文件或把所有的css压缩为一个css文件.其中包括一些压缩配置参数的使用. 但以上两种方式有几个问题 1.通过命令手动配置压缩选项显 ...

  10. Css轮廓

    css code: p{ outline-width:2px; outline-color:aqua; outline-style: groove; }