psr-7_从HTTP消息到PSR-7:它的全部含义是什么?

本文介绍了PHP-FIG批准的PSR-7:HTTP消息接口规范,该规范将HTTP消息划分为7个接口。内容涵盖了HTTP消息的基本组成部分,如请求行、头部和主体,以及在不同环境下的应用。文章讨论了PSR-7如何处理HTTP请求和响应,包括文件上传和流处理,同时提到了不变性对象的概念。此外,文章还探讨了PSR-7在实际使用中的挑战,如中间件的实现,并列举了如Symfony、Zend Framework、Slim和Guzzle等库对PSR-7的支持情况。
摘要由CSDN通过智能技术生成

psr-7

This article was peer reviewed by Andrew Carter. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

本文由Andrew Carter同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!

The PHP Framework Interoperability Group (PHP-FIG) has relatively recently approved another proposal, the PSR-7: HTTP Messages Interface. The document crystallizes HTTP messages into 7 interfaces which a PHP library should implement if they subscribe to the specification. In PSR-7 By Example, Matthew Weier O’Phinney, editor of the PSR, gives an interesting overview of the specification. So what is it?

PHP框架互操作性小组(PHP-FIG)较近期批准了另一项建议,即PSR-7:HTTP消息接口 。 该文档将HTTP消息具体化为7个接口,如果PHP订阅该规范,则PHP库应该实现这些接口。 在《 PSR-7示例》中 ,PSR的编辑Matthew Weier O'Phinney对该规范进行了有趣的概述。 那是什么

Image of digital question mark, indicating confusion and pending explanation

If you type bbc.co.uk in your browser, you go straight to the homepage of the BBC, but a number of things might have taken place between the time the browser sent an HTTP request to the server and it getting a response back.

如果在浏览器中键入bbc.co.uk ,则直接转到BBC的主页,但是在浏览器向服务器发送HTTP请求到它返回响应之间可能发生了很多事情。

Here’s a sample raw request.

这是原始请求示例。

GET / HTTP/1.1
Host: bbc.co.uk
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept: */*
Referer:

It’s always made up of a request line (GET / HTTP/1.1), a number of header field lines listed as <key>: value, a single empty line and an optional body for any data payload (for example query parameters or post data).

它始终由请求行(GET / HTTP / 1.1),列为<key>: value的多个标头字段行,单个空行和任何数据有效负载(例如查询参数或后置数据)的可选主体组成)。

The blank line after the zero or more header lines must be a CRLF by itself. This means 2 characters – an ASCII 13 (Carriage Return), followed by ASCII 10 (Line Feed) or \r\n.

零个或多个标题行之后的空白行本身必须是CRLF。 这意味着2个字符-ASCII 13(回车),然后是ASCII 10(换行)或\r\n

Let’s send this request from the command line via curl and see the response:

让我们通过curl从命令行发送此请求,并查看响应:

curl -i -H "Host: bbc.co.uk" -H "User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" -H "Accept: */*" -X GET http://bbc.co.uk

HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Date: Sun, 02 Oct 2016 20:49:42 GMT
Location: http://www.bbc.co.uk/
Connection: Keep-Alive
Content-Length: 0

Moved? There was a redirect. Then, let’s follow the trail and make a request to http://www.bbc.co.uk/ instead:

感动吗 有重定向。 然后,让我们按照路径进行操作,然后向http://www.bbc.co.uk/发出请求:

curl -i -H "Host: www.bbc.co.uk" -H "User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" -H "Accept: */*" -X GET http://www.bbc.co.uk | less

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
ETag: W/"29c44-MXo+6t7MoPRad358MSWqwA"
X-Frame-Options: SAMEORIGIN
x-origin-route: xrt-ext
Content-Length: 171076
Date: Sun, 02 Oct 2016 20:54:27 GMT
Connection: keep-alive
Set-Cookie: BBC-UID=15c73fe11704a0731344da5ec13869204c1a22a0c7b444d60a708762e631ac0c0Mozilla/5.0%20(compatible%3b%20MSIE%209.0%3b%20Windows%20NT%206.1%3b%20Trident/5.0); expires=Thu, 01-Oct-20 20:54:27 GMT; path=/; domain=.bbc.co.uk
X-Cache-Action: HIT
X-Cache-Hits: 1223
X-Cache-Age: 55
Cache-Control: private, max-age=0, must-revalidate
Vary: Accept-Encoding, X-CDN, X-BBC-Edge-Scheme

