【Python】Bottle:轻量Web框架

Bottle快速开始

Bottle 是一个非常轻量级的 Python Web 框架,适合用于构建简单的 Web 应用和 RESTful API。Bottle 的最大特点之一是它的单文件设计,意味着你只需下载一个文件 bottle.py 即可使用整个框架,而不需要安装其他依赖。在这篇教程中,我们将演示如何通过下载 bottle.py 文件并直接导入它,快速搭建你的第一个 Web 应用。

环境搭建:通过单个 bottle.py 文件

获取 Bottle 库
  1. 下载 bottle.py 文件

    Bottle 的源代码可以直接从GitHub 仓库下载,或者通过以下步骤手动获取:

    • 打开浏览器,访问 https://github.com/bottlepy/bottle。
    • 点击 “Code” 按钮,然后选择 “Download ZIP” 下载整个仓库。
    • 解压后,找到 bottle.py 文件。
  2. bottle.py 文件放置在项目目录

    将下载的 bottle.py 文件复制到你项目的根目录下。这就是你整个框架的全部内容,无需安装其他包或依赖。

创建一个简单的 bottle.py 文件

在项目的根目录下,创建一个新的 Python 文件,比如 app.py,用来编写 Web 应用代码。你不需要通过 import bottle 来加载整个框架,而是直接导入 bottle.py 文件。可以通过如下方式实现:

# 导入本地的 bottle.py 文件
from bottle import route, run

# 定义路由及处理函数
@route('/hello')
def hello():
    return "Hello, World!"

# 启动应用
run(host='localhost', port=8080)

在这里,我们直接使用了 bottle.py 文件提供的 routerun 函数。这个 bottle.py 文件会被自动识别,并且框架本身也能完美工作。

第一个 Bottle 应用

现在我们已经完成了环境搭建,接下来我们将通过编写简单的路由和请求处理函数,创建一个基本的 Bottle Web 应用。

创建一个最简单的 Web 应用

编辑 app.py 文件,并写入以下代码:

from bottle import route, run

# 创建一个简单的路由
@route('/hello')
def hello():
    return "Hello, World!"

# 启动应用
run(host='localhost', port=8080)
代码解析
  • from bottle import route, run:这行代码导入了 routerun 函数,它们分别用于定义路由和启动应用。
  • @route('/hello'):这是一个路由装饰器,告诉 Bottle 当访问 /hello 路径时,执行下面的 hello() 函数。
  • def hello()::这是定义的视图函数。当用户访问 /hello 时,返回一个简单的文本响应:“Hello, World!”。
  • run(host='localhost', port=8080):启动应用,监听本地 localhost 地址的 8080 端口。
运行应用
  1. 打开终端,进入到 app.py 所在的目录。

  2. 直接运行 app.py 文件:

    python app.py
    
  3. 打开浏览器,访问 http://localhost:8080/hello,你应该能够看到显示 “Hello, World!” 的页面。

路由和请求方法

在 Bottle 中,路由是 Web 应用的核心,决定了不同 URL 请求应该由哪个函数来处理。你可以通过 route() 函数为不同的 URL 配置不同的请求处理函数,支持多种 HTTP 请求方法。

路由参数

Bottle 允许你在路由中定义参数,这样 URL 路径中的一部分就可以作为参数传递给视图函数。

@route('/greet/<name>')
def greet(name):
    return f'Hello {name}!'

当你访问 http://localhost:8080/greet/John 时,URL 中的 John 会被捕获并传递给 greet() 函数中的 name 参数,返回 “Hello John!”。

请求方法

Bottle 支持不同的 HTTP 请求方法,如 GET、POST、PUT 和 DELETE。你可以在路由定义中明确指定请求方法。

GET 请求

GET 请求通常用于获取数据,它是 Web 应用中最常见的请求方法。

@route('/hello', method='GET')
def hello():
    return "This is a GET request!"

访问 http://localhost:8080/hello 时,将返回 “This is a GET request!”。

POST 请求

POST 请求通常用于提交数据,比如提交表单。

from bottle import request

@route('/submit', method='POST')
def submit():
    name = request.forms.get('name')
    return f'Hello {name}, your form has been submitted!'

你可以通过 HTML 表单将数据发送到 /submit 路由,当表单提交时,返回 “Hello {name}, your form has been submitted!”。

PUT 和 DELETE 请求

PUT 和 DELETE 请求通常用于更新或删除资源。你可以通过 method='PUT'method='DELETE' 显式指定这些方法。

@route('/update/<name>', method='PUT')
def update(name):
    return f'User {name} has been updated!'

