Flask -请求
来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应该从Flask模块导入。
某些对象在 Flask 中是全局对象,但不是通常意义下的全局对象。这些对象实际上是 特定环境下本地对象的代理。真拗口!但还是很容易理解的。
设想现在处于处理线程的环境中。一个请求进来了,服务器决定生成一个新线程(或者 叫其他什么名称的东西,这个下层的东西能够处理包括线程在内的并发系统)。当 Flask 开始其内部请求处理时会把当前线程作为活动环境,并把当前应用和 WSGI 环境绑定到 这个环境(线程)。它以一种聪明的方式使得一个应用可以在不中断的情况下调用另一个 应用。
Request对象的重要属性如下所列:
- Form - 它是一个字典对象,包含表单参数及其值的键和值对。(在
POST
或者PUT
请求 中传输的数据)> 当form
属性中不存在这个键时会发生什么?会引发一个KeyError
。 如果你不像捕捉一个标准错误一样捕捉KeyError
,那么会显示一个 HTTP 400 Bad Request 错误页面。因此,多数情况下你不必处理这个问题。
- args - 解析查询字符串的内容,它是问号(?)之后的URL的一部分。> 要操作 URL (如
?key=value
)中提交的参数可以使用args
属性:searchword = request.args.get('key', '')
用户可能会改变 URL 导致出现一个 400 请求出错页面,这样降低了用户友好度。因此, 我们推荐使用 get 或通过捕捉
KeyError
来访问 URL 参数。127.0.0.1:5000/get_user_info?username=1&password=1
- Cookies - 保存Cookie名称和值的字典对象。> Cookie以文本文件的形式存储在客户端的计算机上。其目的是记住和跟踪与客户使用相关的数据,以获得更好的访问者体验和网站统计信息。
Request对象包含Cookie的属性。它是所有cookie变量及其对应值的字典对象,客户端已传输。除此之外,cookie还存储其网站的到期时间,路径和域名。 在Flask中,对cookie的处理步骤为: 设置cookie
设置cookie,默认有效期是临时cookie,浏览器关闭就失效 可以通过 max_age 设置有效期, 单位是秒
resp = make_response("success") # 设置响应体
resp.set_cookie("test_code", "test_code", max_age=3600)
获取cookie
获取cookie,通过reques.cookies的方式, 返回的是一个字典,可以获取字典里的相应的值
cookie_1 = request.cookies.get("test_code")
删除cookie
这里的删除只是让cookie过期,并不是直接删除cookie 删除cookie,通过delete_cookie()的方式, 里面是cookie的名字
resp = make_response("del success") # 设置响应体
resp.delete_cookie("test_code")
以下为Flask Cookies的简单示例:```python
from flask import Flask, render_template, request, redirect, session
app = Flask(name) # flask object app.secret_key = “abiding”
app.debug = True
@app.route(“/login”, methods=[‘GET’, ‘POST’]) def login(): “””request.args # in url method== “get””” user = request.form.get(“user”) pwd = request.form.get(“pwd”) if user == pwd == “admin”: print(“a”) session[‘user_info_username’] = user session[‘user_info_password’] = pwd return redirect(“/index”) else: return render_template(‘login.html’, message=”username or password is null “)
@app.route(‘/‘) def hello_world(): return render_template(“index.html”)
@app.route(“/index”) def index(): user_info_username = session.get(‘user_info_username’) user_info_password = session.get(“user_info_password”) print(user_info_username, user_info_password) if all([user_info_password, user_info_username]): return render_template(“index.html”, index_title=”user.index”) else: return redirect(“/“)
@app.route(“/logout”) def logout(): del session[“user_info_username”] del session[“user_info_password”] return “hello world”
if name == ‘main‘: app.run()
> 注意删除,只是让 cookie 过期。
- **Sessions(会话)**<br />与Cookie不同,**Session(会话)**数据存储在服务器上。会话是客户端登录到服务器并注销服务器的时间间隔。需要在该会话中保存的数据会存储在服务器上的临时目录中。<br />为每个客户端的会话分配**会话ID**。会话数据存储在cookie的顶部,服务器以加密方式对其进行签名。对于此加密,Flask应用程序需要一个定义的**SECRET_KEY**。<br />Session对象也是一个字典对象,包含会话变量和关联值的键值对。<br />例如,要设置一个**'username'**会话变量,请使用以下语句:<br />在使用前必须设置key```python
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
正式使用session```python
Session[‘username’] = ’admin’
<br />要释放会话变量,请使用**pop()**方法。```python
session.pop('username', None)
- files - 与上传文件有关的数据。> 用 Flask 处理文件上传很容易,只要确保不要忘记在你的 HTML 表单中设置
enctype="multipart/form-data"
属性就可以了。否则浏览器将不会传送你的文件。已上传的文件被储存在内存或文件系统的临时位置。你可以通过请求对象
files
属性来访问上传的文件。每个上传的文件都储存在这个 字典型属性中。这个属性基本和标准 Pythonfile
对象一样,另外多出一个 用于把上传文件保存到服务器的文件系统中的save()
方法。下例展示其如何运作: ```python from flask import request
@app.route(‘/upload’, methods=[‘GET’, ‘POST’]) def upload_file(): if request.method == ‘POST’: f = request.files[‘the_file’] f.save(‘/var/www/uploads/uploaded_file.txt’)
> 如果想要知道文件上传之前其在客户端系统中的名称,可以使用 `filename`属性。但是请牢记这个值是 可以伪造的,永远不要信任这个值。如果想要把客户端的文件名作为服务器上的文件名, 可以通过 Werkzeug 提供的 `secure_filename()`函数:
> ```python
from werkzeug.utils import secure_filename
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/' + secure_filename(f.filename))
- method - 当前请求方法。
- redirect-重定向和错误
- 重定向
Flask类有一个redirect()函数。调用时,它返回一个响应对象,并将用户重定向到具有指定状态代码的另一个目标位置。 redirect()函数的原型如下:
Flask.redirect(location, statuscode, response)
在上述函数中:
- location参数是应该重定向响应的URL。
- statuscode发送到浏览器标头,默认为302。
- response参数用于实例化响应。
以下状态代码已标准化:
- HTTP_300_MULTIPLE_CHOICES
- HTTP_301_MOVED_PERMANENTLY
- HTTP_302_FOUND
- HTTP_303_SEE_OTHER
- HTTP_304_NOT_MODIFIED
- HTTP_305_USE_PROXY
- HTTP_306_RESERVED
- HTTP_307_TEMPORARY_REDIRECT
默认状态代码为302,表示‘found’。 在以下示例中,redirect()函数用于在登录尝试失败时再次显示登录页面。 ```python from flask import Flask, redirect, url_for, render_template, request
Initialize the Flask application
app = Flask(name)
- 重定向
@app.route(‘/‘) def index(): return render_template(‘log_in.html’)
@app.route(‘/login’,methods = [‘POST’, ‘GET’]) def login(): if request.method == ‘POST’ and request.form[‘username’] == ‘admin’ : return redirect(url_for(‘success’)) return redirect(url_for(‘index’))
@app.route(‘/success’) def success(): return ‘logged in successfully’
if name == ‘main‘: app.run(debug = True)
> Flask类具有带有错误代码的**abort()**函数。
>
Flask.abort(code)
> **Code**参数采用以下值之一:
> - **400** - 用于错误请求
> - **401** - 用于未身份验证的
> - **403** - Forbidden
> - **404** - 未找到
> - **406** - 表示不接受
> - **415** - 用于不支持的媒体类型
> - **429** - 请求过多
>
让我们对上述代码中的**login()**函数稍作更改。如果要显示**'Unauthurized'**页面,请将其替换为调用**abort(401)**,而不是重新显示登录页面。
> ```python
from flask import Flask, redirect, url_for, render_template, request, abort
app = Flask(__name__)
@app.route('/')
def index():
return render_template('log_in.html')
@app.route('/login',methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
if request.form['username'] == 'admin' :
return redirect(url_for('success'))
else:
abort(401)
else:
return redirect(url_for('index'))
@app.route('/success')
def success():
return 'logged in successfully'
if __name__ == '__main__':
app.run(debug = True)
Flask -响应
- 平常格式输出
视图函数的返回值会自动转换为一个响应对象。如果返回值是一个字符串,那么会被 转换为一个包含作为响应体的字符串、一个200 OK
出错代码 和一个 text/html 类型的响应对象。如果返回值是一个字典,那么会调用jsonify()
来产生一个响应。以下是转换的规则:- 如果视图返回的是一个响应对象,那么就直接返回它。
- 如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的 响应对象。
- 如果返回的是一个字典,那么调用
jsonify
创建一个响应对象。 - 如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由
(response, status)
、(response, headers)
或者(response, status, headers)
组成。status
的值会重载状态代码,headers
是一个由额外头部值组成的列表 或字典。 - 如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为 一个响应对象。
如果想要在视图内部掌控响应对象的结果,那么可以使用 make_response()
)函数。
设想有如下视图:
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
可以使用 make_response()
包裹返回表达式,获得响应对象,并对该对象 进行修改,然后再返回:
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
JSON 格式的 API
JSON 格式的响应是常见的,用 Flask 写这样的 API 是很容易上手的。如果从视图 返回一个dict
,那么它会被转换为一个 JSON 响应。```python @app.route(“/me”) def me_api(): user = get_current_user() return {"username": user.username,
"theme": user.theme,
"image": url_for("user_image", filename=user.image),
}
<br />如果 `dict` 还不能满足需求,还需要创建其他类型的 JSON 格式响应,可以使用 `jsonify()`函数。该函数会序列化任何支持的 JSON 数据类型。 也可以研究研究 Flask 社区扩展,以支持更复杂的应用。```python
@app.route("/users")
def users_api():
users = get_all_users()
return jsonify([user.to_json() for user in users])
消息闪现
一个好的应用和用户接口都有良好的反馈,否则到后来用户就会讨厌这个应用。 Flask 通过闪现系统来提供了一个易用的反馈方式。闪现系统的基本工作原理是在请求结束时 记录一个消息,提供且只提供给下一个请求使用。通常通过一个布局模板来展现闪现的 消息。flash()
用于闪现一个消息。在模板中,使用get_flashed_messages()
来操作消息。完整的例子参见 消息闪现```python from flask import Flask, flash, redirect, render_template, request, url_for app = Flask(name) app.secret_key = ‘random string’ @app.route(‘/‘) def index(): return render_template(‘index.html’) @app.route(‘/login’, methods = [‘GET’, ‘POST’]) def login(): error = None if request.method == ‘POST’:if request.form['username'] != 'admin' or \
request.form['password'] != 'admin':
error = 'Invalid username or password. Please try again!'
else:
flash('You were successfully logged in')
return redirect(url_for('index'))
return render_template(‘login.html’, error = error)
if name == “main”: app.run(debug = True)
<a name="aba0bb19"></a>
## Flask-日志
有时候可能会遇到数据出错需要纠正的情况。例如因为用户篡改了数据或客户端代码出错 而导致一个客户端代码向服务器发送了明显错误的 HTTP 请求。多数时候在类似情况下 返回 `400 Bad Request` 就没事了,但也有不会返回的时候,而代码还得继续运行 下去。
这时候就需要使用日志来记录这些不正常的东西了。自从 Flask 0.3 后就已经为你配置好 了一个日志工具。
以下是一些日志调用示例:
```python
@app.route("/login", methods=['GET', 'POST'])
def login():
"""
[2020-11-16 23:38:08,890] WARNING in app: A warning occurred (42 apples)
[2020-11-16 23:38:08,890] ERROR in app: An error occurred
127.0.0.1 - - [16/Nov/2020 23:38:08] "GET /login HTTP/1.1" 200 -
[2020-11-16 23:38:14,911] WARNING in app: A warning occurred (42 apples)
[2020-11-16 23:38:14,911] ERROR in app: An error occurred
"""
app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
"""request.args # in url method== "get"""
user = request.form.get("user")
pwd = request.form.get("pwd")
if user == pwd == "admin":
session['user_info_username'] = user
session['user_info_password'] = pwd
return redirect("/index")
else:
return render_template('login.html', message="username or password is null ")
Flask-集成 WSGI 中间件
如果想要在应用中添加一个 WSGI 中间件,那么可以包装内部的 WSGI 应用。假设为了 解决 lighttpd 的错误,你要使用一个来自 Werkzeug 包的中间件,那么可以这样做:
from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)