RSGI协议文档中文翻译

用AI翻译的rsgi的内容,记录下

RSGI规范

版本: 1.4
github:https://github.com/emmett-framework/granian.git

摘要

本文档提出了Rust网络协议服务器(特别是Web服务器)与Python应用程序之间的标准接口,旨在允许处理多种常见协议类型(包括HTTP、HTTP/2和WebSocket)。

这个基本规范旨在确定这些服务器交互和运行应用程序代码的API集合;每个支持的协议(如HTTP)都有一个子规范,概述了如何以特定方式处理它。

基本原理

ASGI规范在_纯Python环境_中运行良好,提供了与WSGI相同的灵活性。然而,其设计与Python语言本身以及AsyncIO实现不可分割地绑定在一起。例如,ASGI设计是围绕套接字传输和线程范式由Python本身处理的思想构建的;当查看来自不同语言的实现时,这种条件可能导致低效的范式。我们可以将这个概念总结为这句话:_ASGI期望较低级别的协议由Python处理_。

正如摘要所述,RSGI旨在解决我们为用Rust语言编写的服务器描述的低效问题,其中实际的I/O通信和线程组件在Python解释器之外处理,以允许应用程序利用协议实现提供的性能优势。

RSGI试图像ASGI那样保持简单的应用程序接口,同时提供一个抽象,允许数据通过Rust构建的协议发送和接收。这就是为什么,例如,RSGI在应用层为HTTP请求和Websockets保持相同的接口,但基于协议期望这些接口的不同使用方式:与ASGI不同,请求不会使用_消息_处理。

如我们所说,RSGI不是围绕Python处理较低级别协议的思想构建的,因此其设计不是为了保持与ASGI和WSGI的互操作性:I/O基础发生了变化,支持以前的设计从一开始就是一个有缺陷的决定。

它的主要目标是提供一种方法,利用高效的底层协议在Python中编写HTTP/1、HTTP/2、HTTP/3和WebSocket代码。

概述

RSGI由两个不同的组件组成:

  • 协议服务器,它终止套接字并将它们转换为连接和每个连接的对象。
  • 应用程序,它存在于协议服务器内部,每个连接调用一次,并在连接事件发生时处理它们,在必要时发出自己的事件。

与ASGI一样,服务器在其中托管应用程序,并以标准化格式将传入请求分派给它;与ASGI一样,应用程序是异步可调用的,它们通过与可等待对象交互来与服务器通信。RSGI应用程序必须作为async/await兼容的协程(即asyncio兼容)运行(在主线程上;如果需要同步代码,它们可以自由使用线程或其他进程)。

RSGI连接有两个独立的部分:

  • 一个_连接作用域_,像ASGI一样,代表与用户的协议连接,直到连接关闭才终止。
  • 一个应用程序可以交互的_连接协议_接口,负责将数据从客户端传输到客户端和从客户端传输数据。

因此,应用程序被调用并等待连接作用域和连接协议进行交互。所有这些都发生在异步事件循环中。

应用程序可调用的每次调用都映射到单个传入的"套接字"或连接,并且预计将持续该连接的生命周期,如果有清理工作要做,则会稍长一些。

应用程序

RSGI应用程序应该是单个异步可调用对象:

coroutine application(scope, protocol)
  • scope:连接作用域信息,一个包含指定传入协议的类型键和相关信息的对象
  • protocol:一个具有可等待方法来通信数据的对象

应用程序每个"连接"调用一次。连接及其生命周期的定义由相关的协议规范决定。例如,对于HTTP,它是一个请求,而对于WebSocket,它是单个WebSocket连接。

特定协议的子规范涵盖作用域和协议规范。

应用程序的附加方法

RSGI规范还包括以下应用程序的附加方法。

__rsgi__方法

旨在支持绑定到像ASGI这样的异步可调用的额外协议的RSGI应用程序可以公开更具体的__rsgi__方法接口,代替默认调用。 例如,同时支持RSGI和ASGI协议的应用程序将如下所示:

class App:
    async def __call__(self, scope, receive, send):
        # ASGI协议处理
    
    async def __rsgi__(self, scope, protocol):
        # RSGI协议处理

符合RSGI的服务器在存在__rsgi__方法时应优先选择它而不是__call__

__rsgi_init__方法

init方法为RSGI应用程序提供了一种在服务器启动期间执行初始化操作的方式。

__rsgi_init__的签名定义如下,其中loop参数是Python asyncio事件循环:

function __rsgi_init__(loop)
注意:在调用init函数时,事件循环不会运行

因此,公开RSGI init接口的应用程序可能如下所示:

class App:
    def __rsgi_init__(self, loop):
        some_sync_init_task()
        loop.run_until_complete(some_async_init_task())

    async def __rsgi__(self, scope, protocol):
        # RSGI协议处理

__rsgi_del__方法

del方法为RSGI应用程序提供了一种在服务器关闭期间执行清理操作的方式。

__rsgi_del__的签名定义如下,其中loop参数是Python asyncio事件循环:

function __rsgi_del__(loop)
注意:在调用del函数时,事件循环不会运行

因此,公开RSGI del接口的应用程序可能如下所示:

