[Flask] Flask的请求与响应

2023/11/30 10:11:03

1.Flask的请求

如果以GET请求访问URL,例如URL是127.0.0.1:5000/?name=andy&age=18,那么如何获取这个URL的参数?如果以POST请求提交一个表单,那么又如何获取表单中各个字段值呢?

Flask提供的Request请求对象就可以实现上述功能

Request请求对象的常用属性和方法

属性或方法说明
args存储url请求中的查询参数,返回类似于字典的数据
method存储请求中使用的HTTP方法,例如GET或POST
form存储请求提交的所有表单数据,返回类似于字典的数据
files存储请求上传的所有文件,返回类似于字典的数据
url存储客户端请求的完整URL
host存储请求的域名
headers存储HTTP请求的请求头信息,返回类似于字典的数据
cookies存储请求的所有cookie,返回类似于字典的数据

1.1 GET请求

使用request.args.get()方法就可以获取GET请求参数

实例1:获取GET请求参数

获取127.0.0.1:5000/?name=andy&age=18这个URL中的name和age两个参数,在资源文件目录下创建一个run.py文件

目录结构

代码如下所示

# run.py
from flask import Flask, request
app = Flask(__name__)


@app.route('/')
def index():
    name = request.args.get('name')
    age = request.args.get('age')
    message = f'姓名:{name}\n年龄:{age}'
    return message


if __name__ == '__main__':
    app.run(debug=True)

运行run.py文件,在浏览器中访问网址: 127.0.0.1:5000/?name=andy&age=18,运行结果如下图所示

1.2 POST请求

使用request.args.post()方法可以接收POST请求参数,如果接收表单数据,可以使用request.from对象

实例2: 获取表单提交信息

首先创建一个run.py文件,在该文件中定义一个login路由,代码如下所示

# run.py
from flask import Flask, request, render_template
app = Flask(__name__)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        message = f'用户名是:{username}</br>密码是:{password}'
        return message

    return render_template('login.html')


if __name__ == '__main__':
    app.run(debug=True)

然后在run.py同级目录下创建"templates"文件夹,在"templates"路径下创建login.html模板文件

目录结构

代码如下所示

<!--login.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
    <form action="" method="post">
        <div>
            <label for="username">用户名</label>
            <input type="text" id="username" name="username" value="">
        </div>
        <div>
            <label for="password">密&nbsp;&nbsp;&nbsp;&nbsp;码</label>
            <input type="password" id="password" name="password" value="">
        </div>
        <button type="submit">提交</button>
    </form>
</body>
</html>

运行run.py文件,在浏览器中访问网址127.0.0.1:5000/login,显示表单页面,用户名输入andy,密码输入123456

单击【提交】按钮,运行结果如下所示

文件上传 

在使用Web表单时,经常会使用到上传文件功能,request.files对象可以获取与表单相关的数据

案例3: 实现上传用户图片功能

目录结构

首先定义一个路由函数upload()用于上传图片,然后提交上传的图片,在另一个路由函数uploaded_file()中显示图片内容,具体操作步骤如下

① 在"templates"目录下创建文件上传模板upload.html,代码如下所示

<!--upload.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传图片</title>
</head>
<body>
    <!--form表单中设置enctype="multipart/form-data",用于上传文件-->
    <form action="" method="post" enctype="multipart/form-data">
        <div>
            <label for="avatar">上传图片</label>
            <input type="file" id="avatar" name="avatar" value="">
        </div>
        <button type="submit">提交</button>
    </form>
</body>
</html>

② 创建一个run.py文件,在该文件中编写upload()路由函数,当接受GET请求时,显示模板文件内容;当接受POST请求时,上传图片

代码如下所示

@app.route('/upload',methods=['GET','POST'])
def upload():
    """
    头像上传表单页面
    :return:
    """
    if request.method == 'POST':
        # 接受头像字段
        avatar = request.files['avatar']
        # 判断文件是否上传,已经上传文件类型是否正确
        if avatar and allowed_file(avatar.filename):
            # 生成一个随机文件名
            filename = random_file(avatar.filename)
            # 保存文件
            avatar.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file',filename=filename))

    return render_template('upload.html')

