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是,当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("传正则")


 

 

posted @ 2021-09-07 20:57  和风的夏天  阅读(70)  评论(0)    收藏  举报