一个小型的用于构建Web应用的框架
项目描述
一个小型的用于构建Web应用的框架
用法
Steinie围绕路由的概念构建。您的应用程序由一个或多个路由组成,这些路由指导Web请求通过您的代码。让我们从最简单的Hello World Web应用开始。
from steinie import Steinie
app = Steinie()
@app.get("/")
def get(request, response):
return "Hello World, from Steinie!\n"
if __name__ == "__main__":
app.run()
如果您将此保存到文件中,可以直接使用python运行此命令。这将在本地计算机的5151端口启动一个简单的开发服务器,并响应本地计算机上的/路由。试一试。
Steinie使用Werkzeug来处理其路由。这意味着您可以在Steinie内部使用所有熟悉的路由模式。
Steinie为GET和POST以及DELETE、HEAD、INFO、OPTIONS、PATCH、PUT和TRACE提供了内置的装饰器。
处理参数
另一个常见需求是为您的Web应用提供参数。假设您想在路径中添加一个username,但您希望它是大写的(请稍等一下),您可以使用param装饰器这样做
from steinie import Steinie
app = Steinie()
@app.param("username")
def capitalize(param):
return param.capitalize()
@app.get("/<username:some_user>")
def handler(request, response):
return "Hello, %s\n" % request.params["some_user"]
if __name__ == "__main__":
app.run()
使用param装饰器,您指定要创建的参数名称,然后提供一个函数指定您要执行的操作。您可以运行此示例,然后加载http://localhost:5151/alice,它将响应“Hello, Alice!”
如果您熟悉Flask的(以及通过扩展,Werkzeug的)转换器,这可能会看起来非常熟悉。再次强调,基于Werkzeug的基础,这里提供的大部分内容都模仿了您可能已经熟悉的内容。
现在您已经看到了基本示例,想象一下,如果您创建了一个从数据库中加载用户对象并返回它的函数。使用 params 装饰器,您可以将传入请求的基本参数转换成与您实际应用程序建模方式相匹配的内容。
分组路由和参数
您可能会想知道这如何扩展。一个文件中包含大量装饰函数听起来对我来说非常难以驾驭。幸运的是,Steinie 提供了一种通过所谓的 Router 来将功能拆分为逻辑部分的方法。
让我们增强上面的示例。其中大部分都与用户相关,因此我们将创建一个新的 Route,然后将其挂载到 /user。
首先,调整导入语句,使其看起来像这样
from steinie import Steinie, Router
接下来,从 Router 创建一个新的 route 对象,并调整您的两个装饰函数以使用它。它应该看起来像这样
route = Router()
@route.param("username")
def capitalize(param):
return param.capitalize()
@route.get("/<username:some_user>")
def handler(request, response):
return "Hello, %s\n" % request.params["some_user"]
最后,您需要修改您的 app 对象以使用这个新路由。您可以使用命名得恰当的 use 方法这样做
app.use("/user", route)
保存您的作品,启动您的代码,然后再次访问您的服务器。如果您再次尝试访问 http://localhost:5151/alice,您将得到一个 404。相反,您需要在 URL 中添加 /user,使其看起来像这样: http://localhost:5151/user/alice。
处理中间件
成为 Steine 专家的另一个部分是中间件。中间件为您提供了修改每个传入请求的请求或响应的机会。
让我们继续构建上面的示例。我们不再使用 param 装饰器,而是创建一个中间件,将所有 some_user 参数转换为大写。
首先,让我们创建中间件。Steinie 期望它们是对象,可以被实例化并提供一个 Router 实例,然后通过 __call__ 方法调用。就是这样。将此添加到您的文件中,然后您可以说您已经创建了您自己的 Steinie 中间件
class CapitalizeMiddleware(object):
def __init__(self, route):
pass
def __call__(self, request, response, _next):
if "some_user" in request.params:
new = request.params["some_user"].capitalize()
request.params["some_user"] = new
return _next(request, response)
这里有一些需要注意的地方。首先,我们不需要在实例化时提供的 route,因此没有必要存储它。如果您这样做,您可以将其设置为类的属性。
接下来,__call__ 方法有三个参数。 request 和 response 来自于之前的示例,但 _next 是新的。这是 Steinie 生成的函数,允许中间件控制调用时的操作。在我们的例子中,我们想要修改当它存在时 some_user 的值,将其转换为大写,然后继续。为此,您只需返回 _next(request, response) 的结果。
在这里控制操作的能力是 Steinie 中间件的关键部分。您可以从 _next 捕获返回值并对其进行处理。我想到的用例包括一个 CacheMiddleware,它尝试从缓存中加载请求并返回它(如果找到),如果没有缓存,则允许请求通过。
这个简单的例子只是这样,相当简单。
您还没有完成中间件的设置。接下来,您需要告诉您的路由器使用它。再次使用 router.use
route.use(CapitalizeMiddleware)
这是您用来将路由器附加到应用程序的方法,但这次没有与之关联的路由(您上面使用的第一个参数)。将 router.use 与单个参数一起使用会向 Steinie 发出信号,表示您正在提供它一个中间件,它应在处理该路由器尝试处理的全部请求时执行。
您应该做的最后修改是删除 params 函数并调整您的 get 路由。完成后,它应该看起来像这样
@route.get("/<some_user>")
def handler(request, response):
return "Hello, %s\n" % request.params["some_user"]
现在,重新运行您的代码并访问它。您应该得到相同的结果,但这是一种不同的模式。哪一种模式更好?有趣的是,这正是下一个话题。
中间件与参数
中间件和参数都可以用来实现非常相似的目标,但它们有不同的角色。
- 中间件
这些是全局的,有机会修改每个传入的请求。它们拥有完整的请求,并且能够绕过正常的响应。当您需要修改给定路由处理的 每个 请求时,或者您需要做的不仅仅是改变请求 URL 的一部分到其他对象时,请使用它们。
- 参数
这些局限于具有请求 URL 中的参数的路由。与中间件不同,它们所能做的只是将 URL 的一部分转换成其他内容。当您需要将 ID 转换为数据库中的对象或其他类似转换时,它们非常有用,但它们不会让您更改 Steinie 返回的响应。
灵感
Steinie 在服务器端 JavaScript 世界中受到 Express 的强烈启发。对于 4.x 重写,Express 开始大量借鉴 Steinie 使用的基于路由的模型。
项目详情
steinie-1.0.1.tar.gz 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 6116e6b5674c4da71f896268f8f7d497b810fc72e3bb1bd64c0ef35eaca59307 |
|
MD5 | e169276880c689cff281b744225e0b68 |
|
BLAKE2b-256 | 78dd3b82275492a6ed6999cb0e652734f31717b1d8320185e0ea4c794725fa80 |