@route('/delete/<name>', method='DELETE')
def delete(name):
    return f'User {name} has been deleted!'

访问 /update/John/delete/John 路径时,分别返回 “User John has been updated!” 和 “User John has been deleted!”。

请求数据:表单和 URL 参数

Bottle 提供了简单的 API 来处理请求中的数据:

  • URL 参数:通过动态路由捕获 URL 参数,或者使用 request.query 获取查询字符串中的参数。
  • 表单数据:通过 request.forms 获取 POST 请求中的表单数据。
@route('/greet')
def greet():
    name = request.query.name  # 获取查询字符串中的参数
    return f'Hello {name}!'

访问 http://localhost:8080/greet?name=John 将返回 “Hello John!”。

路由与请求处理

在构建 Web 应用时,路由与请求处理是核心概念之一。Bottle 作为一个轻量级的 Python Web 框架,其路由系统非常简洁且易于理解。它通过装饰器的方式定义路由,并为每个请求分配一个处理函数。在这篇教程中,我们将详细讲解 Bottle 中的路由参数、请求对象和响应对象的使用,帮助你深入理解 Bottle 框架的请求处理机制。

路由参数

路由参数是 Web 应用中的常见需求,它使得 URL 中的某些部分可以动态地映射到视图函数的参数。Bottle 提供了非常简单的方式来定义路由参数,使得你可以根据请求路径中的参数进行数据处理。

动态路由参数

Bottle 的路由支持动态参数,可以通过在 URL 路径中使用 <param> 占位符来捕获路径的一部分。

from bottle import route, run

@route('/greet/<name>')
def greet(name):
    return f"Hello, {name}!"

run(host='localhost', port=8080)

在这个例子中,<name> 就是一个动态路由参数,表示 URL 中的路径部分。访问 http://localhost:8080/greet/John 时,John 会作为参数传递给 greet() 函数,返回结果是 Hello, John!

参数类型:
Bottle 支持多种类型的路由参数,可以通过自定义参数类型来限制输入的内容:

  • 字符串参数:默认情况下,路由参数是字符串类型。
  • 整数参数:可以通过在路由参数中指定类型来限制只能匹配整数。
@route('/user/<id:int>')
def show_user(id):
    return f"User ID is {id}"

访问 http://localhost:8080/user/123 时,id 将是一个整数。如果你访问一个非整数的值(例如 /user/abc),Bottle 会自动返回 404 错误。

捕获多个参数

你可以在一个路由中捕获多个参数,只需在路由路径中使用多个占位符即可。

@route('/greet/<first_name>/<last_name>')
def greet_full_name(first_name, last_name):
    return f"Hello, {first_name} {last_name}!"

访问 http://localhost:8080/greet/John/Doe 时,first_namelast_name 将分别是 JohnDoe

使用正则表达式限制参数

如果你需要更精细的控制,可以通过正则表达式来限制路由参数的格式。可以在路由装饰器中使用 re 参数来指定正则表达式。

import re

@route('/item/<id:re:[0-9]+>')
def show_item(id):
    return f"Item ID is {id}"

在这个例子中,<id:re:[0-9]+> 表示 id 参数必须是一个数字。如果访问 http://localhost:8080/item/123,返回 Item ID is 123,但访问 /item/abc 会返回 404 错误。

请求对象

在 Bottle 中,request 对象用于表示 HTTP 请求的所有信息。通过 request 对象,你可以获取请求的各种数据,包括查询参数、表单数据、HTTP 请求头、客户端信息等。

获取 URL 查询参数

查询参数是 URL 中 ? 后面的部分,通常以键值对的形式传递。例如,访问 http://localhost:8080/greet?name=Johnname=John 就是查询参数。

from bottle import request

@route('/greet')
def greet():
    name = request.query.name  # 获取查询参数中的 'name' 参数
    return f"Hello, {name}!"

访问 http://localhost:8080/greet?name=John 时,name 的值将是 John,返回的内容是 Hello, John!

获取表单数据

表单数据通常通过 POST 请求提交,可以通过 request.forms 来访问表单字段的值。

@route('/submit', method='POST')
def submit():
    name = request.forms.get('name')  # 获取表单数据中的 'name' 字段
    return f"Hello, {name}, your form has been submitted!"

HTML 表单代码示例:

<form action="/submit" method="POST">
    <input type="text" name="name" placeholder="Enter your name" />
    <input type="submit" value="Submit" />
</form>
获取请求头

请求头包含关于请求的元数据,如浏览器信息、内容类型等。你可以通过 request.headers 获取请求头。

