【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 文件。可以通过如下方式实现:

python 复制代码
# 导入本地的 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 文件,并写入以下代码:

python 复制代码
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 文件:

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

路由和请求方法

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

路由参数

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

python 复制代码
@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 应用中最常见的请求方法。

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

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

POST 请求

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

python 复制代码
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' 显式指定这些方法。

python 复制代码
@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 请求中的表单数据。
python 复制代码
@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> 占位符来捕获路径的一部分。

python 复制代码
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 支持多种类型的路由参数,可以通过自定义参数类型来限制输入的内容:

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

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

捕获多个参数

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

python 复制代码
@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 参数来指定正则表达式。

python 复制代码
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 就是查询参数。

python 复制代码
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 来访问表单字段的值。

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

HTML 表单代码示例:

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

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

python 复制代码
@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 等)。你可以根据请求方法来决定如何处理请求。

python 复制代码
@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

python 复制代码
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 响应头。

python 复制代码
@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 状态码,表示请求成功。如果你希望返回其他状态码,可以手动设置。

python 复制代码
@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 都应该是幂等的(即无论请求多少次,结果是相同的),并且应该遵循一致的路径命名和参数设计。

创建基础应用

python 复制代码
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 来获取用户信息。

python 复制代码
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 错误。

获取所有资源

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

python 复制代码
@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 请求时,服务器会根据请求数据创建一个新的资源,并返回该资源的信息。

创建新用户
python 复制代码
@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 数据:

json 复制代码
{
  "name": "Tom Hanks",
  "email": "tom@example.com"
}

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

创建PUT请求API

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

更新用户信息
python 复制代码
@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 数据:

json 复制代码
{
  "name": "John Doe Updated",
  "email": "john.updated@example.com"
}

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

创建DELETE请求API

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

删除用户
python 复制代码
@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 模板引擎的配置方法:

python 复制代码
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 来配置模板的搜索路径。

基本示例:
python 复制代码
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:
html 复制代码
<!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 %}
示例:
html 复制代码
<!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 代码:
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 来实现模板的继承。

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

{% block content %}
    <p>Welcome to the homepage!</p>
{% endblock %}
Python 代码:
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() 函数来服务静态文件。你可以为静态文件指定一个路由,并将静态文件的路径作为响应返回。

python 复制代码
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 文件夹中。为了方便管理,建议将静态资源与应用代码分开存放。

bash 复制代码
project/
│
├── app.py
└── static/
    ├── images/
    ├── css/
    └── js/

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

使用静态文件

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

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() 方法注册中间件。

使用中间件记录日志

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

python 复制代码
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 头部,允许跨域访问:

python 复制代码
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 数据的例子:

python 复制代码
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() 方法进行注册。

python 复制代码
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 示例
python 复制代码
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

错误处理钩子

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

python 复制代码
@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 请求
python 复制代码
@app.route('/post_json', method='POST')
def post_json():
    data = request.json
    return {"received": data}

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

返回 JSON 响应
python 复制代码
@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 插件
python 复制代码
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 时,系统会检查用户是否已登录。

相关推荐
勤奋的大熊猫几秒前
Jupyter lab 打开时默认使用 Notebook 而不是浏览器
ide·python·jupyter
猫猫村晨总6 分钟前
涉及到行合并的el-table表格导出功能实现
前端·vue.js·element plus
AiFlutter15 分钟前
Java对接GraphQL
java·开发语言·graphql
VillanelleS22 分钟前
Vue2进阶之Vue3高级用法
前端·javascript·vue.js
天农学子26 分钟前
EasyUI弹出框行编辑,通过下拉框实现内容联动
前端·javascript·easyui
AI视觉网奇1 小时前
pytorch3d报错:RuntimeError: Not compiled with GPU support.
人工智能·pytorch·python
格瑞@_@1 小时前
11.Three.js使用indexeddb前端缓存模型优化前端加载效率
前端·javascript·缓存·three.js·indexeddb缓存
虞书欣的61 小时前
Python小游戏22——吃豆豆小游戏
python·算法·游戏·编辑器·pygame
cliffordl1 小时前
SQLAlchemy 介绍与实践
数据库·python
木子七1 小时前
Js Dom
前端·javascript