class App:
    def __rsgi_del__(self, loop):
        some_sync_cleanup_task()
        loop.run_until_complete(some_async_cleanup_task())

    async def __rsgi__(self, scope, protocol):
        # RSGI协议处理

协议

HTTP协议

HTTP格式涵盖HTTP/1.0、HTTP/1.1和HTTP/2。HTTP版本作为字符串在作用域中可用。

HTTP连接作用域

HTTP连接具有单请求连接作用域 - 也就是说,您的应用程序将在请求开始时被调用,并将持续到该特定请求结束,即使底层套接字仍然打开并提供多个请求。

如果您保持响应打开以进行长轮询或类似操作,连接作用域将持续到响应从客户端或服务器端关闭为止。

HTTP协议的作用域对象定义如下:

class Scope:
    proto: Literal['http'] = 'http'
    rsgi_version: str
    http_version: str
    server: str
    client: str
    scheme: str
    method: str
    path: str
    query_string: str
    headers: Mapping[str, str]
    authority: Optional[str]

以下是上述属性的描述:

  • rsgi_version:包含RSGI规范版本的字符串
  • http_version:包含HTTP版本的字符串("1"、"1.1"或"2"之一)
  • server:格式为{address}:{port}的字符串,其中host是此服务器的监听地址,port是整数监听端口
  • client:格式为{address}:{port}的字符串,其中host是远程主机的地址,port是远程端口
  • scheme:URL方案部分("http"或"https"之一)
  • method:HTTP方法名称,大写
  • path:HTTP请求目标,不包括任何查询字符串
  • query_string?后的URL部分
  • headers:一个类似映射的对象,其中key是头名称,value是头值;头名称始终为小写;get_all方法返回给定键的所有头值列表
  • authority:一个可选字符串,包含相关的伪头(在HTTP 2之前的版本上为空)

HTTP协议接口

HTTP协议对象实现了两个可等待方法来接收请求体,以及五种不同的方法来发送数据,特别是:

  • __call__bytes格式接收整个正文
  • __aiter__bytes块接收正文
  • response_empty发送回空响应
  • response_str发送回带有str正文的响应
  • response_bytes发送回带有bytes正文的响应
  • response_file发送回文件响应(从其路径)
  • response_stream开始流响应

上述所有响应方法都接受整数status参数、字符串元组列表作为headers参数,以及相关类型的body参数(如适用):

coroutine __call__() -> body
asynciterator __aiter__() -> body chunks
function response_empty(status, headers)
function response_str(status, headers, body)
function response_bytes(status, headers, body)
function response_file(status, headers, file)
function response_stream(status, headers) -> transport

response_stream方法将返回一个_传输对象_,它实现了异步消息接口,具体来说:

  • 一个send_bytes可等待方法,用于从bytes内容生成外发消息
  • 一个send_str可等待方法,用于从str内容生成外发消息
coroutine send_bytes(bytes)
coroutine send_str(str)

Websocket协议

WebSockets共享一些HTTP详细信息 - 它们有路径和头 - 但也有更多状态。同样,大部分状态都在作用域中,它将与套接字一样长寿。

Websocket连接作用域

WebSocket连接的作用域与套接字本身一样长寿 - 如果应用程序终止,套接字应该关闭,反之亦然。

Websocket协议的作用域对象定义如下:

class Scope:
    proto: Literal['ws'] = 'ws'
    rsgi_version: str
    http_version: str
    server: str
    client: str
    scheme: str
    method: str
    path: str
    query_string: str
    headers: Mapping[str, str]
    authority: Optional[str]

以下是上述属性的描述:

  • rsgi_version:包含RSGI规范版本的字符串
  • http_version:包含HTTP版本的字符串("1"、"1.1"或"2"之一)
  • server:格式为{address}:{port}的字符串,其中host是此服务器的监听地址,port是整数监听端口
  • client:格式为{address}:{port}的字符串,其中host是远程主机的地址,port是远程端口
  • scheme:URL方案部分("http"或"https"之一)
  • method:HTTP方法名称,大写
  • path:HTTP请求目标,不包括任何查询字符串
  • query_string?后的URL部分
  • headers:一个类似映射的对象,其中key是头名称,value是头值;头名称始终为小写;get_all方法返回给定键的所有头值列表
  • authority:一个可选字符串,包含相关的伪头(在HTTP 2之前的版本上为空)

Websocket协议接口

Websocket协议对象为应用程序实现了两个接口方法:

  • accept可等待方法
  • close方法
coroutine accept() -> transport
function close(status)

accept可等待方法将返回一个_传输对象_,它实现了异步消息接口,具体来说:

  • 一个receive可等待方法,返回单个传入消息
  • 一个send_bytes可等待方法,用于从bytes内容生成外发消息
  • 一个send_str可等待方法,用于从str内容生成外发消息
coroutine receive() -> message
coroutine send_bytes(bytes)
coroutine send_str(str)

在RSGI websockets中,传入消息由以下形式的对象组成:

class WebsocketMessage:
    kind: int
    data: Optional[Union[bytes, str]]

其中kind是具有以下值的整数:

描述
0客户端关闭的Websocket
1字节消息
2字符串消息
评论已关闭