<!DOCTYPE html>
<!--[if lte IE 9]>
  <html lang="en-GB" class="no-js no-flexbox no-flexboxlegacy">
<![endif]-->
<!--[if gt IE 9]><!-->
  <html lang="en-GB" class="no-js">
<!--<![endif]-->
<head>

That’s more like it. The first line, HTTP/1.1 200 OK, is the status line. Then we have headers, in a similar pattern to requests – <key>: value, an empty line, and the response body. Note: We passed the output through less so that we can see the first part of the response.

这还差不多。 第一行HTTP/1.1 200 OK是状态行。 然后,我们具有与请求类似的头文件- <key>: value ,空行和响应主体。 注意:我们将输出传递给less以便我们可以看到响应的第一部分。

Requests and responses can be broken down into a message line, a number of header lines and body lines. The commonalities can be abstracted in an interface (MessageInterface) which the request (RequestInterface) and response (ResponseInterface) can extend with their distinct flavor of HTTP message.

请求和响应可以分为消息行,许多标题行和正文行。 可以在接口( MessageInterface )中抽象这些共性,请求( RequestInterface )和响应( ResponseInterface )可以使用其独特的HTTP消息RequestInterface进行扩展。

PHP doesn’t only run within a web environment, and web requests might have originated from APIs. The ServerRequestInterface was designed to take care of other types of HTTP requests.

PHP不仅在网络环境中运行,而且网络请求可能源自API。 ServerRequestInterface旨在处理其他类型的HTTP请求。

The other three interfaces are a further abstraction of specific aspects in messages. Looking back at the request message line:

其他三个接口是消息中特定方面的进一步抽象。 回顾请求消息行:

GET / HTTP/1.1

This comprises:

