Flask 访问请求数据

对于 Web 应用,与客户端发送给服务器的数据交互至关重要。在 Flask 中
由全局的 request 对象来提供这些信息。如果你有一定的
Python 经验,你会好奇,为什么这个对象是全局的,为什么 Flask 还能保证
线程安全。答案是环境作用域:

环境局部变量

内幕

如果你想理解其工作机制及如何利用环境局部变量实现自动化测试,请阅
读此节,否则可跳过。

Flask 中的某些对象是全局对象,但却不是通常的那种。这些对象实际上是特定
环境的局部对象的代理。虽然很拗口,但实际上很容易理解。

想象一下处理线程的环境。一个请求传入,Web 服务器决定生成一个新线程(
或者别的什么东西,只要这个底层的对象可以胜任并发系统,而不仅仅是线程)。
当 Flask 开始它内部的请求处理时,它认定当前线程是活动的环境,并绑定当
前的应用和 WSGI 环境到那个环境上(线程)。它的实现很巧妙,能保证一个应
用调用另一个应用时不会出现问题。

所以,这对你来说意味着什么?除非你要做类似单元测试的东西,否则你基本上
可以完全无视它。你会发现依赖于一段请求对象的代码,因没有请求对象无法正
常运行。解决方案是,自行创建一个请求对象并且把它绑定到环境中。单元测试
的最简单的解决方案是:用 test_request_context()
境管理器。结合 with 声明,绑定一个测试请求,这样你才能与之交互。下面
是一个例子:

from flask import request

with app.test_request_context('/hello', method='POST'):
    # now you can do something with the request until the
    # end of the with block, such as basic assertions:
    assert request.path == '/hello'
    assert request.method == 'POST'

另一种可能是:传递整个 WSGI 环境给
request_context() 方法:

from flask import request

with app.request_context(environ):
    assert request.method == 'POST'

请求对象

API 章节对请求对象作了详尽阐述(参见 request ),因此这
里不会赘述。此处宽泛介绍一些最常用的操作。首先从 flask 模块里导入它:

from flask import request

当前请求的 HTTP 方法可通过 method 属性来访问。通
过:attr:~flask.request.form 属性来访问表单数据( POSTPUT 请求
提交的数据)。这里有一个用到上面提到的那两个属性的完整实例:

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template('login.html', error=error)

当访问 form 属性中的不存在的键会发生什么?会抛出一个特殊的
KeyError 异常。你可以像捕获标准的 KeyError 一样来捕获它。
如果你不这么做,它会显示一个 HTTP 400 Bad Request 错误页面。所以,多数
情况下你并不需要干预这个行为。

你可以通过 args 属性来访问 URL 中提交的参数
( ?key=value ):

searchword = request.args.get('q', '')

我们推荐用 get 来访问 URL 参数或捕获 KeyError ,因为用户可能会修
改 URL,向他们展现一个 400 bad request 页面会影响用户体验。

欲获取请求对象的完整方法和属性清单,请参阅 request
文档。

文件上传

用 Flask 处理文件上传很简单。只要确保你没忘记在 HTML 表单中设置
enctype=”multipart/form-data” 属性,不然你的浏览器根本不会发送文件。

已上传的文件存储在内存或是文件系统中一个临时的位置。你可以通过请求对象
的 files 属性访问它们。每个上传的文件都会存储在
这个字典里。它表现近乎为一个标准的 Python file 对象,但它还有
一个 save() 方法,这个方法
允许你把文件保存到服务器的文件系统上。这里是一个用它保存文件的例子:

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() 函数:

from flask import request
from werkzeug 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))
    ...

一些更好的例子,见 上传文件 模式。

Cookies

你可以通过 cookies 属性来访问 Cookies,用
响应对象的 set_cookie 方法来设置 Cookies。请
求对象的 cookies 属性是一个内容为客户端提交的
所有 Cookies 的字典。如果你想使用会话,请不要直接使用 Cookies,请参
会话 一节。在 Flask 中,已经注意处理了一些 Cookies 安全
细节。

读取 cookies:

from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not get a
    # KeyError if the cookie is missing.

存储 cookies:

from flask import make_response

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp

可注意到的是,Cookies 是设置在响应对象上的。由于通常视图函数只是返
回字符串,之后 Flask 将字符串转换为响应对象。如果你要显式地转换,你
可以使用 make_response() 函数然后再进行修改。

有时候你想设置 Cookie,但响应对象不能醋在。这可以利用
延迟请求回调
模式实现。

为此,也可以阅读 关于响应

作者:admin,如若转载,请注明出处:https://www.web176.com/flask2/21767.html

(0)
打赏 支付宝 支付宝 微信 微信
adminadmin
上一篇 2023年5月18日
下一篇 2023年5月18日

相关推荐

发表回复

登录后才能评论