处理 HTTP 响应
响应报文
响应报文主要由协议版本、状态码(status code)、原因短语(reason phrase)、响应首部和响应主体组成。
组成说明 | 响应报文内容 |
---|---|
(报文首部) 状态行(协议、状态码、原因短语) | HTTP/1.0 200 OK |
(报文首部) 各种首部字段 | Content-Type: text/html; charset=utf-8 Content-Length: 31 Server: Werkzeug/0.15.4 Python/3.10.4 Date: Wed, 03 Jul 2023 14:06:49 GMT |
空行 | |
报文主体 | <h1>Hello, flask!</h1> |
响应报文的首部包含一些关于响应和服务器的信息,这些内容由 Flask 生成,而我们在视图函数中返回的内容即为响应报文中的主体内容。浏览 器接收到响应后,会把返回的响应主体解析并显示在浏览器窗口上。
HTTP 状态码用来表示请求处理的结果
状态码
常见的 HTTP 状态码和相应的原因短语
类 型 | 状态码 | 原因短语(用于解释状态码) | 说 明 |
---|---|---|---|
成功 | 200 | OK | 请求被正常处理 |
201 | Created | 请求被处理,并创建了一个新资源 | |
204 | No Content | 请求处理成功,但无内容返回 | |
重定向 | 301 | Moved Permanently | 永久重定向 |
302 | Found | 临时性重定向 | |
304 | Not Modified | 请求的资源未被修改,重定向到缓存的资源 | |
客户端错误 | 400 | Bad Request | 表示请求无效,即请求报文中存在错误 |
401 | Unauthorized | 类似403,表示请求的资源需要获取授权信息, 在浏览器中会弹出认证弹窗 | |
403 | Forbidden | 表示请求的资源被服务器拒绝访问 | |
404 | Not Found | 表示服务器上无法找到请求的资源或URL无效 | |
服务器端错误 | 500 | Internal Server Error | 服务器内部发生错误 |
在 Flask 中生成响应
响应在 Flask 中使用 Response 对象表示,响应报文中的大部分内容由服务器处理,大多数情况下,我们只负责返回主体内容。
视图函数可以返回最多由三个元素组成的元组:响应主体、状态码、首部字段。其中首部字段可以为字典,或是两元素元组组成的列表。Flask 会调用 make_response() 方法将视图函数返回值转换为响应对象。
比如,普通的响应可以只包含主体内容:
@app.route('/')
def hello():
return '<h1>Hello, Flask!</h1>'
默认的状态码为 200,下面指定了不同的状态码
元组方式
可以返回一个元组,这样的元组必须是 (response, status, headers) 的形式,且至少包含一个元素。 status 值会覆盖状态代码, headers 可以是一个列表或字典,作为额外的消息标头值。
@app.route('/')
def hello():
...
return '<h1>Hello, Flask!</h1>', 201
有时你会想附加或修改某个首部字段。比如要生成状态码为 3XX 的
make_response 方式
from flask import make_response
@app.route('/response')
def response():
resp = make_response('make response测试')
resp.headers["code"] = "Python"
resp.status = "404 not found"
return resp
错误响应
大多数情况下,Flask 会自动处理常见的错误响应。如果你想手动返回错误响应,更方便的方法是使用 Flask 提供的 abort() 函数。
在 abort() 函数中传入状态码即可返回对应的错误响应
from flask import Flask, abort
@app.route('/not_found')
def not_found():
abort(404)
abort() 函数前不需要使用 return 语句,但一旦 abort() 函数被调用, abort() 函数之后的代码将不会被执行。
响应格式
常用的数据格式有纯文本、HTML 和 JSON,下面我们分别对这 几种数据进行简单的介绍和分析。为了对不同的数据类型进行对比,我们 将会用不同的数据类型来表示一个便签的内容:张三写给李四的一封信。
JSON
JSON 指 JavaScript Object Notation(JavaScript 对象表示法),是一种流行的、轻量的数据交换格式。JSON 轻量,简洁,容易阅读和解析,而且能和 Web 默认的客户端语言 JavaScript 更好地兼容。正是因为这种通用的数据结构,使得 JSON 在同样基于这些结构的编程语言之间交换成为可能。
Flask 通过引入 Python 标准库中的 json 模块为程序提供了 JSON ⽀持。你可以直接从 Flask 中导入 json 对象,然后调用 dumps() 方法将字典、列表或元组序列化(serialize)为 JSON 字符串,再使用前面介绍的方法修改 MIME 类型,即可返回 JSON 响应,如下所示:
from flask import Flask, make_response, json
...
@app.route('/json')
def json_view():
data = {'姓名': '张三', '性别': '男'}
resp = make_response(json.dumps(data))
resp.mimetype = 'application/json'
return resp
不过我们一般并不直接使用 json 模块的 dumps() 、load() 等方法, 因为 Flask 通过包装这些方法提供了更方便的 jsonify() 函数。借助 jsonify() 函数,我们仅需要传入数据或参数,它会对我们传入的参数进行序列化,转换成 JSON 字符串作为响应的主体,然后生成一个响应对象, 并且设置正确的 MIME 类型。
jsonify() 函数接收多种形式的参数。你既可以传入普通参数,也可以传入关键字参数。如果你想要更直观一点,也可以像使用 dumps() 方 法一样传入字典、列表或元组,比如:
from flask import jsonify
@app.route('/json2')
def json_view2():
return jsonify({"gender": "male", "name": "zhengxinonly"})
会生成下面的 JSON 字符串:
'{"gender": "male", "name": "zhengxinonly"}'
HTML
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>给李四的信</title>
</head>
<body>
<h1>给李四的信</h1>
<p>亲爱的李四:</p>
<p>你好</p>
<p><strong>生活就像是强奸,如果不能反抗,那就好好享受!</strong></p>
<p>祝:工作顺利</p>
<p>x年x月x日</p>
<p>你的朋友:张三</p>
</body>
</html>
当数据类型为 HTML 时,浏览器会自动根据 HTML 标签以及样式类定义渲染对应的样式。 这也是默认的数据类型。
网页重定向
视图函数的名字是自由定义的,和 URL 规则无关。和定义其他函数或变量一样,只需要让它表达出所要处理页面的含义即可。使用 Flask 提供的 url_for()
函数获取 URL,当路由中定义的 URL 规则被修改时,这个函数总会返回正确的 URL 。
除此之外,它还有一个重要的作用:作为代表某个路由的端点(endpoint),同时用来生成 URL。对于程序内的 URL,为了避免手写,Flask 提供了一个 url_for
函数来生成 URL,它接受的第一个参数就是端点值,默认为视图函数的名称。
from flask import url_for
@app.route('/test_url_for')
def url_for_view():
return url_for('baidu_view', user='test_url_for') # baidu_view --> /baidu
- 路由的端点即视图函数的名称
test_url_for
,调用url_for('test_url_for')
即可 获取对应的 URL,即/test_url_for
。 - 在
app.route()
装饰器中使用endpoint
参数可以自定义端点值,不过我们通常不需要这样做。 - 如果URL含有动态部分,那么我们需要在
url_for()
函数里传入相应的参数
在 Web 程序中,我们经常需要进行重定向。比如,当某个用户在没有经过认证的情况下访问需要登录后才能访问的资源,程序通常会重定向到登录页面。
对于重定向这一类特殊响应,Flask 提供了一些辅助函数。除了像前面 那样手动生成302响应,我们可以使用 Flask 提供的 redirect()
函数来生成 重定向响应,重定向的目标 URL 作为第一个参数。前面的例⼦可以简化 为:
from flask import Flask, redirect
@app.route('/baidu')
def baidu_view():
return redirect('https://www.baidu.com')
重定向流程示意图
危险
必须是浏览器发送的请求,后端重定向才会自动生效。