这包括:

  • METHOD: Although RFC 2616 defines safe and idempotent types of methods, for general applications, it’s sufficient to identify them by name – GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD and TRACE. CONNECT is reserved for use with a proxy that can dynamically switch to being a tunnel e.g. SSL tunneling.

    方法:尽管RFC 2616定义了安全和幂等的方法类型,但对于一般应用程序而言,通过名称来识别它们就足够了-GET,POST,PUT,PATCH,DELETE,OPTIONS,HEAD和TRACE。 CONNECT保留供与代理一起使用,该代理可以动态切换为隧道,例如SSL隧道。

  • TARGET: This is the URI or our request target, and things get a bit interesting here as we can have:

    目标:这是URI或我们的请求目标,在这里,事情变得有些有趣,因为我们可以拥有:

    • origin-form – path and query string of the URI. The query string may or may not be present.

      origin-form – URI的路径和查询字符串。 查询字符串可能存在也可能不存在。
    • absolute-form – an absolute URI.

      绝对形式–绝对URI。
    • authority-form – the authority part of a URI, made up of a maximum of 3 parts – user-info (optional), host and port (optional). The user-info may require a password too – user:password. We end up with a pattern of user:password@host:port. The user-info may also have require an

      权威形式– URI的权威部分,最多由3部分组成–用户信息(可选),主机和端口(可选)。 用户信息可能也需要密码– user:password。 我们以user:password @ host:port的模式结束。 用户信息可能还需要一个
    • asterisk-form – just the string, *

      星号形式–仅是字符串,*

    We end up with scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]. This part of the request message was abstracted to the UriInterface.

    我们以以下scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]结束scheme:[//[user:password@]host[:port]][/]path[?query][#fragment] 。 请求消息的这一部分被抽象到UriInterface

  • VERSION: There’s limited choice here as HTTP/1.1 is the current version. Prior to that, we had HTTP/1.0, and the next draft version is HTTP/2.0

    版本:这里的选择有限,因为HTTP / 1.1是当前版本。 在此之前,我们使用HTTP / 1.0,下一个草案版本是HTTP / 2.0

Also, file uploads required special attention. In non-SAPI environments, the $_FILES environment variable is empty and in some situations such as non-POST requests, $_FILES isn’t populated at all. The UploadedFileInterface was designed to allow for a more consistent interaction with files.

另外,文件上传需要特别注意。 在非SAPI环境中, $_FILES环境变量为空,在某些情况下(例如非POST请求),根本不会填充$_FILESUploadedFileInterface旨在允许与文件进行更一致的交互。

The message (request or response) needs to be able to handle large data efficiently for both client and server. PHP has had streams built in since 4.3.0. The StreamInterface part of PSR-7 provides a wrapper around common operations and serialization of an entire stream to a string.

消息(请求或响应)需要能够有效地为客户端和服务器处理大量数据。 从4.3.0开始,PHP内置了流。 PSR-7的StreamInterface部分提供了通用操作以及将整个流序列化为字符串的包装。

alt

挑战性 (Challenges)

The path to PSR-7 was paved with strong debate and differing opinions at every step of the way.

通往PSR-7的道路在每个步骤中都经过激烈的辩论和不同的意见。

  • Immutable objects – The immutability or mutability of objects was one of the most hotly-debated points, and PSR-7 eventually settled for this:

    不可变的对象–对象的不可变性或可变性是最热门的争论点之一,PSR-7最终为此解决了:

    The proposal models messages and URIs as value objects.

    该提案将消息和URI建模为值对象。

    Messages are values where the identity is the aggregate of all parts of the message; a change to any aspect of the message is essentially a new message. This is the very definition of a value object. The practice by which changes result in a new instance is termed immutability, and is a feature designed to ensure the integrity of a given value.

    消息是值,其中身份是​​消息所有部分的总和; 对消息的任何方面进行的更改本质上都是新消息。 这就是值对象的定义。 更改导致新实例的做法称为不变性,并且是旨在确保给定值完整性的功能。

    What this means is that each time you make any change to a message object, you end up with a new copy. The complexity of URI, headers and streams require an assurance that a full adoption of immutability by all collaborators offered to the designers of the interfaces.

    这意味着每次对消息对象进行任何更改时,都会得到一个新副本。 URI,标头和流的复杂性要求确保提供给接口设计人员的所有协作者都完全采用不变性。

    With immutability, any state change you make requires you to assign the result.

    有了不变性,您所做的任何状态更改都需要您分配结果。

    $request = $request->setHeader('Cache-Control', 'public');

    Any method that changes the state of the current message returns an instance of it with the changes made. As long as a result assignment is made, you can chain any number of changes in a fluent-like syntax.

    更改当前消息状态的任何方法都将返回所做更改的实例。 只要进行了结果分配,就可以使用流利的语法链接任意数量的更改。

    $request = $request
            ->setHeader('Cache-Control', 'public')
            ->addHeader('Cache-Control', 'max-age=18600')
            ->setStatus(200);

    The methods having the prefix “with” must conform to the immutability requirement. A concern is that supporting mutability in one of the message interfaces means enforcing it across all the other interfaces.

    前缀为“ with”的方法必须符合不变性要求。 一个问题是,在消息接口之一中支持可变性意味着要在所有其他接口上强制实现可变性。

    On the other hand, it has been highlighted that PSR-7 Objects Are Not Immutable as they are generally thought to be. It’s worthy of note that similar HTTP object implementations in Ruby and Node are mutable by design. So, PHP is in good company.

    另一方面,已经强调了PSR-7对象不是通常认为的不可变的 。 值得注意的是,Ruby和Node中类似的HTTP对象实现在设计上是可变的。 因此,PHP表现出色。

  • Nomenclature – These objects are designed as interfaces. Isn’t calling it MessageInterface superfluous? A method signature taking a request and response ends up being too long. Compare the following:

    命名法–这些对象被设计为接口。 这不是MessageInterface多余的吗? 接受请求和响应的方法签名最终太长。 比较以下内容:

    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) : ResponseInterface
    {
    }
    public function __invoke(ServerRequest $request, Response $response, callable $next) : Response
    {
    }

    Aliasing is the suggested solution for those who prefer to drop the Interface suffixes.

    对于那些喜欢删除接口后缀的用户,建议使用别名解决方案。

  • Middleware – We’ve got the message interfaces which are like the ingredients for making a cake, perfectly measured out. I want a cake to consume but I don’t know how to bake. How about a recipe? PSR-7 only prescribes a standard for the definition of a request and response. How do we move from request to response? That “middleman” that does the leg work between the request and response is called middleware.

    中间件–我们有消息接口,就像制作蛋糕的原料一样,经过精心设计。 我想吃一块蛋糕,但我不知道怎么烤。 食谱怎么样? PSR-7仅规定了定义请求和响应的标准。 我们如何从请求转移到响应? 在请求和响应之间起作用的那个“中间人”称为中间件。

    The next step would be a unification of how to plumb PSR-7 interfaces so that applications and frameworks that conform to them can be completely swappable. This part of the debate which borders on providing a template for an interoperable implementation of PSR-7, has been moved to the separate PSR-15: HTTP Middlewares.

    下一步将是如何使PSR-7接口垂直化,以便符合它们的应用程序和框架可以完全交换。 辩论的这一部分与为PSR-7的互操作实现提供模板有关,已经转移到单独的PSR-15:HTTP中间件。