@route('/headers')
def show_headers():
    user_agent = request.headers.get('User-Agent')  # 获取 User-Agent 请求头
    return f"Your User-Agent is: {user_agent}"
获取请求方法

request.method 返回当前请求的 HTTP 方法(如 GETPOSTPUTDELETE 等)。你可以根据请求方法来决定如何处理请求。

@route('/check_method', method=['GET', 'POST'])
def check_method():
    if request.method == 'GET':
        return "This is a GET request"
    else:
        return "This is a POST request"

响应对象

在 Bottle 中,视图函数通常会返回一个字符串或者其它类型的响应,但你也可以使用 response 对象来对响应进行更细致的控制。response 对象提供了很多功能,可以让你控制响应的内容类型、HTTP 状态码等。

设置响应内容

默认情况下,Bottle 会将视图函数的返回值作为响应内容。如果你需要返回更复杂的内容(如 JSON 或者 HTML),可以直接操作 response.body

from bottle import response
import json

@route('/json')
def get_json():
    data = {'name': 'John', 'age': 30}
    response.content_type = 'application/json'  # 设置响应内容类型为 JSON
    return json.dumps(data)

在这个例子中,返回的内容类型为 application/json,表示响应的数据是 JSON 格式。

设置响应头

你可以使用 response.headers 设置返回的 HTTP 响应头。

@route('/custom_header')
def custom_header():
    response.headers['X-Custom-Header'] = 'Hello, World!'
    return "Response with custom header"

访问这个路由时,返回的响应会包含一个名为 X-Custom-Header 的自定义响应头,值为 Hello, World!

设置 HTTP 状态码

通过设置 response.status,你可以控制返回的 HTTP 状态码。默认情况下,Bottle 会返回 200 状态码,表示请求成功。如果你希望返回其他状态码,可以手动设置。

@route('/error')
def error():
    response.status = 404  # 设置状态码为 404
    return "Page not found"

访问 /error 路径时,浏览器会接收到 404 错误。

构建RESTful API

RESTful API(代表性状态转移的应用程序接口)是一种设计风格,通过HTTP协议实现客户端与服务器之间的通信。在Web应用中,RESTful API非常常见,它允许客户端与服务器以标准的方式进行交互。在这篇教程中,我们将深入介绍如何使用 Bottle 框架构建RESTful API,涵盖 RESTful 设计原则、GET、POST、PUT 和 DELETE 请求的实现。

RESTful设计原则

REST(Representational State Transfer)是一种基于 Web 的架构风格,其核心设计思想是通过 HTTP 协议的方法(GET、POST、PUT、DELETE)来操作资源。以下是 RESTful API 的一些关键设计原则:

  • 资源:每个数据实体或信息对象(如用户、文章、产品)都被视为一个资源。资源应该有一个唯一的 URI(统一资源标识符)。
  • HTTP 方法
    • GET:用于获取资源。
    • POST:用于创建资源。
    • PUT:用于更新资源。
    • DELETE:用于删除资源。
  • 无状态:每个请求都应该包含足够的信息来进行处理,服务器不应保存任何客户端的状态。
  • 支持多种数据格式:API 支持多种格式(如 JSON、XML)来表示资源。
  • 统一接口:每个 API 都应该是幂等的(即无论请求多少次,结果是相同的),并且应该遵循一致的路径命名和参数设计。

创建基础应用

from bottle import Bottle, run

app = Bottle()

@app.route('/')
def home():
    return "Welcome to the Bottle RESTful API!"

run(app, host='localhost', port=8080)

运行上述代码后,访问 http://localhost:8080/ 可以看到 “Welcome to the Bottle RESTful API!” 的欢迎信息。

创建GET请求API

GET 请求用于从服务器获取资源。在 RESTful API 中,GET 请求是最常见的请求方式,通常用于获取单个资源或资源的列表。

获取单个资源

假设我们有一个简单的资源模型 User,我们可以通过 ID 来获取用户信息。

from bottle import Bottle, run, request, response

app = Bottle()

# 模拟的用户数据
users = {
    1: {"name": "John Doe", "email": "john@example.com"},
    2: {"name": "Jane Smith", "email": "jane@example.com"}
}

@app.route('/users/<user_id:int>', method='GET')
def get_user(user_id):
    user = users.get(user_id)
    if user:
        response.content_type = 'application/json'
        return {"id": user_id, "name": user["name"], "email": user["email"]}
    else:
        response.status = 404
        return {"error": "User not found"}

run(app, host='localhost', port=8080)

