flask开发restful api系列(1),flaskrestful

flask开发restful api系列(1),flaskrestful

  从前,向我们声明的是,我们全部框架用的是flask + sqlalchemy +
redis。若无开拓过web,依然先去上学一下,那边只是介绍假设从开辟web调换来支付移动端。即使flask还不是很熟谙,小编提议先到这么些网址轻松学习一下,特别特别轻松。 

  一贯想写一些特其余东西,能让我们学习研讨的事物。但眼前互连网的无数博客,老么就依照法定文书档案照本宣读,要么直接搬代码,什么都不表达。小编写那么些类别的博客,让大家由表及里,一步一步走向复杂构造,以致为什么要如此走,别的艺术行不行等等。

  这段日子看来,手机支付最火,而大家python最切合开荒移动的就是flask
web框架,那款web框架特别明晰,能够简轻松单用,能够复杂用。最简便易行的时候,二个py文件,就足以做三个类型;复杂的时候,利用蓝图,做种种版本调控,代码构造本人全然调控,极其自由。

  首先,大家要明了,最近我们线上支付为主都在用restful
api,什么是restful api呢?百度宏观一下:Web 应用程序最要紧的 REST
原则是,顾客端和服务器之间的互相在伸手之间是无状态的。从客商端到服务器的各个须求都一定要包蕴了解哀告所非常重要的音信。若是服务器在伸手之间的任哪天刻点重启,客商端不会收获文告。此外,无状态乞求能够由别的可用服务器回答,那十一分相符云总计之类的蒙受。客商端能够缓存数据以改过质量。

  说白了大家无法选择cookie,不能够使用session了。如若有些有一点http经历的人,都驾驭,非常多时候,大家都把有个别宗旨内容放在cookie里面,服务器每一遍读取大概写入的时候,服务器端就径直设置session就足以了,那样,每趟,顾客端直接带走自身的cookie值上来,大家就掌握它是何人,怎么把多少给它。但restful
api的品格分裂意那样,那服务器应该采纳何种方案吧?

  方今互连网海大学部分做法是token格局,第1回登陆的时候,先交由客户名密码,服务器搜罗到今后,先验证一下,要是证实通过了,这个时候服务器端基于客户名、密码、当前时间戳等剧情,用md5或然des可能aes等加密方法,生成一个token值,然后把token值贮存到redis里面,记录它对应哪个客商,然后把这么些token值发给顾客端。顾客端收到token值今后,后一次做客服务器端任何接口的时候,直接带入那些token,服务器端就精通它是哪个人了,该给它什么数据。哪以何种措施给劳务器端呢?平常的做法正是把token值放在header里面。当然那个不是纯属,你也能够投身body里面,那个都以各持己见各持己见的事。好了,大家就先放在header头里面。

  以上说了那样多,大家也烦了,直接上代码,再解释吗。

  首先,创设整个工程,为了最简便易行,方便,大家直接就封存以下的py文件。

   图片 1

  看model.py里面包车型大巴代码:

  

# coding:utf-8
from sqlalchemy import create_engine, ForeignKey, Column, Integer, String, Text, DateTime,
    and_, or_, SmallInteger, Float, DECIMAL, desc, asc, Table, join, event
from sqlalchemy.orm import relationship, backref, sessionmaker, scoped_session, aliased, mapper
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
from sqlalchemy.orm.collections import attribute_mapped_collection
import datetime

engine = create_engine("mysql://root:[email protected]:3306/blog01?charset=utf8", pool_recycle=7200)

Base = declarative_base()

db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))

Base.query = db_session.query_property()


class User(Base):
    __tablename__ = 'user'

    id = Column('id', Integer, primary_key=True)
    phone_number = Column('phone_number', String(11), index=True)
    password = Column('password', String(30))
    nickname = Column('nickname', String(30), index=True, nullable=True)
    register_time = Column('register_time', DateTime, index=True, default=datetime.datetime.now)


if __name__ == '__main__':
    Base.metadata.create_all(engine)

运行一下,就创办user表了。

user表中,有电话号码,phone_number;密码,password;昵称,nickname;register_time,注册时间

  下面是view.py代码

 1 # coding:utf-8
 2 from flask import Flask, request, jsonify
 3 from model import User, db_session
 4 import hashlib
 5 import time
 6 import redis
 7 
 8 app = Flask(__name__)
 9 redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123')