用法 (Usage)

A number of libraries and frameworks have added support for PSR-7 in different ways.

许多库和框架以不同的方式增加了对PSR-7的支持。

  1. Symfony – The HttpFoundation Component is one of the most popular OOP abstractions of the HTTP specification prior to PHP-FIG. With the emergence of PSR-7, Symfony opted for a PSR-7 Bridge which converts HttpFoundation objects from and to objects which implement PSR-7 message interfaces.

    Symfony – HttpFoundation组件是PHP-FIG之前HTTP规范中最流行的OOP抽象之一。 随着PSR-7的出现,Symfony选择了一种PSR-7桥HttpFoundationHttpFoundation对象与实现PSR-7消息接口的对象相互转换。

  2. Zend Framework (ZF) – They came up with a Composer package, zendframework/zend-diactoros, of implementations of the HTTP message interfaces, not surprising as the editor of PSR-7 is the ZF Project Lead. Diactoros goes a step further by including a server that is similar to the one provided by http.Server in NodeJS.

    Zend Framework(ZF)–他们提出了HTTP消息接口实现的Composer软件包zendframework/zend-diactoros ,这并不奇怪,因为PSR-7的编辑者是ZF项目负责人。 Diactoros通过在NodeJS中包含与http.Server提供的服务器相似的服务器,进一步向前迈进了一步。

  3. Slim – PSR 7 and Value Objects describes a flexible approach that makes Slim accept any implementation of PSR-7. That is, if the one provided by Slim doesn’t suffice.

    Slim – PSR 7和Value Objects描述了一种灵活的方法,可使Slim接受PSR-7的任何实现。 也就是说,如果Slim提供的功能还不够。

  4. Guzzle – Being an HTTP client library, PSR-7 is of great relevance to this library. They built the guzzlehttp/psr7 Composer package, a message implementation of PSR-7, which they rely on. Guzzle and PSR-7 gives an excellent overview of their take on the specification.

    Guzzle –作为HTTP客户端库,PSR-7与该库非常相关。 他们构建了guzzlehttp/psr7 Composer软件包,这是他们依赖的PSR-7的消息实现。 Guzzle和PSR-7很好地概述了它们对规范的看法。

  5. Aura – They’ve included Aura.Router, a web router implementation of PSR-7 in their collection of independent library packages. All router objects are managed by a RouterContainer from which you retrieve an instance of a Map object. Each method of this Map object may accept an HTTP message interface as one of its arguments.

    Aura –他们在独立库包的集合中包含了Pura -7的Web路由器实现Aura.Router 。 所有路由器对象都由一个RouterContainer管理,您可以从中检索Map对象的实例。 此Map对象的每种方法都可以接受HTTP消息接口作为其参数之一。

  6. HTTPlug – A package of interfaces that allow library and application developers to create HTTP clients that are fully compatible with PSR-7. The HttpClient sends a PSR-7 Request and returns a PSR-7 response. See Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug for a practical way of using this package.

    HTTPlug –一组接口,允许库和应用程序开发人员创建与PSR-7完全兼容的HTTP客户端。 HttpClient发送PSR-7请求并返回PSR-7响应。 有关使用此软件包的实用方法,请参阅使用PHP-HTTP和HTTPlug摆脱Guzzle5