在这个例子中,/users/<user_id:int> 路径接收一个用户 ID 作为路径参数,返回对应的用户信息。如果用户不存在,则返回 404 错误。

访问 http://localhost:8080/users/1 会返回用户 John Doe 的信息,访问 http://localhost:8080/users/3 会返回 404 错误。

获取所有资源

我们可以扩展上面的应用,来获取所有用户的列表。

@app.route('/users', method='GET')
def get_users():
    response.content_type = 'application/json'
    return {"users": list(users.values())}

访问 http://localhost:8080/users 将返回所有用户的 JSON 列表。

创建POST请求API

POST 请求通常用于创建资源。当客户端发送一个 POST 请求时,服务器会根据请求数据创建一个新的资源,并返回该资源的信息。

创建新用户
@app.route('/users', method='POST')
def create_user():
    # 获取请求体中的 JSON 数据
    user_data = request.json
    if not user_data or not user_data.get('name') or not user_data.get('email'):
        response.status = 400
        return {"error": "Name and email are required"}
    
    # 创建一个新的用户
    new_id = max(users.keys()) + 1
    users[new_id] = {"name": user_data['name'], "email": user_data['email']}
    
    response.status = 201  # 返回 201 创建成功状态码
    return {"id": new_id, "name": user_data['name'], "email": user_data['email']}

在此代码中,客户端通过 POST 请求发送一个 JSON 格式的用户数据,服务器将创建一个新用户并返回新用户的 ID、名字和邮箱。返回的状态码是 201 Created,表示资源已成功创建。

通过工具(如 Postman)发送 POST 请求 http://localhost:8080/users,并附带如下 JSON 数据:

{
  "name": "Tom Hanks",
  "email": "tom@example.com"
}

会创建一个新的用户并返回创建的用户数据。

创建PUT请求API

PUT 请求用于更新现有的资源。它要求客户端提供完整的资源信息,服务器将该资源替换为客户端提供的数据。

更新用户信息
@app.route('/users/<user_id:int>', method='PUT')
def update_user(user_id):
    user_data = request.json
    user = users.get(user_id)
    
    if not user:
        response.status = 404
        return {"error": "User not found"}
    
    if not user_data or not user_data.get('name') or not user_data.get('email'):
        response.status = 400
        return {"error": "Name and email are required"}
    
    # 更新用户数据
    user['name'] = user_data['name']
    user['email'] = user_data['email']
    
    return {"id": user_id, "name": user['name'], "email": user['email']}

在此代码中,客户端通过 PUT 请求发送新的用户数据,服务器将根据提供的 ID 更新该用户的资料。请求体必须包含完整的用户信息(如姓名和邮箱)。

通过工具(如 Postman)发送 PUT 请求 http://localhost:8080/users/1,并附带如下 JSON 数据:

{
  "name": "John Doe Updated",
  "email": "john.updated@example.com"
}

这将更新用户 ID 为 1 的信息,并返回更新后的用户数据。

创建DELETE请求API

DELETE 请求用于删除现有的资源。当客户端发送 DELETE 请求时,服务器将删除指定的资源。

删除用户
@app.route('/users/<user_id:int>', method='DELETE')
def delete_user(user_id):
    user = users.pop(user_id, None)
    
    if user:
        return {"message": "User deleted successfully"}
    else:
        response.status = 404
        return {"error": "User not found"}

在此代码中,客户端通过 DELETE 请求删除指定 ID 的用户。如果删除成功,返回一条成功消息;如果用户不存在,返回 404 错误。

通过工具(如 Postman)发送 DELETE 请求 http://localhost:8080/users/1,将删除用户 ID 为 1 的用户。

模板与静态文件

在构建 Web 应用时,模板渲染和静态文件服务是常见且重要的功能。模板渲染帮助你将数据与 HTML 结构分离,提供动态内容的展示;静态文件服务则让你可以轻松处理 CSS、JavaScript、图片等不需要动态生成的文件。Bottle 作为一个轻量级框架,内建了对这两种功能的支持,使得 Web 开发变得更加简洁和高效。在本教程中,我们将深入介绍如何在 Bottle 中使用模板渲染和静态文件服务。

使用模板渲染

模板引擎允许你将动态数据与静态 HTML 文件结合,生成最终的响应内容。在 Bottle 中,默认使用的是 SimpleTemplate 引擎,当然你也可以配置使用其他模板引擎,如 Jinja2 或 Mako。

配置模板引擎

Bottle 支持内置的 SimpleTemplate 引擎。如果你需要使用其他模板引擎,可以通过配置来更改。例如,下面是如何使用 Jinja2 模板引擎的配置方法:

