Flask DAY 2
一、请求(request)与响应(response)原理
当我们在浏览器中的地址栏中输入这个URL,然后按下Enter,稍等片刻,浏览器会显示一个问候页面。这背后到底发生了什么?你一定可以猜想到,这背后也有一个类似我们编写的程序运行着。它负责接收用户的请求,并把对应的内容返回给客户端,显示在用户的浏览器上。事实上,每一个Web应用都包含这种处理模式,即“请求-响应循环(Request-Response Cycle)”:客户端发出请求,服务器处理请求并返回响应,如下图所示:

附注 客户端(Client Side)是指用来提供给用户的与服务器通信的各种软件。在本书中,客户端通常指Web浏览器(后面简称浏览器),比如Chrome、Firefox、IE等;服务器端(Server Side)则指为用户提供服务的服务器,也是我们的程序运行的地方。
这是每一个Web程序的基本工作模式,如果再进一步,这个模式又包含着更多的工作单元,
下图展示了一个Flask程序工作的实际流程:

从上图可以看出,HTTP在整个流程中起到了至关重要的作用,它是客户端和服务器端之间沟通的桥梁。
当用户访问一个URL,浏览器便生成对应的HTTP请求,经由互联网发送到对应的Web服务器。Web服务器接收请求,通过WSGI将HTTP格式的请求数据转换成我们的Flask程序能够使用的Python数据。在程序中,Flask根据请求的URL执行对应的视图函数,获取返回值生成响应。响应依次经过WSGI转换生成HTTP响应,再经由Web服务器传递,最终被发出请求的客户端接收。浏览器渲染响应中包含的HTML和CSS代码,并执行JavaScript代码,最终把解析后的页面呈现在用户浏览器的窗口中。
Request对象(from flask import Flask,request)
这个请求对象封装了从客户端发来的请求报文,我们能从它获取请求报文中的所有数据。
我们先从URL说起。假设请求的URL是http://helloflask.com/hello?name=Grey,当Flask接收到请求后,请求对象会提供多个属性来获取URL的各个部分,常用的属性如下表所示:

除了URL,请求报文中的其他信息都可以通过request对象提供的属性和方法获取,其中常用的部分如下表所示:

在我们的示例程序中实现了同样的功能。当你访问http://localhost:5000/hello?name=Grey,页面加载后会显示“Hello, Grey!”。这说明处理这个URL的视图函数从查询字符串中获取了查询参数name的值,如下所示:
from flask import Flask, request
app = Flask(__name__)
@app.route('/hello')
def hello():
print(request.method) #打印请求方式
print(request.url) #打印请求地址
name = request.args.get('name', 'Flask') # 获取查询参数name的值
return '<h1>Hello, %s!</h1>' % name # 插入到返回值中
需要注意的是,和普通的字典类型不同,当我们从request对象中类型为MutliDict或ImmutableMultiDict的属性(比如files、form、args)中直接使用键作为索引获取数据时(比如request.args['name']),如果没有对应的键,那么会返回HTTP 400错误响应(Bad Request,表示请求无效),而不是抛出KeyError异常,如下图所示。为了避免这个错误,我们应该使用get()方法获取数据,如果没有对应的值则返回None;get()方法的第二个参数可以设置默认值,比如requset.args.get('name', 'Human')。

二、从路径中获取参数
Flask不同于Django直接在定义路由时编写正则表达式的方式,而是采用转换器;
URL中路径参数的获取:
语法:<>
作用:提取URL路径参数
效果:将该位置数据以字符串格式匹配,值同样为字符串类型,转换器中的值为参数名传入视图
@app.route('/index/<id>',methods=["GET","POST"])
#def first_flask(id): #视图函数
print(id)
return"hello user %S!" % id
三、设定视图函数能够处理的请求方式
HTTP有很多URL方法的。默认路由只回应GET请求,但是我们可以在装饰器app.route中传递methods参数改变请求方式,
当我们需要视图函数能够处理多种请求时,需要在对应的视图函数的装饰器上进行修改增加一行代码:methods=["get","post"]如果还有其他的请求方式需要添加,在括号中继续加入对应的请求方式即可。
@app.route('/index/<id>',methods=["GET","POST"])
四、返回指定的前端网页(利用render_template()渲染html)
render_template()有什么用?
在Python代码中 直接生成 HTML 缺点很多,比如笨拙,效率低,可读性差。因此, Flask 提供了 Jinja2 模板引擎来帮助开发者高效灵活生成HTML。
使用该方法可以渲染模板,你只要提供模板名称和需要作为参数传递给模板的变量就行了.
html模板文件的位置
模板即自己写好的模板html文件,需要放在templates文件夹内。目录结构如下:
/application.py
/templates #创建一个新的空文件夹且命名templates.
/hello.html
实例
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('files_list.html')
if __name__="__main__" :
app.run(debug=True)
五、返回JSON数据(import json,from flaskimport Flask,jsonify)
在前后端分离的时代,后端一般返回前端的数据就是json格式的响应数据。
而json格式的响应数据其实实际上就是一个字符串。
要知道Flask如何返回json响应数据,首先就需要知道如何将字典dict转化为json字符串。
In [1]: import json
In [2]: data = {"user_name":"libai", "user_pwd": "123456"}
In [3]: type(data)
Out[3]: dict
# 将dict转为json字符串
In [4]: res = json.dumps(data)
In [5]: res
Out[5]: '{"user_name": "libai", "user_pwd": "123456"}'
In [6]: type(res)
Out[6]: str
# 将json字符串转为dict
In [7]: rec = json.loads(res)
In [9]: rec
Out[9]: {'user_name': 'libai', 'user_pwd': '123456'}
In [10]: type(rec)
Out[10]: dict
视图函数使用json库返回json响应数据
from flask import Flask, request
import json
# 实例化app
app = Flask(import_name=__name__)
@app.route('/login', methods=["GET","POST"])
def login():
data = {
"user_name": "libai",
"user_age": 18,
}
res_json = json.dumps(data)
return res_json
if __name__ == '__main__':
app.run(debug=True)
在浏览器请求如下:

