外观
Flask响应
Flask响应是由Request对象完成的,但是一般情况下只处理请求即可。
处理404请求
在浏览器输入网址后Flask会先检测是否有与该路径匹配的路由,若没有则会返回404状态。默认的404页面是一串英文,我们可以将其改为自己的页面,代码如下:
from flask import Flask, render_template
app = Flask(__name__)
@app.errorhandler(404)
def page_not_found(e): # 这里需要传递一个参数:e,代表错误的对象
print(e)
return '404'
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
app.run()处理其他请求
如处理302重定向请求,就需要将首部字段的Location设为重定向至的URL,示例代码:
@app.route('/index')
def index():
return '', 302, {'Location': 'https://qi1.zone'}当访问127.0.0.1:5000时,会重定向至https://qi1.zone。但是在多数情况下,只需要返回主体即可。
响应格式
MIME类型
在HTTP响应中,数据可以以多种方式传输,最常见的方式就是返回一个HTML代码,然后浏览器将其解析并呈现出页面。Flask的默认返回类型也是HTML代码,这时我们可以通过设置MIME类型来改变返回页面的类型。MIME类型在首部的Content-Type字段中定义。以默认的HTML类型为例,Content-Type类型如下:
Content-Type: text/html; charset=utf-8但是在特定的情况下,也会使用其他格式。此时可以通过Flask提供的make_response()生成响应对象,传入相应的主体作为参数,然后使用响应对象的mimetype属性设置MIME类型。示例代码如下:
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def index():
response = make_response('Hello World!')
response.mimetype = 'text/plain'
return response
if __name__ == '__main__':
app.run()常用的格式有纯文本、HTML、XML和JSON,它们对应的MIME类型如下:
- 纯文本:text/plain
- HTML:text/html
- XML:application/xml
- JSON:application/json
下面将演示如何返回JSON数据。
JSON数据格式
JSON,JavaScript对象表示法,是一种流行的、轻量的数据交换格式。它由“键值对”组成,类似于Python的字典。
对于JSON格式,MIME类型为application/json,Python处理JSON的笔记请见Python基础部分笔记。在Flask框架中,我们可以不使用json模块的load()和dumps()方法,而是使用Flask提供的jsonify()方法处理JSON字符串。
使用json.dumps()返回:
@app.route('/')
def index():
data = {'name': '棋', 'age': 20}
response = make_response(json.dumps(data))
response.mimetype = 'application/json'
return response使用jsonify()返回:
@app.route('/')
def index():
return jsonify(name='棋', age=20)jsonify()函数既可以传入关键字参数,也可以传入普通参数,如:
jsonify({'name': '棋', 'age': 20})Cookie和Session
HTTP是无状态协议,用户跳转到其他网页时浏览器不会保存数据,这对登录以及其他需要传递信息的工作来说非常不方便。因此Cookie就诞生了。Cookie是服务器为了存储某些数据而保存在浏览器的小型文本信息,浏览器会将此信息保存一段时间,并在下一次向同一个服务器发送请求时附带这些数据,以便于进行会话管理。
在Flask中,使用Response类提供的set_Cookie()方法就可以在响应中添加一个Cookie。首先使用make_response()生成一个响应对象,传入相应主体作为参数。这个方法返回的默认为内置的Response对象,内置的Response对象有如下属性和方法:
- headers:一个Werkzeug的headers对象,表示响应首部,可以像字典一样操作
- status:状态
- status_code:状态码,文本类型
- mimetype:MIME类型,仅包含内容类型部分
- set_cookie:用来设置Cookie
- get_json:解析为JSON数据
- is_json:判断是否为JSON数据
其中,set_cookie()方法支持使用多个参数来设置Cookie选项,如下:
- key:cookie的键/名称
- value:cookie的值
- max_age:cookie的保存时间,单位为秒。默认在用户会话结束(关闭浏览器)时过期
- expires:具体的过期时间,一个datetime对象或UNIX时间戳
- path:下载Cookie时只有指定的URL可用,默认为整个域名‘
- domain:设置Cookie可用的域名
- secure:若为True,代表只有通过HTTPS才可以使用
- httponly:若为True,将禁止客户端Javascript获取cookie
例:
# app.py
from flask import Flask, request, render_template, make_response, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = 'qi1' # 设置表单密钥
class LoginForm(FlaskForm): # 表单模型
user = StringField('用户名', [DataRequired('请输入用户名')]) # 用户名字段
password = PasswordField('密码', [DataRequired('请输入密码')]) # 密码字段
submit = SubmitField('提交') # 提交按钮
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
user = request.form['user'] # 获取表单中user字段的值
password = request.form['password'] # 获取表单中password字段的值
if user == 'qi' and password == '123456':
response = make_response('登录成功')
response.set_cookie(key='user', value=user) # 设置cookie
return response
else:
return '登录失败'
else:
return render_template('login.html', form=LoginForm()) # 渲染表单
@app.route('/')
def index():
user = request.cookies.get('user')
if user is not None:
return f'欢迎{user}'
else:
return redirect(url_for('login'))
if __name__ == '__main__':
app.run()<!-- login.html -->
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>登录</title>
</head>
<body>
{{ form.csrf_token }}
<form action="" method="post">
{{ form.user.label }}:{{ form.user }}<br/>
{{ form.password.label }}:{{ form.password }}<br/>
{{ form.submit }}
</form>
</body>
</html>运行此代码后输入127.0.0.1:5000后,由于用户未登录,因此会重定向至127.0.0.1:5000/login。在用户名密码输入框内正确输入密码后就会显示登录成功,此时在输入127.0.0.1:5000后就会显示登录成功的用户信息。
Session对象
上面的例子我们在用户登录成功后添加的Cookie是以明文方式显示的,这样恶意用户就可以通过伪造Cookie的方式非法获取网页中的内容。这时我们就可以通过Flask提供的Session对象解决这个问题。Session指用户会话,或对话,它用于加密Cookie,默认情况下它会把数据存储在名为Session的Cookie中。Session需要密钥加密数据对数据进行签名以加密数据,因此需要设置一个密钥,这个密钥可以通过密码生成工具生辰复杂度较高的密钥。
在下面的例子我们将上面run.py中的代码做如下改动:
# app.py
from flask import Flask, request, render_template, make_response, redirect, url_for, session
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = 'qi1' # 设置表单密钥
class LoginForm(FlaskForm): # 表单模型
user = StringField('用户名', [DataRequired('请输入用户名')]) # 用户名字段
password = PasswordField('密码', [DataRequired('请输入密码')]) # 密码字段
submit = SubmitField('提交') # 提交按钮
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
user = request.form['user'] # 获取表单中user字段的值
password = request.form['password'] # 获取表单中password字段的值
if user == 'qi' and password == '123456':
session['user'] = user
return '登录成功'
else:
return '登录失败'
else:
return render_template('login.html', form=LoginForm()) # 渲染表单
@app.route('/logout')
def logout():
session.pop('user')
return redirect(url_for('login'))
@app.route('/')
def index():
user = session.get('user')
if user is not None:
return f'欢迎{user}'
else:
return redirect(url_for('login'))
if __name__ == '__main__':
app.run()