from bottle import Bottle, template, jinja2_template

# 使用 Jinja2 模板引擎
app = Bottle()

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

app.run(host='localhost', port=8080)

在这个例子中,我们使用 jinja2_template 渲染一个 Jinja2 模板文件 hello.html,并传递了一个变量 name

渲染模板

使用 template 函数来渲染模板文件。模板文件通常存储在一个单独的目录中,可以使用 bottle.TEMPLATE_PATH 来配置模板的搜索路径。

基本示例:
from bottle import Bottle, template

app = Bottle()

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

app.run(host='localhost', port=8080)
hello.tpl:
<!DOCTYPE html>
<html>
<head>
    <title>Hello Page</title>
</head>
<body>
    <h1>Hello, {{name}}!</h1>
</body>
</html>

在这个例子中,hello 是一个模板文件,它会被渲染并返回给用户。模板中的 {{name}} 会被传入的参数值替换。

模板语法

Bottle 使用的是一个非常简洁的模板语法,支持常见的控制结构,如条件语句、循环等。

  • 变量插值: {{variable}}
  • 条件语句: {% if condition %} ... {% endif %}
  • 循环语句: {% for item in items %} ... {% endfor %}
示例:
<!DOCTYPE html>
<html>
<head>
    <title>Items List</title>
</head>
<body>
    <h1>Items:</h1>
    <ul>
    {% for item in items %}
        <li>{{item}}</li>
    {% endfor %}
    </ul>
</body>
</html>
Python 代码:
from bottle import Bottle, template

app = Bottle()

@app.route('/items')
def show_items():
    items = ['Apple', 'Banana', 'Cherry']
    return template('items', items=items)

app.run(host='localhost', port=8080)

此示例中,items 列表中的每个元素都会被渲染为一个 <li> 标签。

模板继承

模板继承是一种让页面共享布局的方式,避免了在多个模板文件中重复相同的代码。可以通过 blockextends 来实现模板的继承。

父模板:
<!-- layout.tpl -->
<!DOCTYPE html>
<html>
<head>
    <title>{{title}}</title>
</head>
<body>
    <header>
        <h1>{{title}}</h1>
    </header>
    <main>
        {% block content %} {% endblock %}
    </main>
</body>
</html>
子模板:
<!-- home.tpl -->
{% extends "layout.tpl" %}

{% block content %}
    <p>Welcome to the homepage!</p>
{% endblock %}
Python 代码:
from bottle import Bottle, template

app = Bottle()

@app.route('/')
def home():
    return template('home', title="Home Page")

app.run(host='localhost', port=8080)

在这个例子中,home.tpl 继承了 layout.tpl 模板,且只有内容部分被替换。

静态文件服务

在 Web 应用中,静态文件(如 CSS、JavaScript 和图像文件)通常不需要经过动态生成,而是直接从服务器返回。Bottle 提供了非常简便的方式来服务这些静态文件。

静态文件服务

Bottle 提供了 static_file() 函数来服务静态文件。你可以为静态文件指定一个路由,并将静态文件的路径作为响应返回。

from bottle import Bottle, static_file

app = Bottle()

# 处理静态文件请求
@app.route('/static/<filename>')
def server_static(filename):
    return static_file(filename, root='./static')

app.run(host='localhost', port=8080)

在这个例子中,我们将所有对 /static/ 路径的请求映射到本地 ./static 文件夹中的文件。比如,当访问 http://localhost:8080/static/style.css 时,服务器会返回 ./static/style.css 文件的内容。

处理静态文件的目录结构

通常,Web 应用的静态文件会存放在 static 文件夹中。为了方便管理,建议将静态资源与应用代码分开存放。

project/
│
├── app.py
└── static/
    ├── images/
    ├── css/
    └── js/

在此结构中,static/images/ 存放图片文件,static/css/ 存放 CSS 文件,static/js/ 存放 JavaScript 文件。你可以按需配置路由来访问这些资源。

使用静态文件

假设你有一个 CSS 文件 style.css,你可以在 HTML 模板中使用它:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="/static/css/style.css">
    <title>My Web App</title>
</head>
<body>
    <h1>Welcome to My Web App</h1>
</body>
</html>

当访问此 HTML 页面时,浏览器会向 /static/css/style.css 路径发出请求,Bottle 会返回位于 ./static/css/style.css 的文件内容。

高级功能