如果单纯直接返回响应消息,Content-Type:text/html 是不正确的,应该改为application/json 才对。
修改响应消息的headers如下:
from flask import Flask, request, abort, make_response
import json
# 实例化app
app = Flask(import_name=__name__)
@app.route('/login', methods=["GET","POST"])
def login():
data = {
"user_name": "libai",
"user_age": 18,
}
res_json = json.dumps(data)
# return 响应体, 状态码, 响应头
return res_json, 200, {"Content-Type":"application/json"}
if __name__ == '__main__':
app.run(debug=True)
在浏览器的请求响应如下:

可以看到正常返回json数据了。
但是可以感觉到这样其实挺麻烦的。在Flask框架中有一个jsonify的方法可以将这个过程简化。
使用jsonify来返回json响应数据
from flask import Flask, jsonify
# 实例化app
app = Flask(import_name=__name__)
@app.route('/login', methods=["GET","POST"])
def login():
data = {
"user_name": "libai",
"user_age": 18,
}
return jsonify(data)
if __name__ == '__main__':
app.run(debug=True)
浏览器请求如下:

可以看到,使用jsonify返回json响应数据是最简单的一种方式。
- 另外
jsonify不单单可以将dict转为json响应数据,还可以直接往里面写参数值
jsonify(token=123456, gender=0)
示例如下:
from flask import Flask, jsonify
# 实例化app
app = Flask(import_name=__name__)
@app.route('/login', methods=["GET","POST"])
def login():
return jsonify(token=123456, gender=0)
if __name__ == '__main__':
app.run(debug=True)
浏览器请求如下:

六、重定向,重定向补充与自定义状态码
现象:访问地址a,跳转到地址b,在flask中,使用redirect()来进行重定向
永久性重定向:301,多用于旧网址被废弃了,需要跳转到新网址访问
例如请求www.jingdong.com,会自动跳转到www.jd.com

暂时性重定向:302,比如没有访问当前访问地址的权限,需跳转到有权限的地址
比如在淘宝买东西,未登录的情况下,去下单,会重定向到登录

反转URL url_for('函数名')
通过url_for函数可以实现视图函数到URL路径的转换,服务器可以利用这个路径实现视图函数的重定向。
一、基本使用方法(不带参数)
例如:
@app.route('/post/list/') def my_list(page): return 'my list'
print(url_for('my_list')) #构建出来的url:/my_list/
二、带参数的url_for()
url_for('函数名',参数1=xxx,参数2=xxx)
`url_for`第一个参数,应该是视图函数的名字的字符串。后面的参数就是传递给`url`。
如果传递的参数之前在`url`中已经定义了,那么这个参数就会被当成`path`的形式给
`url`。如果这个参数之前没有在`url`中定义,那么将变成查询字符串的形式放到`url`中。
例如:
@app.route('/post/list/<page>/')
def my_list(page):
return 'my list'
print(url_for('my_list',page=1,count=2))
# 构建出来的url:/my_list/1/?count=2
三、在flask中的使用
from flask import Flask, request, redirect, url_for
app = Flask( __name__ )
@app.route( '/login/' )
def login():
return '这是登录页面'
@app.route( '/profile/' )
def profile():
if request.args.get( 'name' ):
return '个人中心页面'
else:
# redirect 重定向
return redirect( url_for( 'login' ) )
搜索引擎输入:127.0.0.1:5000/profile/?name=xxx
浏览器展示:个人中心页面
自定义状态码(在视图函数里面,return内容后面加入自己定义的状态码即可)
from flask import Flask app = Flask(__name__) @app.route('/') def demo():
return '状态码666', 666
if __name__ == '__main__':
app.run()
七、自定义过滤器
#非重点
#1 写类,继承BaseConverter
#2 注册:app.url_map.converters['regex'] = RegexConverter # 这个类自己定义
# 3 使用:@app.route('/index/<regex("\d+"):nid>') 正则表达式会当作第二个参数传递到类中
from flask import Flask, url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class RegexConverter(BaseConverter): # 类名无所谓可以自己定义
"""
自定义URL匹配正则表达式
"""
def __init__(self, map, *args):
super(RegexConverter, self).__init__(map)
self.regex = args[0] # 添加属性
# 添加到flask中
app.url_map.converters['regex'] = RegexConverter
# 正则匹配处理结果,要交给to_python,to_python函数可以对匹配处理结果做处理
@app.route('/index/<regex("[]{}")>')
def index(nid):
print("index",nid,type(nid))
return 'Index'
if __name__ == '__main__':
app.run()
1 导入from werkzeug.routing import BaseConverter
将上面的类注册到app.url_map.converters['regex'] = RegexConverter中
然后就可以在路由转化器中使用regex("传正则")

浙公网安备 33010602011771号