10 
11 
12 @app.route('/')
13 def hello_world():
14     return 'Hello World!'
15 
16 
17 @app.route('/login', methods=['POST'])
18 def login():
19     phone_number = request.get_json().get('phone_number')
20     password = request.get_json().get('password')
21     user = User.query.filter_by(phone_number=phone_number).first()
22     if not user:
23         return jsonify({'code': 0, 'message': '没有此用户'})
24 
25     if user.password != password:
26         return jsonify({'code': 0, 'message': '密码错误'})
27 
28     m = hashlib.md5()
29     m.update(phone_number)
30     m.update(password)
31     m.update(str(int(time.time())))
32     token = m.hexdigest()
33 
34     redis_store.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1})
35     redis_store.set('token:%s' % token, user.phone_number)
36     redis_store.expire('token:%s' % token, 3600*24*30)
37 
38     return jsonify({'code': 1, 'message': '成功登录', 'nickname': user.nickname, 'token': token})
39 
40 
41 @app.route('/user')
42 def user():
43     token = request.headers.get('token')
44     if not token:
45         return jsonify({'code': 0, 'message': '需要验证'})
46     phone_number = redis_store.get('token:%s' % token)
47     if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'):
48         return jsonify({'code': 2, 'message': '验证信息错误'})
49 
50     nickname = redis_store.hget('user:%s' % phone_number, 'nickname')
51     return jsonify({'code': 1, 'nickname': nickname, 'phone_number': phone_number})
52 
53 
54 @app.route('/logout')
55 def logout():
56     token = request.headers.get('token')
57     if not token:
58         return jsonify({'code': 0, 'message': '需要验证'})
59     phone_number = redis_store.get('token:%s' % token)
60     if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'):
61         return jsonify({'code': 2, 'message': '验证信息错误'})
62 
63     redis_store.delete('token:%s' % token)
64     redis_store.hmset('user:%s' % phone_number, {'app_online': 0})
65     return jsonify({'code': 1, 'message': '成功注销'})
66 
67 
68 @app.teardown_request
69 def handle_teardown_request(exception):
70     db_session.remove()
71 
72 if __name__ == '__main__':
73     app.run(debug=True, host='0.0.0.0', port=5001)

 

上面来每一个解释一下,

率先,多少个import不用解释了,注意把User和db_session
都import过来,然后定义叁个redis的connection。