上述代码中,使用request.files['avatar']接收表单中name='avatar'的字段值,然后检测用户是否上传了图片,并且使用allowed_file()函数检测上传的文件类型是否满足设定的要求

allowed_file()函数代码如下所示

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])

def allowed_file(filename):
    """
    判断上传文件类型是否允许
    :param filename: 文件名
    :return: 布尔值True或False
    """
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

接下来使用random_file()函数为上传的文件重新创建一个随机的不重复的文件名,通过使用uuid.uuid4()生产处一个随机的几乎不可能重复的文件名,然后拼接一个完整的路径,代码如下所示

import uuid

def random_file(filename):
    """
    生成随机文件
    :param filename: 文件名
    :return: 随机文件名
    """
    # 获取文件后缀
    ext = os.path.splitext(filename)[1]
    # 使用uuid生成随机字符
    new_filename = uuid.uuid4().hex+ext
    return new_filename

准备工作完成后,最后调用avartar.save()方法将图片存储到相应的路径下

③ 在run.py文件中创建uploaded_file()路由函数,显示图片内容,代码如下所示

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    """
    显示上传头像
    :param filename: 文件名
    :return: 真实文件路径
    """
    return send_from_directory(app.config['UPLOAD_FOLDER'],filename)

send_from_directory()函数用于显示静态资源文件

上述run.py文件完整代码如下所示

# run.py
import os
import uuid
from flask import send_from_directory
from flask import Flask, request, render_template, redirect, url_for

app = Flask(__name__)
UPLOAD_FOLDER = os.path.join(app.root_path, 'uploads')
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER


def allowed_file(filename):
    """
    判断上传文件类型是否允许
    :param filename: 文件名
    :return: 布尔值True或False
    """
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


def random_file(filename):
    """
    生成随机文件
    :param filename: 文件名
    :return: 随机文件名
    """
    # 获取文件后缀
    ext = os.path.splitext(filename)[1]
    # 使用uuid生成随机字符
    new_filename = uuid.uuid4().hex+ext
    return new_filename


@app.route('/upload', methods=['GET', 'POST'])
def upload():
    """
    头像上传表单页面
    """
    if request.method == 'POST':
        # 接受头像字段
        avatar = request.files['avatar']
        # 判断文件是否上传,已经上传文件类型是否正确
        if avatar and allowed_file(avatar.filename):
            # 生成一个随机文件名
            filename = random_file(avatar.filename)
            # 保存文件
            avatar.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file', filename=filename))

    return render_template('upload.html')


@app.route('/uploads/<filename>')
def uploaded_file(filename):
    """
    显示上传头像
    :param filename: 文件名
    :return: 真实文件路径
    """
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)


if __name__ == '__main__':
    app.run(debug=True)

执行run.py程序文件,在浏览器中输入网址: http://127.0.0.1:5000/upload,显示上传图片页面,单击【浏览】按钮,弹出一个选择框,选择一个图片后,单击【打开】按钮,会将图片文件名显示在【浏览】按钮右侧

上传图片页面
 选择需要上传的图片
图片文件名成功显示

单击【提交】按钮上传文件,如果上传成功,页面将跳转至uploads,在该页面显示图片内容,运行结果如下图所示

 显示上传的图片内容

此时,图片被上传到设置的路径下,并创建了一个随机的文件名

上传图片所在路径和随机文件名

1.3 钩子函数的应用

有时需要对请求进行预处理(preprocessing)和后处理(postprocessing),这时可以使用Flask提供的一些请求钩子(Hook),它们可以用来注册在请求处理的不同阶段执行的处理函数

Flask的请求钩子指的是在执行视图函数前后执行的一些函数,我们可以在这些函数里面做一些操作 

Flask利用装饰器给我们提供了四种钩子函数

before_first_request: 在处理第一个请求前执行,比如链接数据库操作

before_request: 在每次请求前执行,比如权限校验

after_request: 每次请求之后调用,前提是没有未处理的异常抛出

teardown_request: 每次请求之后调用,即使有未处理的异常抛出

实例4: 使用请求钩子,在执行视图函数前后执行相应的函数

目录结构

创建一个run.py文件,在该文件中定义一个index视图函数,然后定义before_first_request、before_request、after_request和teardown_request四个钩子,代码如下所示

# run.py
from flask import Flask
app = Flask(__name__)