Packagist has a list of PSR-7 implementations with a wide range of popularity or acceptance. However, a developer still has the following usage options:

Packagist提供了一系列PSR-7实施方案,并受到广泛的欢迎或接受。 但是,开发人员仍然具有以下使用选项:

  1. Direct – As the specification states, while Psr\Http\Message\MessageInterface MAY be implemented directly, implementors SHOULD implement Psr\Http\Message\RequestInterface and Psr\Http\Message\ResponseInterface. The simplest way is to install the package with Composer.

    直接–规范指出,虽然可以直接实现Psr \ Http \ Message \ MessageInterface,但是实现者应该实现Psr \ Http \ Message \ RequestInterface和Psr \ Http \ Message \ ResponseInterface。 最简单的方法是使用Composer安装软件包。

    composer require psr/http-message
  2. Indirect – The interfaces are used indirectly through an adapter. For example, PSR-7 support in Symfony is through the PSR HTTP Message Bridge, a library designed to convert Symfony Request and Response objects into objects that are fully compatible with PSR-7, and from PSR-7 back to Symfony objects.

    间接–接口通过适配器间接使用。 例如,Symfony对PSR-7的支持是通过PSR HTTP消息桥实现的,该库旨在将Symfony RequestResponse对象转换为与PSR-7完全兼容的对象,并将其从PSR-7转换回Symfony对象。

  3. Partial – You might be interested in the more generic interfaces such as StreamInterface, UriInterface and UploadedFileInterface. Nothing stops you from implementing them in a non-HTTP messages context. The package is available on Packagist and Composer is your friend.

    部分–您可能对更通用的接口(例如StreamInterface,UriInterface和UploadedFileInterface)感兴趣。 没有什么可以阻止您在非HTTP消息上下文中实现它们。 该软件包可在Packagist上找到,Composer是您的朋友。

结论 (Conclusion)

The PHP community should be applauded for coming together on the fundamental principle of how we interact with and manage HTTP requests and responses. PSR-15 transcends this and the intensity of the debate surrounding middlewares will not go away very soon, neither should the draft be expected to be accepted quickly. In the meantime, PSR-7 is there for all to embrace.

应该为PHP社区在我们如何与HTTP请求和响应交互以及如何管理它们的基本原理上走到一起而受到赞扬。 PSR-15超越了这一点,围绕中间件的争论不会很快消失,也不应期望草案能被Swift接受。 同时,PSR-7可供所有人使用。

What do you think about PSR-7? Do you use it and subscribe to it, or do you feel like it’s just a layer of complication? We’d like to hear from you!

您如何看待PSR-7? 您使用它并订阅它,还是觉得它只是复杂的一层? 我们希望收到您的来信!

翻译自: https://www.sitepoint.com/from-http-messages-to-psr-7-whats-it-all-about/

psr-7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>