优秀的编程知识分享平台

网站首页 > 技术文章 正文

Flask的基础用法之四(flask rq)

nanyue 2024-10-15 11:33:17 技术文章 4 ℃

十一、文件上传

用 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')
 ...

对应的html表单如下:

 <form method=post enctype=multipart/form-data>
 <input type=file name='the_file'>
 <input type=submit value=Upload>
 </form>

如果想要知道文件上传之前其在客户端系统中的名称,可以使用 filename 属性。但是请牢记这个值是 可以伪造的,永远不要信任这个值。如果想要把客户端的文件名作为服务器上的文件名, 可以通过 Werkzeug 提供的secure_filename() 函数:

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

更好的例子参见 上传文件 方案。

十二、Cookies

要访问 cookies ,可以使用 cookies 属性。可以使用响应 对象 的 set_cookie 方法来设置 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 。

重定向和错误

使用 redirect() 函数可以重定向。使用 abort() 可以 更早退出请求,并返回错误代码:

from flask import abort, redirect, url_for
@app.route('/')
def index():
 return redirect(url_for('login'))
@app.route('/login')
def login():
 abort(401)
 this_is_never_executed()

上例实际上是没有意义的,它让一个用户从索引页重定向到一个无法访问的页面(401 表示禁止访问)。但是上例可以说明重定向和出错跳出是如何工作的。

缺省情况下每种出错代码都会对应显示一个黑白的出错页面。使用 errorhandler() 装饰器可以定制出错页面:

from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
 return render_template('page_not_found.html'), 404

注意 render_template() 后面的 404 ,这表示页面对应的出错 代码是 404 ,即页面不存在。缺省情况下 200 表示:一切正常。

详见 错误处理 。

十三、关于响应

视图函数的返回值会自动转换为一个响应对象。如果返回值是一个字符串,那么会被转换 为一个包含作为响应体的字符串、一个 200 OK 出错代码 和一个 text/html 类型的响应对象。以下是转换的规则:

  1. 如果视图返回的是一个响应对象,那么就直接返回它。
  2. 如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的 响应对象。
  3. 如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由 (response, status, headers) 或者 (response, headers) 组成。 status 的值会重载状态代码, headers 是一个由额外头部值组成的列表或字典。
  4. 如果以上都不是,那么 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

十四、会话

除了请求对象之外还有一种称为 session 的对象,允许你在不同请求 之间储存信息。这个对象相当于用密钥签名加密的 cookie ,即用户可以查看你的 cookie ,但是如果没有密钥就无法修改它。

使用会话之前你必须设置一个密钥。举例说明:

from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/')
def index():
 if 'username' in session:
 return 'Logged in as %s' % escape(session['username'])
 return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])
def login():
 if request.method == 'POST':
 session['username'] = request.form['username']
 return redirect(url_for('index'))
 return ''' 对应的HTML form 表单
 <form method="post">
 <p><input type=text name=username>
 <p><input type=submit value=Login>
 </form>
 '''
@app.route('/logout')
def logout():
 # remove the username from the session if it's there
 session.pop('username', None)
 return redirect(url_for('index'))

这里用到的 escape() 是用来转义的。如果不使用模板引擎就可以像上例 一样使用这个函数来转义。

如何生成一个好的密钥

生成随机数的关键在于一个好的随机种子,因此一个好的密钥应当有足够的随机性。 操作系统可以有多种方式基于密码随机生成器来生成随机数据。使用下面的命令 可以快捷的为 Flask.secret_key ( 或者 SECRET_KEY )生成值:

$ python -c 'import os; print(os.urandom(16))'

b'_5#y2L"F4Q8z\n\xec]/'

基于 cookie 的会话的说明: Flask 会取出会话对象中的值,把值序列化后储存到 cookie 中。在打开 cookie 的情况下,如果需要查找某个值,但是这个值在请求中 没有持续储存的话,那么不会得到一个清晰的出错信息。请检查页面响应中的 cookie 的大小是否与网络浏览器所支持的大小一致。

除了缺省的客户端会话之外,还有许多 Flask 扩展支持服务端会话。

十五、日志

有时候可能会遇到数据出错需要纠正的情况。例如因为用户篡改了数据或客户端代码出错 而导致一个客户端代码向服务器发送了明显错误的 HTTP 请求。多数时候在类似情况下 返回 400 Bad Request 就没事了,但也有不会返回的时候,而代码还得继续运行 下去。

这时候就需要使用日志来记录这些不正常的东西了。自从 Flask 0.3 后就已经为你配置好 了一个日志工具。

以下是一些日志调用示例:

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')

logger 是一个标准的 Logger Logger 类, 更多信息详见官方的 logging 文档 。

更多内容请参阅 应用错误处理 。

最近发表
标签列表