@app.route('/')
def index():
    print('视图函数执行')
    return 'index page'


# 在第一次请求之前运行
@app.before_first_request
def before_first_request():
    print('before_first_request')


# 在每一次请求前都会执行
@app.before_request
def before_request():
    print('before_request')


# 在请求之后运行
@app.after_request
def after_request(response):
    # response就是前面的请求处理完毕之后,返回的响应数据,前提是视图函数没有出现异常
    print('after_request')
    return response


# 无论视图函数是否出现异常,每一次请求之后都会调用,会接收一个参数,参数是服务器出现的错误信息
@app.teardown_request
def teardown_request(error):
    print('teardown_request: error %s' % error)


if __name__ == '__main__':
    app.run(debug=True)

执行run.py程序文件,第1次在浏览器中访问网址127.0.0.1:5000时,控制台输出结果如下

before_first_request 
before_request 
视图函数执行
after_request
teardown_request: error None

2次在浏览器中访问网址127.0.0.1:5000时,控制台输出结果如下

before_request 
视图函数执行 
after_request
teardown_request: error None 

请求钩子的一些常见应用场景

1.运行程序前需要进行一些程序的初始化操作,比如创建数据库表,添加管理员用户等,这些工作可以放到使用before_first_request装饰器注册的函数中 

2.网站上要记录用户最后在线的时间,可以通过用户最后发送的请求时间来实现。为了避免在每个视图函数都添加更新在线时间的代码,可以仅在使用before_request钩子注册的函数中调用这段代码

3.在视图函数中进行数据库操作时,比如更新、插入等操作,之后需要将更改提交到数据库中,提交更改的代码就可以放到after_request钩子注册的函数中

2.Flask的响应

Response响应对象常用的属性和方法

属性或方法说明
headers响应首部
status状态
status_code状态码,文本类型
mimetypeMIME类型
set_cookie设置Cookie
get_json解析为JSON数据
is_json判断是否为JSON数据

2.1 接收响应

响应在Flask中使用Response响应对象表示,响应报文中的大部分内容由服务器处理,大多数情况下,我们只负责返回主体内容

当在浏览器中输入一个网址时,Flask会先判断是否可以找到与请求URL相匹配的路由,如果没有,则返回404响应。如果找到,则调用相应的视图函数

视图函数的返回值构成了响应报文的主体内容,当请求成功时,返回状态码默认为200

最常见的响应可以只包含主体内容,示例代码如下所示

@app.route('/index')
def index():
    return render_template('index.html')

响应还可以返回带状态码的形式,示例代码如下所示

@app.errorhandler(404)
def page_note_found(e):
    return render_template('404.html')

在大多数情况下,除了响应主体,其他部分我们通常只需要使用默认值即可

2.2 响应的格式

在HTTP响应中,数据可以通过多种格式传输

不同的响应数据格式需要设置不同的MIME类型,MIME类型在首部的Content-Type字段中定义

我们以默认的HTML类型为例,Content-Type内容如下

Content-Type: text/html; charset=utf-8

但是在特定的情况下,也会使用其他格式。我们可以通过Flask提供的make_response()方法生成响应对象,传入响应的主体作为参数,然后使用响应对象的mimetype属性设置MIME类型

常用的数据格式有纯文本、HTML、XML和JSON,它们对应的MIME类型如下

纯文本:text/plain

HTML: text/html

XML:application/xml

JSON:application/json

实例5

目录结构
# run.py
from flask import Flask, make_response
app = Flask(__name__)


@app.route('/index')
def index():
    response = make_response('Hello World')
    response.mimetype = 'text/plain'
    return response


if __name__ == '__main__':
    app.run(debug=True)

运行run.py文件,在浏览器中访问网址127.0.0.1:5000/index,结果如下图所示

实例6

目录结构
# run.py
from flask import Flask, make_response, json
app = Flask(__name__)


@app.route('/index')
def index():
    data = {'name':'Andy', 'age':18}
    # 调用dumps()方法将字典、列表或元组序列化(serialize)为JSON字符串
    response = make_response(json.dumps(data))
    response.mimetype = 'application/json'
    return response


if __name__ == '__main__':
    app.run(debug=True)

