Flask入门教程(八):视图函数详解——请求处理与响应的核心

1. 定义视图函数

视图函数是一个普通的Python函数,它接收请求并返回响应。视图函数通常与路由配合使用,通过装饰器将URL映射到视图函数。

复制代码
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello, World!'
  • @app.route('/'):将根URL / 映射到home视图函数

  • def home():视图函数,返回字符串作为响应

2. 接收请求数据

视图函数可以接收不同类型的请求数据,包括URL参数、表单数据、查询参数等。

获取URL参数(动态路由)

复制代码
@app.route('/greet/<name>')
def greet(name):
    return f'Hello, {name}!'

<name>是一个URL参数,Flask会自动将其传递给视图函数greet的同名参数。

获取表单数据(POST请求)

复制代码
from flask import request

@app.route('/submit', methods=['POST'])
def submit():
    username = request.form.get('username')
    return f'Form submitted by {username}!'

request.form.get('username'):获取POST请求中表单数据的username字段。

获取查询参数(GET请求)

复制代码
@app.route('/search')
def search():
    query = request.args.get('query')
    return f'Search results for: {query}'

request.args.get('query'):获取GET请求URL中的查询参数query(如/search?query=flask)。

3. 返回响应

视图函数可以返回多种类型的响应,包括字符串、HTML模板、JSON数据或自定义响应对象。

返回字符串

复制代码
@app.route('/message')
def message():
    return 'This is a simple message.'

返回HTML模板

复制代码
from flask import render_template

@app.route('/hello/<name>')
def hello(name):
    return render_template('hello.html', name=name)

render_template('hello.html', name=name):渲染HTML模板hello.html,并将name变量传递给模板。

返回JSON数据

复制代码
from flask import jsonify

@app.route('/api/data')
def api_data():
    data = {'key': 'value', 'list': [1, 2, 3]}
    return jsonify(data)

jsonify(data):将Python字典转换为JSON响应,并自动设置Content-Typeapplication/json

在Flask 2.2+中,直接返回字典或列表也会自动调用jsonify(),因此可以简写为return data

返回自定义响应对象

复制代码
from flask import Response

@app.route('/custom')
def custom_response():
    response = Response('Custom response with headers', status=200)
    response.headers['X-Custom-Header'] = 'Value'
    return response

Response():创建自定义响应对象,可以设置状态码和响应头。

4. 处理请求和响应

视图函数可以访问请求对象,并根据请求数据生成响应。

使用request对象

复制代码
from flask import request

@app.route('/info')
def info():
    user_agent = request.headers.get('User-Agent')
    method = request.method
    path = request.path
    return f'Method: {method}, Path: {path}, User-Agent: {user_agent}'

使用make_response创建响应

复制代码
from flask import make_response

@app.route('/header')
def custom_header():
    response = make_response('Response with custom header')
    response.headers['X-Custom-Header'] = 'Value'
    response.set_cookie('theme', 'dark')
    return response

make_response():创建响应对象并支持设置自定义头信息、Cookie等。

5. 处理错误

可以在视图函数中处理异常或错误,也可以通过Flask提供的错误处理机制来处理应用中的错误。

在视图函数中处理错误(try-except)

复制代码
@app.route('/divide/<int:x>/<int:y>')
def divide(x, y):
    try:
        result = x / y
        return f'Result: {result}'
    except ZeroDivisionError:
        return 'Error: Division by zero', 400

使用try-except语句处理除零错误,并返回自定义错误消息和状态码。

使用abort终止请求

复制代码
from flask import abort

@app.route('/post/<int:post_id>')
def view_post(post_id):
    # 假设文章ID有效范围是1-100
    if post_id < 1 or post_id > 100:
        abort(404, description='文章不存在')
    return f'<h1>文章 #{post_id}</h1>'

全局错误处理

复制代码
@app.errorhandler(404)
def not_found(error):
    return 'Page not found', 404

@app.errorhandler(500)
def internal_error(error):
    return 'Internal server error', 500

@app.errorhandler(ZeroDivisionError)
def handle_zero_division(error):
    return 'Cannot divide by zero', 400

@app.errorhandler():定义处理特定错误或异常的函数,可以捕获HTTP错误码或Python异常类。

6. 视图函数的装饰器(请求钩子)

除了@app.route,Flask还提供了多种装饰器,用于在请求处理的不同阶段执行自定义逻辑。

