Flask 请求和响应

来源:互联网 发布:喇叭测试软件 编辑:程序博客网 时间:2024/05/16 14:58

一、请求调度

浏览器通过URL访问Flask服务器时,要通过URL和视图函数的映射关系表找到处理该URL的视图函数(该视图函数返回响应给浏览器),这个映射关系可以通过app.route修饰器建立。下面给出了上一篇文章中的helloworld例子

#coding:utf-8from flask import Flaskapp=Flask(__name__)@app.route("/")def index():return "<h1>Hello World!</h1>"@app.route("/user/<name>")def user(name):return "<h1>Hello,%s</h1>"%nameif __name__=="__main__":app.run(debug=True,host="0.0.0.0",port=8000)
例子中将程序根目录URL和视图函数index映射起来。可以在python命令行通过app.url_map查看这种映射关系:

HEAD,OPTIONS,GET是URL与视图函数的请求方法,HEAD和OPTIONS为Flask自动处理,功能分别为获取响应报文首部(即不发送报文主体)和询问访问某URL支持的方法。 可以通过route修饰器的methods参数为路由指定不同的请求方法,比较常用的是GET和POST方法。

二、程序和请求上下文

视图函数在处理请求时,有时需要获取一些其他对象信息,这个时候的处理方式是使用线程独立的全局变量而非传参,比如请求对象request等(其他上下文全局变量如下表)。上下文可以理解为对这些对象的引用池,方便我们随时访问这些变量。

Flask上下文全局变量变量名上下文说明current_app程序上下文当前激活的程序实例,比如helloworld例子中的appg程序上下文用作处理请求时的临时存储,每次请求都重设request请求上下文请求对象,包含了客户端HTTP请求的内容,例如获取客户端请求报文头部中包含的
User-Agent信息:request.headers.get("User-Agent")session请求上下文用户会话,字典格式,存储请求间需要记住的信息

从flask中引入上下文变量就可以使用这些变量,例如下面的视图函数返回请求中的User-Agent给客户端:

@app.route("/user-agent/")def get_user_agent():user_agent=request.headers.get("User-Agent")return "<p>%s</p>"%user_agent

输入URL http://127.0.0.1:8000/user-agent/ 访问:


Falsk上下文在请求之前会先激活,请求处理完毕则会将其删除。

三、响应

响应即视图函数的返回值,上述例子中的返回都很简单,直接将html代码作为返回值。但是Flask Http协议的返回值中通常还会有以下几种不同的格式:

1.元组:(html字符串,状态码,返回报文首部信息)

状态响应码:Flask默认为200(故此时可省略),即请求成功处理。一些常用的状态码如下:

    2xx成功:200(请求成功处理)、204(请求成功处理但无资源返回)、206(请求部分内容成功,在请求报文实体首部中包含需要的资源)

    3xx重定向:301(永久性重定向,表示访问资源已经更新了URI,通常在返回报文首部信息增加Location提示新的URI,如果访问的URI保存为书签,则会被更新为新的URI)

                          302(临时性重定向,表示此次访问资源被重定向到新的URI,并非永久,不更新书签)

                          304(资源不满足客户端请求条件,比如请求的是某时间点后有更新则返回新资源,但资源在该时间点后无更新,被规在3xx,但和重定向没啥关系)

    4xx客户端错误:400(客户端请求存在错误,应该修改请求后再次发送)、401(未授权)、403(禁止访问)、404(找不到访问的资源)

    5xx服务器错误:500(服务器处理请求时出现错误)、503(服务器忙碌或者停机维护无法处理请求)

返回报文首部信息:比如包含重定向时,包含URI的Location信息,{"Location":"http:xxx"},很少用到,可省略。

2.Response对象

make_response()函数生成Response对象,函数接受1、2、3个参数,参数意义和元组形式一致,可以对响应进行一些设置后返回,比如设置cookie。

from flask import make_response@app.route("/response/")def response():response=make_response("<h1>This response carries a cookie</h1>")response.set_cookie("answer","42")return response

浏览器访问后再次请求f12查看请求头中包含设置的cookie。


3.使用redirect函数

常用来跳转到重定向的url,比如return redirect("http://www.baidu.com/")

from flask import redirect@app.route("/redirect")def test_redirect():return redirect("http://www.baidu.com/")

4.使用abort函数处理错误

通常用来抛出异常,把控制权交给web服务器返回异常,比如:abort(404)

