Vibora 填坑笔记

Author Avatar
Xin Qiu Jul 09, 2018
  • Read this article on other device

vibora 填坑笔记

学习 asyncio 时无意间发现的高性能 Web 框架,正好 Django 学累了,换换口味。

简介

Vibora 是一个基于 python 3.6+的高性能简洁的异步 http C/S 框架,因为是才出来的项目,这里面还有不少坑。

首先是安装,python3.6+ 才能体验完整的特性。这里使用的是 Vibora 0.06。

pip install vibora[fast]

启动 Vibora 非常的简单,新建一个 main.py 并填写以下代码,运行 python main.py 即可运行一个经典的 Hello World Web 服务器。简洁性非常类似 Flask。

from vibora import Vibora
from vibora.responses import Response


app = Vibora()


@app.route('/')
async def home():
    return Response(b"Hello  World!")

if __name__ == '__main__':
    app.run(debug=False, port=8000)

这里要注意的是, Response(b"Hello World!") 中的 b 是万万不能少的,Response 里传递的是 bytes 对象,所以只能是英文字符,那么问题来了,如果想传中文怎么办?将其改成 Response(f'你好,世界'.encode('utf-8')),其中'utf-8'是省略可以不写的。

路由

类似 Flask 的方式,使用装饰器的方式来快速设置路由,其中 methods 默认为 GET 。

@app.route("/home", methods=['GET'])
async def home():
    return Response(b'123')

URL请求参数

除了上面的静态路由,也有动态的路由。

@app.route('/<page_id>')
async def page(page_id: int):
    return Response(f'Page {page_id}'.encode())

尖括号中的是变量名字,传入函数时一定要加上类型, Vibora 在某种程度上对类型的要求比较严格,在字符串中,使用花括号将变量包裹可以由 Response 之后进行转义。

路由逻辑

Vibora 有三种路由逻辑:

  • Strict 严格要求ULR,路径缺少/会跳转到404
  • Redirect (默认的方式) 路径缺少/会进行302跳转
  • Clone 类似重定向,但不会是302

可以在应用运行前设置。

from vibora import Vibora
from vibora.router import RouterStrategy

app = Vibora(router_strategy=RouterStrategy.STRICT)

静态文件

Vibora提供了静态文件的特性,通过设置目录。

from vibora.static import StaticHandler

app = Vibora(
    static=StaticHandler(
        paths=['/your_static_dir', '/second_static_dir'],
        host='static.vibora.io',
        url_prefix='/static',
        max_cache_size=1 * 1024 * 1024
    )
)

请求回应

JSON Response

除了简介里提到的普通回应,这里还有一种 Json 回应,非常适合做成 restful api。

from vibora import Vibora
from vibora.responses import JsonResponse


app = Vibora()

@app.route('/api')
async def api():
    return JsonResponse({'Hello': 'world'})


if __name__ == '__main__':
    app.run(debug=True, port=8000)

Streaming Response

如果客户端发来请求,服务器需要一些耗时操作之后才能返回结果,为了不阻塞其他的客户端请求,这里构造了一个异步操作,使用流式回应,可以等服务端处理好时,及时返回给客户端,客户端并不需要端口连接。

@app.route('/home', methods=['GET'])
async def home():
    async def stream_builder():
        for x in range(0, 5):
            yield str(x).encode()
            await asyncio.sleep(0.5)

    return StreamingResponse(stream_builder, chunk_timeout=5, complete_timeout=30)

其中,StreamingResponse 第一个参数必须是一个可回调的函数, chunk_timeout 的机制我还没摸索透,阅读源码会发现,应该是指传输这个流的时间限制,其调用的是 stream_chunked_response 这个函数,这里面会发现, chunk_timeout 就是这里异步传送 chunk 的时限。 complete_timeout 很好理解,就是启用这个流的时间,如果流数据传送时间超过这个 timeout,这个回应就会关闭,这样操作可以有效的防止DDoS。

渲染模板

其实模板引擎算是单独的一个章节,但很多情况下,Response是用于api的访问,而页面访问,大多是进行渲染传递特殊的数据。渲染操作非常类似 Jinja2。

这里是需要将模板页面放在模板文件夹里的,默认的模板路径是python脚本的同一层级,也就是

.
├── main.py
└── templates
    └── index.html

这里 index.html 就是简单的模板 HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
这是第 {{ tmp }} 页
</body>
</html>

使用 await app.render 来进行渲染页面,后面的参数即为需要传递的参数,在上面的模板中,使用 将传递的变量名包裹,这样就能显示由后端传递到前端的变量值。

@app.route('/<page_id>')
async def home(page_id: int):
    return await app.render('index.html', tmp=page_id)

因为和 Jinja2 几乎是一样的,所以完全可以用 Jinja2 的思路来写模板,确实减少了不少学习成本。

表单

目前 Vibora 貌似只提供了部分简单的表单功能。

@app.route('/form', methods=['POST'])
async def form(request: Request):
    form = await request.form()
    return JsonResponse(form)

以上实现了将读到的表单以JSON的形式返回。这里就牵扯到一个使用curl测试的问题,之前测试了半天,发现后端一直无法得到post的数据,换了Postman却有用,查了半天才知道原来是curl的参数使用错了,以为使用 -d 然后写json就可以发送,其实curl会以application/x-www-url-encoded格式上传参数,真正需要用-F才行,使用-F参数,curl会以multipart/form-data的方式发送POST请求。

使用 Schema

之前介绍了简单的表单功能,实际情况中,表单的格式是需要固定的,这里就引入了 Schema。Schema 可以来约定表单的格式。

 from vibora.schemas import Schema

 class SimpleSchema(Schema):
    name: str

在自定义的 Schema 类中,需要填写变量名和类型,这种没有用到 fields 的方式是用来接收 JSON 格式的表单。

@app.route('/form', methods=['POST'])
async def form(request: Request):
    schema = await SimpleSchema.load_json(request)
    return JsonResponse({'name': schema.name})

使用 .load_json() 可以将 request 转化为上面定义的 Schema 格式。

介绍完简单的 JSON 方式,普通的表单方式, Schema 里则需要一些修改,必须告诉 Schema 更多详细的字段。

class SimpleSchema(Schema):
    name: str = fields.String(required=False)

这样就简单的定义了一个正常 form 的 Schema,其中 required 字段默认为 True,也就是说如果 POST 没有提交这个数据,就会引起错误,如果是 False,那么如果没有提交这个数据,这个变量的值就默认为 null。fields.String 里还有 load_from, default, validators 这些参数, validators 在当前 Vibora 0.0.6 还不能用,所以这几个参数之后再细细研究。 正常 form 变成 Scheme 也很类似 JSON的方式,将 SimpleSchema.load_json 修改为 SimpleSchema.load_form 即可。