装饰器 触发时机 典型用途
@app.before_request 每个请求处理之前 权限验证、数据库连接、请求日志
@app.before_first_request 第一个请求处理之前(仅一次) 初始化全局资源
@app.after_request 每个请求处理之后,返回响应之前 添加响应头、压缩响应内容
@app.teardown_request 请求结束后(无论是否有异常) 释放资源、关闭数据库连接

示例:请求钩子使用

复制代码
@app.before_request
def before_request():
    print('Before request')
    # 可以在这里做用户认证检查
    # 如果未认证,可以返回响应提前终止请求

@app.after_request
def after_request(response):
    print('After request')
    # 添加自定义响应头
    response.headers['X-Request-Time'] = '123ms'
    return response

@app.teardown_request
def teardown_request(exception):
    print('Teardown request')
    # 清理资源,如关闭数据库连接
    # 如果有异常,exception参数包含异常对象

多个钩子的执行顺序

复制代码
请求到达
    │
    ▼
@app.before_request(按注册顺序执行)
    │
    ▼
路由匹配 → 视图函数执行
    │
    ▼
@app.after_request(按注册逆序执行)
    │
    ▼
响应返回客户端
    │
    ▼
@app.teardown_request(异常时也执行)

7. 视图函数返回的状态码

视图函数不仅可以返回内容,还可以指定HTTP状态码来表示请求的处理结果。

复制代码
# 返回状态码200(成功)
@app.route('/status')
def status():
    return 'Everything is OK', 200

# 返回状态码201(创建成功)
@app.route('/create', methods=['POST'])
def create():
    return {'id': 1, 'message': 'Created'}, 201

# 返回状态码400(请求错误)
@app.route('/validate')
def validate():
    return 'Invalid input', 400

# 返回状态码401(未认证)
@app.route('/protected')
def protected():
    return 'Authentication required', 401

# 返回状态码403(无权限)
@app.route('/admin')
def admin():
    return 'Access forbidden', 403

# 返回状态码404(未找到)
@app.route('/old-page')
def old_page():
    return 'Page not found', 404

# 返回状态码500(服务器内部错误)
@app.route('/error')
def error():
    return Response('Internal server error', status=500)

8. 视图函数返回值类型汇总

返回类型 示例 Flask自动处理
str return "Hello" 作为HTML响应体,200 OK
dict return {"key": "value"} 转为JSON响应,200 OK
list return [1, 2, 3] 转为JSON响应,200 OK
tuple return "body", 404 自定义状态码
tuple return "body", {"X-Header": "v"} 自定义响应头
Response return Response("body", status=200) 完全控制的响应
render_template() return render_template("page.html") HTML模板渲染
jsonify() return jsonify(data) JSON响应
redirect() return redirect("/login") 302重定向
abort() abort(404) 错误响应

小结

本章详细讲解了Flask视图函数的完整知识体系。视图函数通过路由装饰器与URL绑定,通过request对象获取URL参数、表单数据、查询参数等请求信息;响应方面可以返回字符串、模板、JSON或自定义响应对象;错误处理可以通过try-exceptabort()@app.errorhandler()实现;请求钩子(@app.before_request@app.after_request等)允许在请求处理的不同阶段执行统一逻辑;视图函数还可以通过元组或Response对象灵活指定状态码。这些知识构成了Flask应用业务逻辑编写的完整基础。

相关推荐
河南凹凸环境艺术设计24 分钟前
民宿酒店设计实力公司
大数据·人工智能·python
小江的记录本30 分钟前
【AI Agent】《2026年9月 AI Agent全栈开发技术选型专项面试宝典》
java·spring boot·python·spring·ai·面试·ai编程
春涧草茶1 小时前
慢就是快-11-1数据容器 | 列表
python
维克兜率天1 小时前
【维克】技术指标是什么:从均线到MACD的数学原理
人工智能·笔记·python·算法·量化
卷无止境1 小时前
当FastAPI遇上机器学习,一个脚手架工具能省下多少工夫
后端·python·fastapi
卷无止境1 小时前
Kilo CLI 到底是什么
人工智能·后端·python
coderCN1 小时前
Nodejs 响应头和请求头
后端·node.js
SamDeepThinking1 小时前
里氏替换原则的盲区:为什么符合契约的List替换依然会失败?
后端·面试·程序员