nginx + uwsgi + flask
一、安装
1、安装uwsgi
[root@yaoliang day_13]# wget http://projects.unbit.it/downloads/uwsgi-2.0.4.tar.gz
[root@yaoliang day_13]# tar xf uwsgi-2.0.4.tar.gz -C /usr/local
[root@yaoliang day_13]# cd /usr/local/uwsgi-2.0.4
[root@yaoliang uwsgi-2.0.4]# make
[root@yaoliang uwsgi-2.0.4]# vim /etc/ld.so.conf # 添加动态链接库目录
/usr/local/lib # 添加内容
[root@yaoliang uwsgi-2.0.4]# ldconfig
[root@yaoliang uwsgi-2.0.4]# cp uwsgi /usr/bin
2、安装nginx
[root@yaoliang day_13]# wget
[root@yaoliang day_13]# tar xf nginx-1.10.1.tar.gz -C /usr/local
[root@yaoliang day_13]# cd /usr/local/nginx-1.10.1
[root@yaoliang nginx-1.10.1]# ./configure--user=nginx --group=nginx --with-pcre=/usr/local/pcre-8.38/--prefix=/usr/local/nginx --sbin-path=/usr/sbin/nginx --conf-path=/usr/local/nginx/nginx.conf--error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid--lock-path=/var/lock/subsys/nginx --with-http_ssl_module--with-http_stub_status_module --with-file-aio --with-http_dav_module--with-http_realip_module
[root@yaoliang nginx-1.10.1]# make && make install
二、配置
1、配置uwsgi
[root@yaoliang nginx]# vim uwsgi.ini
[uwsgi]
# socket = /tmp/uwsgi.sock # 监听的套接字(本地使用)
socket = 127.0.0.1:8888 # 监听的地址和端口号
processes = 4 # 开启的进程数量
threads = 1 # 运行的线程数量
pythonpath = /data/python/homework_12/ # 指定运行目录
module = app # 指定运行的python包名
callable = app # 指定运行的python应用名
buffer-size = 32768 # 缓存大小
2、配置nginx
[root@yaoliang nginx]# vim nginx.conf
location / {
# uwsgi_pass /tmp/uwsgi.sock; # 代理uwsgi套接字文件
uwsgi_pass 127.0.0.1:8888; # 代理uwsgi地址和端口
include uwsgi_params;
}
三、启动服务
1、启动uwsgi
[root@yaoliang day_13]# uwsgi --ini /usr/local/nginx/uwsgi.ini -d /var/log/uwsgi.log --pidfile /tmp/uwsgi.pid
[root@yaoliang day_13]# ss -tnlp | grep 8888 # 8888端口已开启
LISTEN 0 100 127.0.0.1:8888 *:* users:(("uwsgi",pid=103733,fd=3),("uwsgi",pid=103732,fd=3),("uwsgi",pid=103731,fd=3),("uwsgi",pid=103724,fd=3))
2、启动nginx
[root@yaoliang day_13]# /usr/sbin/nginx -c /usr/local/nginx/nginx.conf
Flask中传参的两种方法
# coding:utf-8
from flask import Flask,request,render_template
app = Flask(__name__)
@app.route('/',methods=['GET','POST']) # 方式一
def index():
if request.method == 'GET':
name = request.args.get('name')
return 'GET User is %s\n'% name
elif request.method == 'POST':
name = request.form.get('name')
return 'POST User is %s\n'% name
@app.route('/<string:username>',methods=['GET','POST']) # 方式二,基于api开发,必须要传入username参数,否则就会报错
def test(username):
if request.method == 'GET':
age = request.args.get('age')
elif request.method == 'POST':
age = request.form.get('age')
return 'User is %s, age is %s\n'% (username,age)
if __name__=='__main__':
app.debug=True
app.run(host='0.0.0.0',port=5000)
运行结果
[root@yaoliang day_13]# curl -XGET http://localhost:5000?'name=wd'
GET User is wd
[root@yaoliang day_13]# curl -XGET http://localhost:5000/wd?age=20
User is wd, age is 20
[root@yaoliang day_13]# curl -XPOST http://localhost:5000 -d 'name=wd'
POST User is wd
[root@yaoliang day_13]# curl -XPOST http://localhost:5000/wd -d 'age=20'
User is wd, age is 20
Python HTTP库:requests
一、安装
[root@yaoliang day_13]# pip install requests
二、基本用法
1、直接处理数据
In [1]: import requests
In [2]: r = requests.get("http://httpbin.org/get",timeout=5) # 模拟get请求,超时时间5秒
In [3]: r = requests.post("http://httpbin.org/post") # post请求,用的最多
In [4]: r = requests.put("http://httpbin.org/put")
In [5]: r = requests.delete("http://httpbin.org/delete")
In [6]: r = requests.head("http://httpbin.org/get") # 直接获取head,不下载内容
In [7]: r = requests.options("http://httpbin.org/get")
2、为URL传递参数
In [8]: data = {'key1':'value1','key2':'value2'}
In [9]: r = requests.get("http://httpbin.org/post",params=data) # get中,params为传递的参数
In [10]: r = requests.post("http://httpbin.org/post",json=data) # post中,json为传递的参数
In [117]: r = requests.post("http://httpbin.org/post",data=json.dumps(data)) # post中,data也可以为传递的参数
原理:
如果传递的参数是dict类型,在发出请求时会自动编码为表单提交的形式,如果传递的数据不是dict类型,而是str,requests就将其当做字符串传值过去,传过去的是什么类型,flask后端获取到的就是什么类型
3、flask对应获取的数据的方式
flask默认及restful API格式的接受方式
get,delete请求:request.args.get('key1'),
post,put请求 :request.form.get('key1')
getJSON请求: request.get_json() #jquery的请求方式
示例:以json形式发送举例:restful API格式
In [10]: r = requests.post(url, data=json.dumps(payload), headers=headers)
In [11]: r = requests.post(url, json=payload, headers=headers) # 两种方式等价,后端获取方式均为request.get_json()
补充:requests通过json请求的几种写法
In [12]: data = {'name':'wd'}
In [13]: r = requests.delete(url, headers=headers,json=data) # 后端get_json()获取后,类型依旧是<type 'dict'> ,可直接取值,仅仅是当做json字符串传输,到后端字符串类型不变
In [14]: r = requests.post(url, headers=headers,json=json.dumps(data)) # 将字典转换为json,然后在通过json方式传送,后端get_json()获取后,类型为<type 'unicode'>,需要json.loads()反解。
In [15]: data = request.get_json() # 通过get_json()获取传入的json字符串
In [16]: data = json.loads(data) # 将json字符串反解为原来的格式
4、flask jsonrpc API的接受方式:最常用的两种
@jsonrpc.method('App.user') # jsonrpc格式
def user(*arg, **kwargs):
data = {}
data['name'] = kwargs.get('name',None)
data['age'] = kwargs.get('age',None)
return 'I am %s,age is %s' % (data['name'],data['age'])
@jsonrpc.method('App.users')
def users(**kwargs):
data = request.get_json() # 如果要传入的参数比较多,kwargs.get()的方式可能比较费劲,可以get_json()获取所有参数,通过字典列表的方式减少代码量
data['name'] = data['params']['name']
data['age'] = data['params']['age']
return 'I am %s,age is %s' % (data['name'],data['age'])
# encoding:utf-8
import json
import requests
headers = {'content-type': 'application/json'}
url = "http://127.0.0.1:5000/api"
data = {
'jsonrpc':'2.0',
# 'method': 'App.user', # 请求后端不定参数的method,通过形参获取参数
'method': 'App.users', # 请求后端不定参数的method,get_json获取参数
'id':'1',
'params':{
'name':'wd', # 无参数的method,此处为空,指定参数的method,只能保留一条参数
'age':'18'
}
}
r = requests.post(url, headers=headers,json=data) #以json字符串形式传值
print r.status_code
print r.content
运行结果
[root@yaoliang day_13]# python test.py
200
{
"id": "1",
"jsonrpc": "2.0",
"result": "I am wd,age is 18"
}
备注:request在传送json字符串时,有两种方式
1、数据参数名自定义,将数据json.dumps表明以json形式传送
2、数据参数名定义为json,数据会自动转为json方式传送
三、其他用法
1、requests获取服务器响应的内容
In [1]: import requests
In [2]: r = requests.get("http://www.httpbin.org.")
In [3]: r.text # 获取返回的内容
Out[3]: ... ...
In [4]: r.content # 获取二进制相应的内容
Out[4]: ... ...
In [5]: r.url # 获取请求的url
Out[5]: u'http://www.httpbin.org.'
In [6]: r.encoding # 获取编码格式
Out[6]: 'utf-8'
In [7]: r.status_code # 获取相应状态码
Out[7]: 200
In [8]: r.json() # 获取json数据,不需要像urllib使用json.load解码
Out[8]: ... ...
2、请求定制头
添加HTTP头部,只需要传递一个dict给headers参数即可
In [9]: headers = {'content-type':'application/json'}
In [10]: r = requests.post(url,data=json.dumps(data),headers=headers)
In [11]: r.headers # 返回服务器响应头,返回的是一个dict
Out[11]: {'Content-Length': '12150', 'Server': 'nginx', 'Connection': 'keep-alive', 'Access-Control-Allow-Credentials': 'true', 'Date': 'Mon, 24 Oct 2016 03:32:42 GMT', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'text/html; charset=utf-8'}
In [12]: r.request.headers # 返回本次的请求头部
Out[12]: {'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.6.0 CPython/2.7.5 Linux/3.10.0-327.el7.x86_64'}
token
1.token是什么?
官方解释:令牌,代表执行某些操作的权利的对象
个人解释:用户信息的加密串,系统拿到这个加密串来判断用户是谁,能干什么,不能干什么
2.token怎么生成?
token的生成方式因人而异,大致思路是将自己需要的一些信息,混合时间戳,随机数等加密生成,习惯是(用户名。用户id,角色,时间戳,随机数)
生成token:
token = base64.b64encode(name|uid|role|str(random.random())|int(time.time()+7200))
3.token怎么用,以判断登录是否过期?
先解密token,生成一个列表
res = base64.decode(token)
通过时间戳判断token是否失败:
if int(res.split('|')[4] > int(time.time())
return True
token示例
#!/usr/bin/python
#coding:utf-8
from flask import Flask,request
import base64,time,random,json
app = Flask(__name__)
def create_token(name,uid,role): # 创建token
token = base64.b64encode('%s|%s|%s|%s|%s'% (name,uid,role,str(random.random()),int(time.time()+7200)))
return token
def verify_token(token): # 对token进行认证
t = int(time.time())
key = base64.b64decode(token)
x = key.split('|')
if len(x) != 5:
return json.dumps({'code':'1','errmsg':'token参数不足'})
if t > int(x[4]):
return json.dumps({'code':'1','errmsg':'登录过期'})
else:
return json.dumps({'code':'0','username':x[0],'uid':x[1],'role':x[2]})
@app.route('/login',methods=['GET','POST'])
def login():
name = request.form.get('name')
passwd = request.form.get('passwd')
if name == 'wd' and passwd == '123456': # 做简单的测试
uid = 1
role = 0
token = create_token(name,uid,role) # 登录成功就创建token
return json.dumps({'code':0,'token':'%s'% token})
else:
return json.dumps({'code':1,'errmsg':'token 创建失败'})
@app.route('/',methods=['GET','POST','PUT'])
def index():
token = request.args.get('token',None) # 获取传入的token
if not token:
return 'token is null'
result = verify_token(token) # 对token进行判断
result = json.loads(result)
if int(result['code']) == 1: # 根据token中的信息来判断用户的权限
return 'error: %s'% result['errmsg']
if int(result['role']) == 0:
return '%s is admin ,you can do everything'% result['username']
else:
return '%s is not admin ,request refuse' % result['username']
if __name__=='__main__':
app.run(host='0.0.0.0',port=9092,debug=True)
模拟登录并生成token
#!/usr/bin/python
#coding:utf-8
import requests,json
import sys
'''
模拟登录并生成token
'''
data = {'name':'wd','passwd':'123456'}
r = requests.post(' # 模拟登录
print r.status_code # 获取状态码
print r.text # 获取返回值
result = json.loads(r.text)
if result['code'] == 0:
token = result['token']
else:
print result['errmsg']
'''
调用生成的token,进行后面的认证操作,api是无状态的,先生成一个token,然后用这个token进行后面的权限认证
web环境中,通过cookie或者session保存状态的,在用户登录成功获取到token后可以把token存放到session,然后直接从sesson中获取token
'''
token = {'token':token}
r = requests.get('http://127.0.0.1:9092',params = token) # 将token以get的方式传入
print r.status_code
print r.text
执行结果
[root@yaoliang day_13]# python token_msg.py
200
{"token": "d2R8MXwwfDAuMzU5MTI4NDkyNDg1fDE0NzcyOTgxODU=", "code": 0}
200
wd is admin ,you can do everything