再接下去就login接口,直接post方法,获取json格式数据,里面有phone_flask开发restful api系列(1),flaskrestful。number和password,接下去,数据库查询,若无那么些顾客,重临四个json格式,再接下去比较password,假诺phone_number和password都确实无疑,就用md5函数,生成一个token,那么些token包蕴由phone_number、password、当前时间戳str(int(time.time(State of QatarState of Qatar卡塔尔(قطر‎生成,再回到。

看自身各类再次来到的东西,首先,都以json格式,这么些是当前许多运动支付暗中同意重返的格式;其次,各样重回,必定有个code,如今那边有2个值,是0和1,其实能够看出来,0代表战败,1意味着成功,有0之处必须要有message。每一种重临多个code是必得的,可是值,能够团结定义。非常多开支把http的code直接拿来用,也足以,举例成功重返,就200,未有就404,制止就403。这一个都得以,只要服务器端开荒和客商端支出初始就预定八个值就好,具体的值,只要能飞快支付,都能够。

好了,重返格式先表明到这,大家以后会三回九转扩张。再看接下去的redis。

第大器晚成行,先用 user:13765505223
这种类型的作为每种客商的key,值是生机勃勃对主导的事物,个中app_online,代表上线了,这些app_online,其实相当重大的,因为移动端支付跟web不相同,要记录移动端在报到状态,依然登出状态。假如在登入情状,大家就足以从服务器推送了,关于推送,大家随后会日渐讲,那么些先放在这里边。

第二行,用token:token 作为key,key里面包车型大巴值是现实的客商电话号码

其三行,把这几个token设置一个超时日子,当先这几个日子,就删除,那一个有亟待的app能够设置一下。假让你的app的token想永世不改变,那行代码能够注释掉。

好了,最近login函数基本到位。

接下去看表明函数user,和撤消函数logout,

user这几个函数,那是来表明登入未来,有未有数量,没多少意义。

逐行深入分析,首先在header里找到这几个token,若无token,就再次回到失利;其次,验证redis,纵然token所在的key
value对里面没有值只怕值错误,则赶回退步。然后重临具体的数量。特别轻便的叁个函数。

上面包车型客车logout函数也大致,也是这么,也是表达,然后删除token的key
value对,再设置app_online为0,表示如今是撤销状态。

提起底三个很首要,那边应当要切记,把这几个函数写上。若无这么些函数,每五个会话以往,db_session都不会去掉,非常多时候,数据库改正了,前台找不到,或者分明生机勃勃度付诸,数据库还是没有改进,大概长日子尚无访谈接口,mysql
gong away,那样的不当。不问可以知道,必供给丰硕。

好了,整个进程已经做到,上边步入验证状态。首先大家在外头新建八个顾客,存到数据库,然后写个小脚本作证一下。

>>> from model import User, db_session
>>> new_user = User(phone_number='12345678901', password='123456', nickname=u'测试用户1')
>>> db_session.add(new_user)
>>> db_session.commit()

三个客商已经创办好,接下去就是测验,那边测量试验有2种艺术,三个用IDE自带的测验软件测验,pycharm有很好的测验软件;其次用小脚本形式测量试验,既然我们以往要不停的写例子,就用小脚本测量检验呢,进度也非常轻便。

 1 # coding:utf-8
 2 import requests
 3 import json
 4 
 5 
 6 class APITest(object):
 7     def __init__(self, base_url):
 8         self.base_url = base_url
 9         self.headers = {}
10         self.token = None
11 
12     def login(self, phone_number, password, path='/login'):
13         payload = {'phone_number': phone_number, 'password': password}
14         self.headers = {'content-type': 'application/json'}
15         response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
16         response_data = json.loads(response.content)
17         self.token = response_data.get('token')
18         return response_data
19 
20     def user(self, path='/user'):
21         self.headers = {'token': self.token}
22         response = requests.get(url=self.base_url + path, headers=self.headers)
23         response_data = json.loads(response.content)
24         return response_data
25 
26     def logout(self, path='/logout'):
27         self.headers = {'token': self.token}
28         response = requests.get(url=self.base_url + path, headers=self.headers)
29         response_data = json.loads(response.content)
30         return response_data

 

写一个很简单的小本子,就能够拉到命令行测验了,咱们探究啊。

>>> from client import APITest
>>> api = APITest('http://127.0.0.1:5001')
>>> data = api.login('12345678901', '1234567')
>>> print data.get('message')
密码错误
>>> data = api.login('12345678901', '123456')
>>> print data.get('message')
成功登录
>>> data = api.user()
>>> print data
{u'phone_number': u'12345678901', u'code': 1, u'nickname': u'u6d4bu8bd5u7528u62371'}
>>> print nickname
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'nickname' is not defined
>>> print data.get('nickname')
测试用户1
>>> data = api.logout()
>>> print data
{u'message': u'u6210u529fu6ce8u9500', u'code': 1}
>>> print message
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'message' is not defined
>>> print data.get('message')
成功注销

 登陆成功的时候,我们进redis看看redis数据格式,相比较直观点。

127.0.0.1:6380[4]> keys *
1) "token:bbf73ab651a13a5bc5601cf01add2564"
2) "user:12345678901"
127.0.0.1:6380[4]> hgetall user:12345678901
1) "token"
2) "bbf73ab651a13a5bc5601cf01add2564"
3) "nickname"
4) "xe6xb5x8bxe8xafx95xe7x94xa8xe6x88xb71"
5) "app_online"
6) "1"
127.0.0.1:6380[4]> get token:bbf73ab651a13a5bc5601cf01add2564
"12345678901"
127.0.0.1:6380[4]> 

 

哦,一切都例行,但大家付出不能够一切符合规律,就满意。就那一个代码,大家有无数亟待改过的地点,越发是印证token的那边,是还是不是足以校订呢?redis设置的时候,三翻七回串动作,假若那个时候出错,或许redis只设置到四分之二怎么做?这么些难点,大家下一章继续解决。

api连串(1卡塔尔(قطر‎,flaskrestful
早前,向大家表达的是,大家不论什么事框架用的是flask + sqlalchemy +
redis。若无支付过web,照旧先去学…

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章