运行run.py文件,在浏览器中访问网址127.0.0.1:5000/index,结果如下图所示 

我们也可以使用Flask提供的jsonify()函数,只要传入数据或参数,它会对传入的参数进行序列化,转换成JSON字符串作为响应的主体,然后生成一个响应对象,并且设置正确的MIME类型

# run.py
from flask import Flask, jsonify
app = Flask(__name__)


@app.route('/index')
def index():
    # return jsonify({'name':'Andy', 'age':18})
    return jsonify(name='Andy', age=18)


if __name__ == '__main__':
    app.run(debug=True)

运行run.py文件,在浏览器中访问网址127.0.0.1:5000/index,结果如下图所示 


http://www.jnnr.cn/a/569168.html

相关文章

ℰ悟透Qt—Http网络编程

目录 概述实践理论QNetworkAccessManager进行Http编程的基本步骤代码实战(重点片段) 概述 网络访问 API 建立在一个 QNetworkAccessManager 对象之上&#xff0c;该对象保存了发送请求所需的公共配置和设置。它包含代理和缓存配置&#xff0c;以及与此类问题相关的信号和可用于…

【C语言初阶(5)】循环练习题

文章目录 1. 计算 n 的阶乘2. 计算 1!2!3!……10!3. 使用二分查找法查找某数二分查找算法介绍代码实现 4. 演示字符移动5. 模拟用户登录场景 1. 计算 n 的阶乘 阶乘 某个数从 1 开始一直乘到这个数本身为止&#xff1b; 例如&#xff1a;3 的阶乘就是 1 * 2 * 3 6&#xff1b…

WebRTC的认知入门

一、学习目的 当前的音视频聊天功能很普通&#xff0c;社会对这方面的需求也很高&#xff0c;疫情期间的在线问诊模式解决类大量急需就医问诊患者的燃眉之急&#xff0c;我们需要了解WebRTC实现实时音视频聊天功能是如何操作的。 二、概念 什么是WebRTC?WebRTC是 Google 在…

形态学操作之膨胀

note // 膨胀原理&#xff1a;操作过程中&#xff0c;若膨胀因子某点是1&#xff0c;且原图该点为1&#xff0c;则锚点位置为1 code // 膨胀 // 膨胀原理&#xff1a;操作过程中&#xff0c;若膨胀因子某点是1&#xff0c;且原图该点为1&#xff0c;则锚点位置为1 typedef e…

SAP-MM未清PO调取

SAP未清PO调取 SAP查询open PO(未清采购清单)可以通过ME2M(PO per material),ME2L(PO per vendor),ME2N(PO per document number)进行查询。 未清订单一般指未完成收货或者已收货未完成发票校验的订单,在输入以上任一事务代码之后,在选择参数Selection Parameters…

云计算的发展趋势及其对企业的影响

第一章&#xff1a;引言 近年来&#xff0c;云计算在IT行业迅猛发展&#xff0c;成为企业提升业务效率和创新能力的重要工具。通过云计算&#xff0c;企业能够将数据和应用程序存储在云端的服务器上&#xff0c;实现灵活的资源调配和高效的数据管理。本文将探讨云计算的发展趋…

基于STM32的直流电机调速系统

目录 基于STM32的直流电机调速系统一、原理图二、部分代码三、视频演示 基于STM32的直流电机调速系统 功能&#xff1a; 1.通过LCD屏幕显示实时两个电机的占空比 2.通过按键调整电机1和2的加减速 3.通过L298N驱动两个直流电机完成调速 一、原理图 二、部分代码 #include &qu…

【Emerson deltaV DCS和组态软件内存越界漏洞】

已经从原单位离职&#xff0c;原工作时候的漏洞没有提交给cnvd&#xff0c;现在闲来无事&#xff0c;提交了一个多月了,迟迟没有回应&#xff08;估计是设备太贵了或者接触不到&#xff0c;cnvd没法验证该漏洞&#xff09;&#xff0c;简直就是杳无音信&#xff0c;不等了&…

Grafana任意文件读取漏洞(CVE-2021-43798)

Grafana任意文件读取漏洞&#xff08;CVE-2021-43798&#xff09; 一、漏洞描述 Grafana是一个跨平台、开源的数据可视化网络应用程序平台。用户配置连接的数据源之后&#xff0c;Grafana可以在网络浏览器里显示数据图表和警告。 二、漏洞影响范围 影响版本&#xff1a; Gr…

