准备
每日一问:
- flask里面加载配置的方法有几种
5种
from_mappig
from_object
from_json
from_envval
from_pyfile - @app.route() 有几个参数
2个 分别是rule和method - 视图接收来自客户端的请求数据,request有几个属性可以接收?
创建python虚拟环境
mkvirtualenv flask -p python3 #创建
deactivate #退出
安装:
pip install flask==0.12.5
已经安装过了所以是这样的显示
创建flask项目
去settings →project:flask → python Interpreter
找到自己创建虚拟环境下的 /home/yanmu/.virtualenvs/flask/bin/python3.8 然后点ok就行
pycharm环境配置完成
flask 基本运行
# 导入Flask类
from flask import Flask
"""
import_name Flask程序所在的包(模块),传 __name__ 就可以
其可以决定 Flask 在访问静态文件时查找的路径
static_path 静态文件访问路径(不推荐使用,使用 static_url_path 代替)
static_url_path 静态文件访问路径,可以不传,默认为:/ + static_folder
static_folder 静态文件存储的文件夹,可以不传,默认为 static
template_folder 模板文件存储的文件夹,可以不传,默认为 templates
"""
# 创建应用对象
app = Flask(__name__)
# 加载项目配置
class Config(object):
DEBUG = True
# flask中支持多种配置方式,通过app.config来进行加载,我们会在这里调用常用的配置类
app.config.from_object(Config)
# 编写路由视图
# flask的路由是通过给视图添加装饰器的方式进行编写的。当然也可以分离到另一个文件中。
# flask的视图函数,flask中默认允许通过return返回html格式数据给客户端。
@app.route('/') # 声明路由
def index(): # 声明视图函数
return "<h2 style='color:blue'>hello world!</h2>" # 直接通过return返回普通字符串
# 使用 app.add_url_rule() 方法注册 index() 函数,其作用与前例相同,是一种很传统的方式
# def index():
# return "<h2 style='color:blue'>hello world!</h2>"
# app.add_url_rule('/', 'index', index)
if __name__ == '__main__':
# 运行flask# 启动项目,不要在run 后面写任何代码,不会被执行到
app.run(host='0.0.0.0', port=8000) # 指定服务器IP和端口号 wsgiref模块提供的
路由参数的传递与接收
1.什么是路由?
路由: 一种访问地址[url]和应用程序[视图]进行一对一绑定的映射关系
往往在开发中,我们所说的路由,其实通常指代完成路由绑定关系的路由类
from flask import Flask
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object(Config)
# 传递路由参数没有限定类型
# @app.route(rule='/user/<user_id>-<mobile>') # 没有限定参数的类型,所以user_id可以是数字,也可以是其他类型的信息
# def index(user_id,mobile):
# return 'user_id={},mobile={}'.format(user_id,mobile)
# 接收参数并使用内置转换器
@app.route(rule='/user/<int:user_id>') # 使用flask内置的路由参数转换器
def user(user_id):
print(user_id)
return '%s' % user_id
# flask系统自带转换器编写在werkzeug.routing.py文件中
# DEFAULT_CONVERTERS = {
# "default": UnicodeConverter,
# "string": UnicodeConverter, 默认类型,接受不带斜杠的任何文本
# "any": AnyConverter,
# "path": PathConverter, 接收`string`但也接受斜线
# "int": IntegerConverter, 接受正整数
# "float": FloatConverter, 接受正浮点值
# "uuid": UUIDConverter, 接受UUID(通用唯一识别码)字符串 xxxx-xxxx-xxxxx-xxxxx
# }
if __name__ == '__main__':
app.run(host='0.0.0.0',port=8001)
自定义匹配路由
from flask import Flask
from werkzeug.routing import BaseConverter # 1.引入BaseConverter路由参数转换器基类
app = Flask(__name__)
'''
# 方法一
class MobileConverter(BaseConverter):
regex = r"1[3-9]\d{9}" # 2.指定自定义匹配的路径
def __init__(self,*args, **kwargs):
super().__init__(*args, **kwargs)
# 3. 注册路由参数转换到app应用对象中
app.url_map.converters['mobile'] = MobileConverter
# 编写路由与视图
@app.route(rule='/user/<mobile:user_mobile>')
def user(user_mobile):
print(user_mobile)
return '{}'.format(user_mobile)
# 方法二
# 自定义路由参数转换器
class RegexConveerter(BaseConverter):
def __init__(self,map,*args):
super().__init__(map)
self.regex = args[0]
# 注册路由参数转换到app应用对象中
app.url_map.converters['re'] = RegexConveerter
# 编写路由和视图
@app.route(rule="/user/<re('\d{6}'):mobile>")
def user(mobile):
print(mobile)
return '{}'.format(mobile)
'''
# 方法三
class MobileConverster(BaseConverter):
def __init__(self,*args,**kwargs):
self.regex = r'[123]\d{2}'
super().__init__(*args,**kwargs)
# app.url_map.converters["使用别名"] = 转换器类名
app.url_map.converters['mob'] = MobileConverster
@app.route(rule='/user/<mob:user_id>')
def user(user_id):
print(user_id)
return "{}".format(user_id)
if __name__ == '__main__':
app.run(debug=True,host='0.0.0.0',port=8001)
http的请求与响应
路由限定请求方式:
from flask import Flask,request
# 限制客户端的http请求方法,注意这里与django不一样,flask并没有默认没有内置csrf攻击防范
@app.route(rule="/user", methods=["post","put","get","delete","patch"])
def user():
# 例如:地址栏中通过 http://127.0.0.1:5000/user?user=1 返回本视图
print(request.method) # 获取本次客户端的http请求方法 GET
print(request.query_string) # 获取本次客户端的查询字符串 b'user=1'
print(request.path) # 获取本次客户端请求的路由路径部分[去掉域名端口] /user
print(request.url) # 获取本次客户端请求的http url地址 http://127.0.0.1:5000/user?user=1
# 直接从请求中取到请求方式并返回
return request.method
常用的属性如下:
获取请求中各项数据
from flask import Flask,request
from urllib.parse import parse_qs
from werkzeug.routing import BaseConverter
app = Flask(__name__)
# 路由转换器对路由参数的类型进行限定
# @app.route(rule="/",methods=["POST","PUT","PATCH","DELETE"])
# @app.route(rule="/") # 没有填写第二个参数methods则默认只能通过get请求访问
# def index():
# return "ok index"
@app.route(rule='/user',methods=['get','put','post','patch','delete'])
def user():
print(request.method) # 获取本次客户端的http请求方法 GET
print(request.path) # 获取本次客户端请求的路由路径部分[去掉域名端口] /user
print(request.url) # 获取本次客户端请求的http url地址 http://0.0.0.0:8000/user?user_id=11&qwq=22&qwq=33&111=qqq
print(request.json) # 获取json数据 {'username': 'xiaohuihui'}
print(request.files) # ImmutableMultiDict([('video1', <FileStorage: 'demo.mp4' ('video/mp4')>)])
print(request.files.get("avatar")) # 获取ajax或者表单中的上传文件都需要使用request.files<FileStorage: 'timg.jpeg' ('image/jpeg')>
# 获取请求头
print(request.headers) # 获取请求头 Content-Type: application/json ,User-Agent: PostmanRuntime/7.26.5........
print(request.headers.to_wsgi_list()) # [('Username', 'qwq'), ('Content-Type', 'application/json'), ('User-Agent', 'PostmanRuntime/7.26.5'), ('Accept', '*/*'), ('Postman-Token', '417ed7d2-4101-48b5-8d35-7614a2f62050'), ('Host', '0.0.0.0:8000'), ('Accept-Encoding', 'gzip, deflate, br'), ('Connection', 'keep-alive'), ('Content-Length', '38')]
# to_list() 将在1.0版中删除 改用 to_wsgi_list()
print(request.headers.get('Host')) # 获取请求头,REMOTE_ADDR客户端的地址 0.0.0.0:8000
print(request.headers.get('username')) # 获取自定义请求头,首字母大写 qwq
print(request.is_json) # 是否是ajax请求
# 获取html表单,视图必须支持post方法访问
print(request.form) # 表单中的全部数据
print(request.form.get("username")) # 表单单个数据
# 获取ajax或者表单中的上传文件都需要使用request.files
print(request.files.get("avatar")) # <FileStorage: 'timg.jpeg' ('image/jpeg')>
# 获取查询数据字符串
print(request.query_string) # 获取本次客户端的(原始)查询字符串 b'user_id=11&qwq=22&qwq=33&111=qqq'
query_string = parse_qs(request.query_string)
print('query_string:',query_string) # query_string: {b'user_id': [b'11'], b'qwq': [b'22', b'33'], b'111': [b'qqq']}
print(query_string['qwq'.encode()][0].decode()) # 22
print(request.args) # 获取本次客户端的(Dict字典)查询字符串 ImmutableMultiDict([('user_id', '11'), ('qwq', '22'), ('qwq', '33'), ('111', 'qqq')])
print(request.args.get('qwq')) # 提取一个值 22
print(request.args.getlist('qwq')) # 提取多个值 ['22', '33']
print(request.args.to_dict()) # {'user_id': '11', 'qwq': '22', '111': 'qqq'}
"""
ImmutableMultiDict的实例对象 提供了四个常用的方法给我们获取数据,
1. get 获取指定参数的第一个值
2. getlist 获取指定参数的多个值
3. to_dict 把所有参数转换成字典[request对象的部分属性不支持]
4. to_list 把所有参数转换成列表[request对象的部分属性不支持]
"""
return 'ok'
class Config():
DEBUG = True
app.config.from_object(Config)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
响应数据格式与页面跳转:
from flask import Flask,request,make_response,jsonify,Response,redirect,url_for
app = Flask(__name__)
# 一、页面跳转
@app.route("/")
def index():
# 页面跳转
# return redirect("http://www.baidu.com") # 跳转到站外
return redirect("/user") # 跳转到站内
# return redirect(url_for("user",user_id=100)) # 通过url_for指定视图名称,直接找到对应路由进行跳转
# 跳转的原理,实际就是利用HTML文档中的元信息
# response = make_response()
# response.headers["Location"] = "http://www.baidu.com"
# response.headers["Company"] = "oldboy" # 自定义响应头
# response.status_code = 302 # 自定义响应状态吗
# return response
# 二、页面反回的数据或格式
@app.route(rule='/user')
def user():
# 默认直接可以通过return返回html文本
# return "<h2 style='color:blue'>hello world!</h2>"
# return make_response("<h2 style='color:blue'>hello world!</h2>" ) # 等同于上面的一段
# return Response("<h2 style='color:blue'>hello world!</h2>") # make_response本质上就是Response
# 返回json格式数据
# data = {"name":"xiaoming","age":13}
# return jsonify(data)
# 关于Response常用的参数
# Response(response='内容', status=‘http响应状态码’, headers=自定义响应头,mimetype="数据格式" )
# 识别身份
# if request.args.get("user") == "abc":
# # 也可以返回图片,压缩包 等其他在浏览器能支持的数据,既可以支持显示图片,也可以支持显示
# with open("2.jpg", "rb") as f:
# content = f.read()
# response = make_response(content)
# response.headers["Content-Type"] = "image/jpeg"
# return response
# else:
# return "没有权限"
# 支持下载
# with open("123.zip", "rb") as f:
# response.headers["Content-Type"] = "application/zip"
# return response
# 返回图片信息
with open('1.png','rb') as f:
content = f.read()
return Response(response=content,status=201,mimetype="image/png")
# 返回文件
# with open('./1.zip',"rb") as f:
# content=f.read()
# # 判断权限,身份...
# return Response(response=content,mimetype="application/zip")
class Config():
DEBUG = True
app.config.from_object(Config)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
http的会话控制
因为 http 是一种无状态协议,浏览器请求服务器是无状态的。
无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。
有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
实现状态保持主要有两种方式:
- 在客户端存储信息使用
Cookie,token[jwt,oauth]
- 在服务器端存储信息使用
Session
Cookie
Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义。
使用场景: 登录状态, 浏览历史, 网站足迹,购物车 [不登录也可以使用购物车]
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
Cookie基于域名安全,不同域名的Cookie是不能互相访问的
如访问luffy.com时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到luffy.com写的Cookie信息
浏览器的同源策略针对cookie也有限制作用.
当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息
设置和获取 cookie:
设置cookie需要通过flask的Response响应对象来进行设置,由响应对象会提供了方法set_cookie给我们可以快速设置cookie信息。
from flask import Flask,make_response,Response,request
app = Flask(__name__)
# 设置cookie
@app.route('/set_cookie')
def set_cookie():
# resp = make_response("ok")
resp = Response("this is to set cookie", status=202) # 等同于上面 status=202返回的状态嘛
# response.set_cookie(key="变量名",value="变量值",max_age="有效时间/秒")
resp.set_cookie('username','xx',max_age=3600)
return resp
# 获取cookie
@app.route('/get_cookie')
def get_cookie():
print(request.cookies)
"""打印效果:
{'username': 'xx'}
"""
resp = request.cookies.get('username')
print(resp) # 'xx'
print(app.session_cookie_name) # session
return Response(response=resp)
# 删除cookie():
@app.route('/del_cookie')
def del_cookie():
response = make_response('删除成功! ok')
response.set_cookie("username", '',0)
return response
class Config():
DEBUG = True
app.config.from_object(Config)
if __name__ == '__main__':
app.run(host='0.0.0.0',port=8080)
设置and获取 session
from flask import Flask, session, Response, request
from datetime import timedelta
import os
app = Flask(__name__)
# 设置session
@app.route('/set_session')
def set_session():
session.permanent = True
app.permanent_session_lifetime = timedelta(seconds=10) # 设置十秒过期
session['username'] = 'this is session'
session['info'] = { # 支持python基本数据类型作为值
'age': 8,
"sex": True,
}
return Response(response=session['username'])
# 获取session
@app.route('/get_session')
def get_session():
print(session.get('username'))
print(session.get('info'))
print(app.session_cookie_name) # app.config中session_cookie_name的配置项 打印 session
return session.get('username')
# 设置secret_key(密钥)的三种方式
class Config():
SECRET_KEY = "12332112aaa" # 自定义设置密钥
DEBUG = True
app.config.from_object(Config)
# app.config['SECRET_KEY'] = os.urandom(24) # os.urandom(24)随机生成一个密钥
# app.secret_key = os.urandom(24)
# app.config.update(SECRET_KEY = os.urandom(24))
# 查看当前flask默认支持的所有配置项
# print(app.config)
"""
<Config {
'DEBUG': False,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31),
'USE_X_SENDFILE': False,
'LOGGER_NAME': '__main__',
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None,
'APPLICATION_ROOT': None,
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200),
'TRAP_BAD_REQUEST_ERRORS': False,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None
"""
if __name__ == '__main__':
app.run(host='0.0.0.0',port=8080)