Bottle 是一个轻量级的 Python Web 框架,设计简洁且功能丰富。在本篇教程中,我们将深入探讨 Bottle 的一些高级功能,帮助你更高效地构建 Web 应用。我们将着重介绍以下内容:

  • 中间件(Middleware):在请求和响应的过程中插入自定义操作。
  • 插件系统:如何使用和创建插件,扩展 Bottle 的功能。
  • 请求和响应钩子:处理请求前后或响应前后的自定义操作。
  • 错误处理:如何处理常见的 HTTP 错误和自定义错误。
  • JSON 数据处理:如何处理 JSON 请求和响应。
  • Session 管理:如何处理会话存储,保持用户状态。

这些功能能够帮助你在实际项目中更加高效地管理 Web 应用的复杂性。

中间件(Middleware)

中间件是在请求和响应的过程中,拦截请求或修改响应的一段代码。Bottle 本身提供了基本的中间件支持,可以通过 install() 方法注册中间件。

使用中间件记录日志

我们可以编写一个简单的中间件,用于记录每个请求的信息(例如请求方法、路径、响应状态等)。

from bottle import Bottle, request, response, run
import logging

app = Bottle()

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')

# 定义日志中间件
def log_request(app):
    def wrapper(environ, start_response):
        # 请求前记录日志
        logging.info(f"{request.method} {request.path}")
        return app(environ, start_response)
    return wrapper

# 注册中间件
app.install(log_request)

@app.route('/')
def home():
    return "Welcome to Bottle with Middleware!"

run(app, host='localhost', port=8080)

在这个例子中,每当一个请求到达时,log_request 中间件会记录下请求的方法和路径。你可以扩展该中间件来记录更多的信息,例如响应状态码或请求头。

使用中间件处理 CORS

跨源资源共享(CORS)是 Web 开发中的一个常见问题。我们可以使用中间件来处理 CORS 头部,允许跨域访问:

def enable_cors(app):
    def wrapper(environ, start_response):
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
        return app(environ, start_response)
    return wrapper

# 注册 CORS 中间件
app.install(enable_cors)

这个中间件将为所有响应添加 CORS 相关的头部,使得浏览器可以从不同的域名发起请求。

插件系统

Bottle 提供了一个插件系统,允许开发者扩展框架功能。你可以使用内置插件,也可以编写自己的插件。

使用 Bottle 插件

Bottle 提供了多个内置插件来简化常见的任务,比如数据库连接、Session 管理等。以下是使用 Bottle 的 simplejson 插件来处理 JSON 数据的例子:

from bottle import Bottle, request, response
from bottle import plugin

app = Bottle()

@plugin(name='json')
def json_plugin(callback):
    def wrapper(*args, **kwargs):
        if request.content_type == 'application/json':
            request.json = request.json()
        return callback(*args, **kwargs)
    return wrapper

app.install(json_plugin)

@app.route('/json', method='POST')
def json_example():
    data = request.json
    return {'received': data}

run(app, host='localhost', port=8080)
创建自定义插件

你也可以创建自己的插件。一个插件通常是一个可以安装的类,并且可以通过 app.install() 方法进行注册。

from bottle import Bottle, response

class MyPlugin:
    def apply(self, callback, route):
        def wrapper(*args, **kwargs):
            response.headers['X-My-Plugin'] = 'Active'
            return callback(*args, **kwargs)
        return wrapper

app = Bottle()

@app.route('/test')
def test():
    return "Plugin is working!"

# 安装插件
app.install(MyPlugin())

run(app, host='localhost', port=8080)

在这个例子中,我们创建了一个名为 MyPlugin 的插件,它会在响应中添加一个自定义的 HTTP 头 X-My-Plugin: Active

请求和响应钩子

请求和响应钩子是 Bottle 的重要特性,可以让你在请求处理的不同阶段执行代码。Bottle 提供了以下几种钩子:

  • before_request:在请求处理之前执行。
  • after_request:在请求处理之后执行。
  • error:当发生错误时执行。
before_request 和 after_request 示例
from bottle import Bottle, request, response, run

app = Bottle()

# before_request 钩子
@app.hook('before_request')
def before_request():
    response.headers['X-Request-Time'] = 'Started'

# after_request 钩子
@app.hook('after_request')
def after_request():
    response.headers['X-Response-Time'] = 'Ended'

@app.route('/')
def home():
    return "Hello, Bottle!"

run(app, host='localhost', port=8080)

在这个例子中,before_request 钩子在请求到来时设置一个自定义的头部 X-Request-Time,而 after_request 钩子在响应发送之前设置一个 X-Response-Time

错误处理钩子

你还可以定义一个错误处理钩子来捕获应用中的异常并返回自定义的错误响应:

@app.hook('error')
def handle_error(error):
    return {"error": str(error.status_code), "message": error.body}