Jvm jmx_exporter Prometheus dubbo Grafana 重点看端口要对应上 单独进程和程序进程内jmx_exporter

目录 JMX Exporter 的两种用法 启动独立进程 jmx_prometheus_httpserver-0.18.0.jar 方式 下载 jmx_exporter 找地方随便一放 创建配置文件 config_jmx_exporter.yaml 增加 启动 jvm 配置 一定要是jvm参数 可别意外写成程序参数 启动jmx_exporter Prometheus yml 配置 …

ResizeKit.NET 自动更改所有控件和字体大小 -Crack Version

ResizeKit2.NET ---Added support for Microsoft .NET 7.0. 使您的应用程序大小和分辨率独立。 ResizeKit.NET 自动更改所有控件和字体的大小&#xff0c;以便它们可以显示在任何大小的表单上。提供完全控制来自定义调整大小过程。即使用户在运行应用程序时切换表单的大小&…

《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Scrapy框架之下载中间件(详解)

目录 Scrapy中下载中间件 概念 方法 process_request(self, request, spider) 参数: process_response(self, request, response, spider) 参数 基本步骤 示例代码 注意 Scrapy 中 Downloader 设置UA 开发UserAgent下载中间件 代码 三方模块 配置模块到Settin…

小研究 - Java 指针分析综述(二)

近年来静态程序分析已成为保障软件可靠性、安全性和高效性的关键技术之一. 指针分析作为基 础程序分析技术为静态程序分析提供关于程序的一系列基础信息&#xff0c;例如程序任意变量的指向关系、变量 间的别名关系、程序调用图、堆对象的可达性等. 介绍了 Java 指针分析的重要…

Rust in Action笔记 第九章 时间管理

本章主要讲如何实现一个网络时间协议NTP&#xff08;Network Time Protocol&#xff09;客户端&#xff0c;谷歌的世界时间同步误差大概在7毫秒&#xff0c;开源网站CockroachDB的延迟在数十毫秒&#xff0c;使用了NTP协议&#xff0c;在处理与时间敏感的数据时&#xff0c;chr…

微前端框架MicroApp入门学习笔记(一)

1、简介 微前端是一种架构风格&#xff0c;旨在通过将前端应用程序拆分为更小、更可管理的部分&#xff0c;使多个团队能够独立开发、部署和维护这些部分&#xff0c;从而实现前端的可扩展性和可维护性。   MicroApp框架是京东出品的一种用于构建微前端架构的开源框架&#x…

01-创建项目-工具使用备忘录

创建项目 Keil5 &#xff08;编写程序工具&#xff09;生成输出hex文件 STC-ISP &#xff08;下载程序辅助工具&#xff09;辅助功能生成代码下载程序到单片机中运行 Keil5 &#xff08;编写程序工具&#xff09; 创建项目 创建好目录文件夹 选择对应芯片型号 不用自动生成启…

postgresql_internals-14 学习笔记(七)—— parallel 并行

不完全来自这本书&#xff0c;把查到的和之前的文章重新汇总整理了一把。 一、 核心参数 几个容易弄混的进程和参数&#xff0c;关系图如下 1. max_worker_processes 整个实例可以同时运行的Background workers Processes最大数量默认值为8&#xff0c;设置为0表示禁用并行&…

使用Nexus搭建Maven私有库实战

本篇快速演示如何搭建和使用Nexus本地库&#xff0c; 关于Nexus 的基本使用参考&#xff1a; Nexus搭建Maven私有库介绍 实战场景 本篇的实际场景是&#xff1a; 本地开发机器可以连接外部网络测试或正式部署环境只能连接内网项目使用了内部开发的组件库 在搭建搭建Maven私…

基于Docker-compose实现的Postgresql-11的主从复制

参考文章&#xff1a; http://t.csdn.cn/EnOVn http://t.csdn.cn/XTJqZ 记录一次主从复制的配置经历 服务器主从角色分配 ipdb 版本角色192.168.33.23411主192.168.33.22511从 docker-compose.yml文件 version: "3.3" services:postgres:image: postgresql-gis:11…
最新文章