Bottle快速开始
Bottle 是一个非常轻量级的 Python Web 框架,适合用于构建简单的 Web 应用和 RESTful API。Bottle 的最大特点之一是它的单文件设计,意味着你只需下载一个文件 bottle.py
即可使用整个框架,而不需要安装其他依赖。在这篇教程中,我们将演示如何通过下载 bottle.py
文件并直接导入它,快速搭建你的第一个 Web 应用。
环境搭建:通过单个 bottle.py
文件
获取 Bottle 库
-
下载
bottle.py
文件Bottle 的源代码可以直接从GitHub 仓库下载,或者通过以下步骤手动获取:
- 打开浏览器,访问 https://github.com/bottlepy/bottle。
- 点击 "Code" 按钮,然后选择 "Download ZIP" 下载整个仓库。
- 解压后,找到
bottle.py
文件。
-
将
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
文件提供的 route
和 run
函数。这个 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
:这行代码导入了route
和run
函数,它们分别用于定义路由和启动应用。@route('/hello')
:这是一个路由装饰器,告诉 Bottle 当访问/hello
路径时,执行下面的hello()
函数。def hello():
:这是定义的视图函数。当用户访问/hello
时,返回一个简单的文本响应:"Hello, World!"。run(host='localhost', port=8080)
:启动应用,监听本地localhost
地址的 8080 端口。
运行应用
-
打开终端,进入到
app.py
所在的目录。 -
直接运行
app.py
文件:bashpython app.py
-
打开浏览器,访问
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_name
和 last_name
将分别是 John
和 Doe
。
使用正则表达式限制参数
如果你需要更精细的控制,可以通过正则表达式来限制路由参数的格式。可以在路由装饰器中使用 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=John
,name=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 方法(如 GET
、POST
、PUT
、DELETE
等)。你可以根据请求方法来决定如何处理请求。
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>
标签。
模板继承
模板继承是一种让页面共享布局的方式,避免了在多个模板文件中重复相同的代码。可以通过 block
和 extends
来实现模板的继承。
父模板:
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
时,系统会检查用户是否已登录。