JSON 数据处理

Bottle 在处理 JSON 数据时非常方便。你可以使用 request.json 属性获取请求体中的 JSON 数据,也可以使用 response.json 返回 JSON 响应。

解析 JSON 请求
@app.route('/post_json', method='POST')
def post_json():
    data = request.json
    return {"received": data}

当客户端发送 JSON 数据时,request.json 会自动解析并将其转换为 Python 字典对象。

返回 JSON 响应
@app.route('/json_response')
def json_response():
    data = {"message": "Hello, JSON!"}
    response.content_type = 'application/json'
    return data

通过设置 response.content_type = 'application/json',你可以明确地告诉客户端返回的数据是 JSON 格式。

Session 管理

在 Web 应用中,Session 是一种常见的状态管理方式。Bottle 提供了一个内置的 Session 插件,支持在客户端使用 cookie 存储会话数据。

使用 Session 插件
from bottle import Bottle, request, response, run
from bottle import default_app
from bottle import session

app = Bottle()

# 使用 session 插件
@app.route('/login', method='POST')
def login():
    session['username'] = request.forms.get('username')
    return {"message": "Logged in!"}

@app.route('/profile')
def profile():
    username = session.get('username')
    if username:
        return {"message": f"Hello, {username}!"}
    else:
        response.status = 403
        return {"error": "Not logged in!"}

app.config['session'] = {'secret_key': 'supersecretkey'}
run(app, host='localhost', port=8080)

在这个例子中,我们使用了 session 对象来存储用户的登录信息。用户登录时,用户名会被存储在 session 中,而访问 /profile 时,系统会检查用户是否已登录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/911258.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言 | Leetcode C语言题解之第542题01矩阵

题目&#xff1a; 题解&#xff1a; /*** Return an array of arrays of size *returnSize.* The sizes of the arrays are returned as *returnColumnSizes array.* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().*/ type…

Transformer究竟是什么?预训练又指什么?BERT

目录 Transformer究竟是什么? 预训练又指什么? BERT的影响力 Transformer究竟是什么? Transformer是一种基于自注意力机制(Self-Attention Mechanism)的神经网络架构,它最初是为解决机器翻译等序列到序列(Seq2Seq)任务而设计的。与传统的循环神经网络(RNN)或卷…

【春秋云镜】CVE-2023-23752

目录 CVE-2023-23752漏洞细节漏洞利用示例修复建议 春秋云镜&#xff1a;解法一&#xff1a;解法二&#xff1a; CVE-2023-23752 是一个影响 Joomla CMS 的未授权路径遍历漏洞。该漏洞出现在 Joomla 4.0.0 至 4.2.7 版本中&#xff0c;允许未经认证的远程攻击者通过特定 API 端…

51单片机教程(七)- 蜂鸣器

1 项目分析 利用P2.3引脚输出电平变化&#xff0c;控制蜂鸣器的鸣叫。 2 技术准备 1 蜂鸣器介绍 有绿色电路板的一种是无源蜂鸣器&#xff0c;没有电路板而用黑胶封闭的一种是有源蜂鸣器。 有源蜂鸣器和无源蜂鸣器 这里的“源”不是指电源。而是指震荡源。也就是说有源蜂鸣…

十六 MyBatis使用PageHelper

十六、MyBatis使用PageHelper 16.1 limit分页 mysql的limit后面两个数字&#xff1a; 第一个数字&#xff1a;startIndex&#xff08;起始下标。下标从0开始。&#xff09;第二个数字&#xff1a;pageSize&#xff08;每页显示的记录条数&#xff09; 假设已知页码pageNum&…

汽车和飞机研制过程中“骡车”和“铁鸟”

在汽车和飞机的研制过程中&#xff0c;“骡车”和“铁鸟”都扮演着至关重要的角色。 “骡车”在汽车研制中&#xff0c;是一种处于原型车和量产车之间的过渡阶段产物。它通常由不同的零部件组合而成&#xff0c;就像骡子是马和驴的杂交后代一样&#xff0c;取各家之长。“骡车…

MySQL存储目录与配置文件(ubunto下)

mysql的配置文件&#xff1a; 在这个目录下&#xff0c;直接cd /etc/mysql/mysql.conf.d mysql的储存目录&#xff1a; /var/lib/mysql Ubuntu版本号&#xff1a;

RibbitMQ-安装

