这是一个用 Python 从头开始编写的小型 HTTP/1.1 库, 深受 hyper-h2 的启发。
它是一个“自带 I/O”的库;h11 完全不包含任何 IO 代码。 这意味着你可以将 h11 连接到你最喜欢的网络 API, 可以是任何你想要的:同步的、基于线程的、异步的, 或者你自己实现的 RFC 6214 —— h11 不会评判你。 (与当前最先进的技术相比,后者每次出现一个新的 网络 API 时,就有人需要从头开始重新实现整个 HTTP 协议。) Cory Benfield 写了一篇 精彩的博文描述了这种方法的优点, 如果你喜欢视频,这里有他关于同一主题的 PyCon 2016 演讲。
这也意味着 h11 开箱即用并非直接有用:
它是一个用于构建支持 HTTP 的程序的工具包,
而不是可以直接替换 requests 或 twisted.web 或
其他东西的工具。但 h11 使得实现类似
requests 或 twisted.web 的东西更加容易。
从宏观角度看,使用 h11 的过程如下:
- 首先,创建一个
h11.Connection对象来跟踪单个 HTTP/1.1 连接的状态。 - 当你从网络读取数据时,将其传递给
conn.receive_data(...);你会得到一个表示高级 HTTP“事件”的 对象列表。 - 当你想要发送一个高级 HTTP 事件时,创建相应的“事件”对象并将其传递给
conn.send(...); 这将返回一些字节,你可以将这些字节推送到网络中。
例如,客户端可能会实例化并发送一个
h11.Request 对象,然后是零个或多个 h11.Data 对象来表示请求正文(例如,如果这是一个 POST 请求),
然后是一个 h11.EndOfMessage 来表示消息的结束。
然后服务器会发送一个 h11.Response,一些 h11.Data,以及
它自己的 h11.EndOfMessage。如果任何一方违反了协议,
你将收到一个 h11.ProtocolError 异常。
h11 适用于实现服务器和客户端,并且具有令人愉悦的对称 API: 客户端发送的事件与服务器接收的事件完全相同,反之亦然。
它还有一个 完整的文档。
为什么?
我想在 Curio 和 Trio 中玩转 HTTP,当时它们还没有任何 HTTP 库。 所以我心想,没问题,Python 有十几个不同的 HTTP 实现, 肯定能找到一个可重用的。我没有找到,但我看到了 Cory 的号召性博客文章。 所以我想,好吧,如果我必须从头开始实现 HTTP, 至少可以确保 别人再也不需要这样做了。
我应该使用它吗?
也许吧。你应该知道这是一个非常年轻的项目。但是, 它功能齐全,拥有详尽的测试套件和完整的文档, 所以下一步是让人们尝试使用它并看看效果 :-)。 如果你这样做了,请告诉我们——至少我们会想在你做出任何不兼容的更改之前与你谈谈!
有哪些功能/限制?
大致来说,它试图成为 HTTP/1.1 规范第一章:RFC 7230:HTTP/1.1 消息语法和路由 的一个健壮、完整、非 hacky 的实现。也就是说, 它主要关注在处理网络上传入和传出的字节层面实现 HTTP, 以及与之相关的头部,并力求严格遵守规范。 它不了解 URL 路由、条件 GET、跨域 Cookie 策略或内容协商等更高级别的关注点。 但它知道如何处理分帧、keep-alive 处理中的跨版本差异以及“过时的行折叠”规则, 因此你可以将精力集中在应用程序的难点/有趣之处, 它试图支持完整的规范,以便任何有用的符合 HTTP/1.1 的应用程序都能使用 h11。
它是纯 Python 的,除了标准库之外没有其他依赖项。
它有一个测试套件,对语句和分支的覆盖率都达到了 100.0%。
目前支持 Python 3 (测试于 3.8-3.12) 和 PyPy 3。
上一个兼容 Python 2 的版本是 h11 0.11.x。
(最初它有一个用于 http-parser 的 Cython 包装器和一个使用
yield from 实现的漂亮的嵌套状态机来后处理输出。
但我不得不把它们去掉——新的解析器比旧的解析器包装器需要更少的代码行,
是用纯 Python 编写的,不使用晦涩的语言语法,并且功能更多。
真的很悲伤;那个旧的状态机确实很酷。我只需要几句话来哀悼它。)
我不知道它有多快。我还没有对其进行基准测试或性能分析, 所以它可能有一些不必要的瓶颈,而且我一直试图在简单性和鲁棒性上权衡, 而不是微优化。但在架构层面,我努力避免根本性的错误决策, 例如,我相信即使面对慢速等病态输入,所有解析算法仍然是线性的, 并且没有逐字节的循环。(我也相信它在面对任意/病态输入时能保持有限的内存使用。)
整个库大约有 800 行代码。你可以在不到一个小时的时间内阅读并理解整个内容。 到目前为止投入的精力主要是通过最小化特殊情况和随意状态操作来保持简单; 即使它现在已经相当小巧简单了,我仍然对还没有找到使其更小、更简单的方法感到恼火。 (不幸的是,HTTP 并不容易变得简单。)
API 大致上功能齐全,我不期望其大致轮廓会有太大变化, 但你必须实际记录和使用 API 才能判断其人体工程学, 所以我会期望在细节上有一些改变。
如何尝试?
$ pip install h11
$ git clone git@github.com:python-hyper/h11
$ cd h11/examples
$ python basic-client.py然后在此基础上进行。
许可证?
MIT
行为准则?
我们要求贡献者在所有项目空间中遵守我们的行为准则。