5.使用渲染模板

前述的例子都太简单,通常一个http请求的处理可能会涉及复杂的业务逻辑和表现逻辑,比如在某网站注册账号的时候,通过POST方法提交一个表单给服务器,服务器需要通过表单内容来生成一个新用户并进行数据库相关操作,然后再给客户端返回一个处理完毕的响应。模板的作用是处理表现逻辑,把业务逻辑和表现逻辑分开,提升代码的可维护性。Flask使用了Jinja2模板引擎。

最简单的helloworld模板可以这样使用:在helloworld.py同一目录下创建templates文件夹,然后把模板文件放在文件夹中,比如'helloworld.html",然后通过Flask的render_template函数渲染模板,并作为视图函数返回值即可。

from flask import render_template@app.route("/")def index():return render_template("helloworld.html")
模板文件包含响应文本:

访问“http://127.0.0.1:8000”可以看到效果和原来一样~

复杂的响应文本中会包含逻辑语句以及变量,变量真实值可以通过render_template传递。使用真实值替换模板中的变量,得到最终的响应文本,这个过程即称为渲染模板。

三、模板

1.变量

模板中的变量使用双大括号占位+变量名表示:比如{{ name }}。我们可以把helloword例子的user视图函数替换成模板渲染后返回:

新增模板文件templates/user.html:

<h1>Hello,{{ name }}</h1>
user视图函数:

@app.route("/user/<name>")def user(name):return render_template("user.html",name=name)
访问url可以看到效果:


上述例子使用url中的<name>字符串作为变量传递给视图函数,视图函数又将之传递给模板渲染后返回响应。Jinja2可以识别复杂的对象,比如可以把一个用户对象传递给模板,然后在模板中访问对象的各个属性变量。例如 {{ user.username }} 获取user对象的username属性。

变量可以用过滤器修改,Jinja2提供了一些常用的过滤器,使用格式为{{ 变量名|过滤器名 }}比如要将上述模板中的name变量全部以大写字母显示,可以修改user.html如下:

效果:

常用的Jinja2过滤器有:

过滤器名说明safe渲染值时不转义,默认情况下安全起见,jinja2会将html标签在渲染时会被转义掉(比如左尖括号转义为&lt;),使用这个过滤器可以保护这些标签不被过滤(对可信的变量比如服务器自己生成的html串采用)capitalize首字母大写,其他字母小写lower小写形式upper大写形式title每个单词首字母大写trim去掉值首尾空格striptags把值中所有的HTML标签删除

2.控制语句,结构: {% 语句 %}

①条件语句

{% if name %}    Hello,{{ user }}!{% else %}    Hello,Stranger!{% endif %}

②for循环

<ul>    {% for user in users %}        <li>user.username</li>    {% endfor %}</ul>

③宏 定义格式类似于函数,比如可以定义一个宏,然后再调用这个宏,使用宏定义的格式替换调用的部分

定义:关键字macro

{% macro render_comment(comment) %}<li>{{ comment }}</li>{% endmacro %}
调用:{{ 宏名(参数) }}

<ul>{% for comment in comments %}{{ render_comment(comment) }}{% endfor %}</ul>
也可以将宏单独保存在一个文件中,再调用的文件中使用 import语句引入。

{% import "_macro.html" as macro %}<ul>{% for comment in comments %}{{ macro.render_comment(comment) }}{% endfor %}</ul>
④导入代码片,其作用是代码重用,如下可将_comments.html中的代码片段包含到模板文件中。

{% include "_comments.html" %}
⑤模板继承,比如同一个网站的不同网页通常有一些相同或相似的格式,这时候可以把这些相似的样式写在一个基模板中,同时预留可供扩展的block区域,其他页面可通过继承该模板,并在对应block区域扩展自己页面的内容:

基模板base.html:

<!DOCTYPE html><html><head>{% block head %}<title>{% block title %}{% endblock %}-My App</title>{% endblock %}</head><body>{% block body %}{% endblock %}</body></html>
继承自base.html的index.html:

{% extends "base.html" %}{% block title %}Index{% endblock %}{% block head %}    {{ supper() }}    <style>    </style>{% endblock %}{% block body %}<h1>Hello World</h1>{% endblock %}

子页面扩展的部分会替换基模板相同的block区域包含的部分,如果有内容需要继承基模板同时扩展新内容,使用supper()来获取基模板内容。

原创粉丝点击