本文主要介绍RibbitMQ的安装 RabbitMQ依赖于Erlang&#xff0c;因此首先需要安装Erlang环境。分别下载erlang-26.2.5-1.el7.x86_64.rpm、rabbitmq-server-4.0.3-1.el8.noarch.rpm 官网地址&#xff1a;https://www.rabbitmq.com/ 官网文档&#xff1a;https://www.rabbitmq.c…

【Linux】解锁操作系统潜能,高效线程管理的实战技巧

目录 1. 线程的概念2. 线程的理解3. 地址空间和页表4. 线程的控制4.1. POSIX线程库4.2 线程创建 — pthread_create4.3. 获取线程ID — pthread_self4.4. 线程终止4.5. 线程等待 — pthread_join4.6. 线程分离 — pthread_detach 5. 线程的特点5.1. 优点5.2. 缺点5.3. 线程异常…

WPF+MVVM案例实战(二十二)- 制作一个侧边弹窗栏(CD类)

文章目录 1、案例效果1、侧边栏分类2、CD类侧边弹窗实现1、样式代码实现2、功能代码实现3 运行效果4、源代码获取1、案例效果 1、侧边栏分类 A类 :左侧弹出侧边栏B类 :右侧弹出侧边栏C类 :顶部弹出侧边栏D类 :底部弹出侧边栏2、CD类侧边弹窗实现 1、样式代码实现 在原有的…

如何对LabVIEW软件进行性能评估?

对LabVIEW软件进行性能评估&#xff0c;可以从以下几个方面着手&#xff0c;通过定量与定性分析&#xff0c;全面了解软件在实际应用中的表现。这些评估方法适用于确保LabVIEW程序的运行效率、稳定性和可维护性。 一、响应时间和执行效率 时间戳测量&#xff1a;使用LabVIEW的时…

stm32使用串口DMA实现数据的收发

前言 DMA的作用就是帮助CPU来传输数据&#xff0c;从而使CPU去完成更重要的任务&#xff0c;不浪费CPU的时间。 一、配置stm32cubeMX 这两个全添加上。参数配置一般默认即可 代码部分 只需要把上期文章里的HAL_UART_Transmit_IT(&huart2,DATE,2); 全都改为HAL_UART_Tra…

论文1—《基于卷积神经网络的手术机器人控制系统设计》文献阅读分析报告

论文报告&#xff1a;基于卷积神经网络的手术机器人控制系统设计 摘要 本研究针对传统手术机器人控制系统精准度不足的问题&#xff0c;提出了一种基于卷积神经网络的手术机器人控制系统设计。研究设计了控制系统的总体结构&#xff0c;并选用PCI插槽上直接内插CAN适配卡作为上…

「C/C++」C/C++ 之 变量作用域详解

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

JSP ft06 问题几个求解思路整理

刷到这篇文章使用Q-learning去求接JSP ft06 问题用基本Q-learning解决作业车间调度问题(JSP)&#xff0c;以FT06案例为例_q-learning算法在车间调度-CSDN博客 本着贼不走空的原则打算全部copy到本地试下&#xff0c;文章作者使用的tf06.txt在这里获取 https://web.cecs.pdx.e…

Uniapp安装Pinia并持久化(Vue3)

安装pinia 在uni-app的Vue3版本中&#xff0c;Pinia已被内置&#xff0c;无需额外安装即可直接使用&#xff08;Vue2版本则内置了Vuex&#xff09;。 HBuilder X项目&#xff1a;直接使用&#xff0c;无需安装。CLI项目&#xff1a;需手动安装&#xff0c;执行yarn add pinia…

Template Method(模板方法)

1)意图 定义一个操作中的算法骨架&#xff0c;而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 2)结构 模板方法模式的结构图如图7-47 所示。 其中: AbstractClass(抽象类) 定义抽象的原语操作&#xff0c;具体…

无人机场景数据集大全「包含数据标注+划分脚本+训练脚本」 (持续原地更新)

一、作者介绍&#xff1a;六年算法开发经验、AI 算法经理、阿里云专家博主。擅长&#xff1a;检测、分割、理解、AIGC 等算法训练与推理部署任务。 二、数据集介绍&#xff1a; 质量高&#xff1a;高质量图片、高质量标注数据&#xff0c;使用 labelimg 软件吐血标注、整理&…

安当ASP系统:适合中小企业的轻量级Radius认证服务器

安当ASP&#xff08;Authentication Service Platform&#xff09;身份认证系统是一款功能强大的身份认证服务平台&#xff0c;特别适用于中小企业。其中&#xff0c;简约型Radius认证服务器是安当ASP系统中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、主要…

跨域及解决跨域

什么是跨域 前端与后端不在同一个域名下&#xff1a; 解决 import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component;import java.io.IOException…