PSR 18 HTTP 客户端 - 说明文档 「起草中」
概览
HTTP 请求和响应是 Web 编程中的两个基本对象
所有与外部 API 通信的客户端都使用某种形式的 HTTP 客户端
许多库被耦合到一个特定的客户端或自己实现一个客户端和(或)适配器层
这导致错误的库设计,版本冲突或与库域无关的太多代码
初衷
感谢 PSR-7,因为 PSR-7 让我们知道了 HTTP 请求和响应是怎么样的
但 PSR-7 并没有规定一个请求应该如何被发送和如何接收一个响应
一个通用的 HTTP 客户端接口将允许库与特定的实现 ( 如 Guzzle ) 分离
内容
特性
- 一个发送 PSR-7 消息的通用接口规范
非目标
- 支持异步 HTTP 请求留给将来的另一个 PSR
- 此篇 PSR 没有定义如何配置 HTTP 客户端,它仅指定了默认的行为
- 我们的目标是中立使用遵循 PSR-15 规范的中间件
异步 HTTP 请求
此 PSR 没有包含异步请求的原因是缺少 Promises 的通用标准,而 HTTP 客户端 PSR 又 不能 定义自己的 promises
在撰写这篇 PSR 时,还未出现最终的 Promises PSR
一定 promise PSR 被接受,那么就可以在单独的 PSR 中定义用于异步请求的单独接口
异步请求的方法签名与同步请求的方法签名不同,因为异步调用的返回类型将是 Promise
因此,我们向前兼容,客户端将能够实现一个或两个接口,因为它们是合理的
标准制定过程
默认行为
此 PSR 的目的是为类库的开发人员提供具有明确定义的行为的 HTTP 客户端
类库应该能够使用任何兼容的客户端而无需特殊的代码来处理客户端实现细节 ( 里氏替换原则 )
此 PSR 不会试图限制或定义如何配置 HTTP 客户端
一种代替的方案是将配置传递给客户端,但这种方案有一些缺点:
- 可配置项必须在 PSR 中定义
- 所有的客户端必须支持 PSR 中定义的配置项
- 如果没有传递任何配置项给客户端,则客户端的行为是不可预知的
异常
异常 NetworkException
和 RequestException
彼此非常相似
但最后的选择是不让它们有继承关系,因为在领域模型里,继承没有任何实际意义。 一个 RequestException
并不是 NetworkException
此前曾讨论过是否需要扩展 RequestAwareException
或 ResponseAwareException
接口,但这显然是不明智的,人们不应该关注具体的异常并且处理它们
虽然可以从更细的粒度去定义异常,例如可以定义 TimeOutException
和 HostNotFoundException
作为 NetworkException
的子类型。 但最后的选择是不这么做,因为处理异常的类库大多时候并不关心这两个异常之间的不同之处
当响应状态吗为 4xx 和 5xx 时抛出异常
最初的想法是允许配置客户端收到 HTTP 状态码为 4xx 和 5xx 的响应时抛出异常
但这种想法被放弃的原因是因为客户端需要分两次检查 4xx 和 5xx 的响应,第一次用来检查响应状态吗,第二次用于捕获可能抛出的异常
为了使规范更加稳定,决定 HTTP 客户端永远不会为 4xx 和 5xx 的响应抛出异常
撰写背景
此 PSR 由 php-http team 于 2015 年发起和创建,他们首先创建了 PHPPlug 作为一个 HTTP 客户端的通用接口,希望通过抽象让第三方库可以用来不依赖特定的 HTTP 客户端实现,如 Guzzle 5,Guzzle 6 或 Buzz
2016 年 1 月,发布了第一个稳定的版本,此后该项目得到广泛采用
未来两年内下载量将超过 300 万次,现在是时候将这种 「事实」 上的标准转换为真正的 PSR
工作组
5.1 撰稿者
- Tobias Nyholm
5.2 发起者
- Sara Golemon
5.3 参与人员
- Simon Asika (Windwalker)
- David Buchmann (HTTPlug)
- David De Boer (HTTPlug)
- Sara Golemon (Sponsor)
- Jermey Lindstrom (Guzzle)
- Christian Lück (Buzz react)
- Tobias Nyholm (Editor)
- Matthew O'Phinney (Zend)
- Mark Sagi-Kazar (Guzzle)
- Joel Wurtz (HTTPlug)