HTTP消息接口
此文檔描述了 RFC 7230 和
RFC 7231 HTTP 消息傳遞的接口,還有 RFC 3986 里對 HTTP 消息的 URIs 使用。
HTTP 消息是 Web 技術(shù)發(fā)展的基礎(chǔ)。瀏覽器或 HTTP 客戶端如 curl 生成發(fā)送 HTTP 請求消息到 Web 服務(wù)器,Web 服務(wù)器響應(yīng) HTTP 請求。服務(wù)端的代碼接受 HTTP 請求消息后返回 HTTP 響應(yīng)消息。
通常 HTTP 消息對于終端用戶來說是不可見的,但是作為 Web 開發(fā)者,我們需要知道 HTTP 機(jī)制,如何發(fā)起、構(gòu)建、取用還有操縱 HTTP 消息,知道這些原理,以助我們剛好的完成開發(fā)任務(wù),無論這個任務(wù)是發(fā)起一個 HTTP 請求,或者處理傳入的請求。
每一個 HTTP 請求都有專屬的格式:
POST /path HTTP/1.1
Host: example.com
foo=bar&baz=bat
按照順序,第一行的各個字段意義為: HTTP 請求方法、請求的目標(biāo)地址(通常是一個絕對路徑的 URI 或
者路徑),HTTP 協(xié)議。
接下來是 HTTP 頭信息,在這個例子中:目的主機(jī)。接下來是空行,然后是消息內(nèi)容。
HTTP 返回消息有類似的結(jié)構(gòu):
HTTP/1.1 200 OK
Content-Type: text/plain
這是返回的消息內(nèi)容
按照順序,第一行為狀態(tài)行,包括 HTTP 協(xié)議版本,HTTP 狀態(tài)碼,描述文本。
和 HTTP 請求類似的,接下來是 HTTP 頭信息,在這個例子中:內(nèi)容類型。接下來是空行,然后是消息內(nèi)容。
此文檔探討的是 HTTP 請求消息接口,和構(gòu)建 HTTP 消息需要的元素數(shù)據(jù)定義。
參考資料
關(guān)于「能愿動詞」的使用
為了避免歧義,文檔大量使用了「能愿動詞」,對應(yīng)的解釋如下:
-
必須 (MUST):絕對,嚴(yán)格遵循,請照做,無條件遵守; -
一定不可 (MUST NOT):禁令,嚴(yán)令禁止; -
應(yīng)該 (SHOULD):強(qiáng)烈建議這樣做,但是不強(qiáng)求; -
不該 (SHOULD NOT):強(qiáng)烈不建議這樣做,但是不強(qiáng)求; -
可以 (MAY)和可選 (OPTIONAL):選擇性高一點(diǎn),在這個文檔內(nèi),此詞語使用較少;
參見:RFC 2119
1. 規(guī)范詳情
1.1 消息
一個 HTTP 消息,指定是一個從客戶端發(fā)往服務(wù)器端的請求,或者是服務(wù)器端返回客戶端的響應(yīng)。對應(yīng)的兩
個消息接口:Psr\Http\Message\RequestInterface 和 Psr\Http\Message\ResponseInterface。
這個兩個接口都繼承于 Psr\Http\Message\MessageInterface。雖然你 可以 實(shí)現(xiàn)
Psr\Http\Message\MessageInterface 接口,但是,最重要的,你 必須 實(shí)現(xiàn)
Psr\Http\Message\RequestInterface 和 Psr\Http\Message\ResponseInterface
接口。
從現(xiàn)在開始,為了行文的方便,我們提到這些接口的時候,都會把命名空間 Psr\Http\Message 去除掉。
1.2 HTTP 頭信息
大小寫不敏感的字段名字
HTTP 消息包含大小寫不敏感頭信息。使用 MessageInterface 接口來設(shè)置和獲取頭信息,大小寫
不敏感的定義在于,如果你設(shè)置了一個 Foo 的頭信息,foo 的值會被重寫,你也可以通過 foo 來
拿到 FoO 頭對應(yīng)的值。
$message = $message->withHeader('foo', 'bar');
echo $message->getHeaderLine('foo');
// 輸出: bar
echo $message->getHeaderLine('FOO');
// 輸出: bar
$message = $message->withHeader('fOO', 'baz');
echo $message->getHeaderLine('foo');
// 輸出: baz
雖然頭信息可以用大小寫不敏感的方式取出,但是接口實(shí)現(xiàn)類 必須 保持自己的大小寫規(guī)范,特別是用 getHeaders() 方法輸出的內(nèi)容。
因為一些非標(biāo)準(zhǔn)的 HTTP 應(yīng)用程序,可能會依賴于大小寫敏感的頭信息,所有在此我們把主宰 HTTP 大小寫的權(quán)利開放出來,以適用不同的場景。
對應(yīng)多條數(shù)組的頭信息
為了適用一個 HTTP 「鍵」可以對應(yīng)多條數(shù)據(jù)的情況,我們使用字符串配合數(shù)組來實(shí)現(xiàn),你可以從一個 MessageInterface 取出數(shù)組或字符串,使用 getHeaderLine($name) 方法可以獲取通過逗號分割的不區(qū)分大小寫的字符串形式的所有值。也可以通過 getHeader($name) 獲取數(shù)組形式頭信息的所有值。
$message = $message
->withHeader('foo', 'bar')
->withAddedHeader('foo', 'baz');
$header = $message->getHeaderLine('foo');
// $header 包含: 'bar, baz'
$header = $message->getHeader('foo');
// ['bar', 'baz']
注意:并不是所有的頭信息都可以適用逗號分割(例如 Set-Cookie),當(dāng)處理這種頭信息時候, MessageInterace 的繼承類 應(yīng)該 使用 getHeader($name) 方法來獲取這種多值的情況。
主機(jī)信息
在請求中,Host 頭信息通常和 URI 的 host 信息,還有建立起 TCP 連接使用的 Host 信息一致。
然而,HTTP 標(biāo)準(zhǔn)規(guī)范允許主機(jī) host 信息與其他兩個不一樣。
在構(gòu)建請求的時候,如果 host 頭信息未提供的話,實(shí)現(xiàn)類庫 必須 嘗試著從 URI 中提取 host
信息。
RequestInterface::withUri() 會默認(rèn)的,從傳參的 UriInterface 實(shí)例中提取 host ,
并替代請求中原有的 host 信息。
你可以提供傳參第二個參數(shù)為 true 來保證返回的消息實(shí)例中,原有的 host 頭信息不會被替代掉。
以下表格說明了當(dāng) withUri() 的第二個參數(shù)被設(shè)置為 true 的時,返回的消息實(shí)例中調(diào)用
getHeaderLine('Host') 方法會返回的內(nèi)容:
| 請求 Host 頭信息1 | 請求 URI 中的 Host 信息2 | 傳參進(jìn)去 URI 的 Host 3 | 結(jié)果 |
|---|---|---|---|
| '' | '' | '' | '' |
| '' | foo.com | '' | foo.com |
| '' | foo.com | bar.com | foo.com |
| foo.com | '' | bar.com | foo.com |
| foo.com | bar.com | baz.com | foo.com |
- <sup id="rhh">1 當(dāng)前請求的
Host頭信息。 - <sup id="rhc">2 當(dāng)前請求
URI中的Host信息。 - <sup id="uhc">3 通過
withUri()傳參進(jìn)入的 URI 中的host信息。
1.3 數(shù)據(jù)流
HTTP 消息包含開始的一行、頭信息、還有消息的內(nèi)容。HTTP 的消息內(nèi)容有時候可以很小,有時候確是
非常巨大。嘗試使用字符串的形式來展示消息內(nèi)容,會消耗大量的內(nèi)存,使用數(shù)據(jù)流的形式來讀取消息
可以解決此問題。StreamInterface 接口用來隱藏具體的數(shù)據(jù)流讀寫實(shí)現(xiàn)。在一些情況下,消息
類型的讀取方式為字符串是能容許的,可以使用 php://memory 或者 php://temp。
StreamInterface 暴露出來幾個接口,這些接口允許你讀取、寫入,還有高效的遍歷內(nèi)容。
數(shù)據(jù)流使用這個三個接口來闡明對他們的操作能力:isReadable()、isWritable() 和
isSeekable()。這些方法可以讓數(shù)據(jù)流的操作者得知數(shù)據(jù)流能否能提供他們想要的功能。
每一個數(shù)據(jù)流的實(shí)例,都會有多種功能:可以只讀、可以只寫、可以讀和寫,可以隨機(jī)讀取,可以按順序讀取等。
最終,StreamInterface 定義了一個 __toString() 的方法,用來一次性以字符串的形式輸出
所有消息內(nèi)容。
與請求和響應(yīng)的接口不同的是,StreamInterface 并不強(qiáng)調(diào)不可修改性。因為在 PHP 的實(shí)現(xiàn)內(nèi),基
本上沒有辦法保證不可修改性,因為指針的指向,內(nèi)容的變更等狀態(tài),都是不可控的。作為讀取者,可以
調(diào)用只讀的方法來返回數(shù)據(jù)流,以最大程度上保證數(shù)據(jù)流的不可修改性。使用者要時刻明確的知道數(shù)據(jù)
流的可修改性,建議把數(shù)據(jù)流附加到消息實(shí)例中,來強(qiáng)迫不可修改的特性。
1.4 請求目標(biāo)和 URI
翻譯到此先告一段落,此規(guī)范篇幅有點(diǎn)過長,需要消耗的時間挺長的,暫且翻譯至此,他日再戰(zhàn)。
Per RFC 7230, request messages contain a "request-target" as the second segment
of the request line. The request target can be one of the following forms:
-
origin-form, which consists of the path, and, if present, the query
string; this is often referred to as a relative URL. Messages as transmitted
over TCP typically are of origin-form; scheme and authority data are usually
only present via CGI variables. -
absolute-form, which consists of the scheme, authority
("[user-info@]host[:port]", where items in brackets are optional), path (if
present), query string (if present), and fragment (if present). This is often
referred to as an absolute URI, and is the only form to specify a URI as
detailed in RFC 3986. This form is commonly used when making requests to
HTTP proxies. -
authority-form, which consists of the authority only. This is typically
used in CONNECT requests only, to establish a connection between an HTTP
client and a proxy server. -
asterisk-form, which consists solely of the string
*, and which is used
with the OPTIONS method to determine the general capabilities of a web server.
Aside from these request-targets, there is often an 'effective URL' which is
separate from the request target. The effective URL is not transmitted within
an HTTP message, but it is used to determine the protocol (http/https), port
and hostname for making the request.
The effective URL is represented by UriInterface. UriInterface models HTTP
and HTTPS URIs as specified in RFC 3986 (the primary use case). The interface
provides methods for interacting with the various URI parts, which will obviate
the need for repeated parsing of the URI. It also specifies a __toString()
method for casting the modeled URI to its string representation.
When retrieving the request-target with getRequestTarget(), by default this
method will use the URI object and extract all the necessary components to
construct the origin-form. The origin-form is by far the most common
request-target.
If it's desired by an end-user to use one of the other three forms, or if the
user wants to explicitly override the request-target, it is possible to do so
with withRequestTarget().
Calling this method does not affect the URI, as it is returned from getUri().
For example, a user may want to make an asterisk-form request to a server:
$request = $request
->withMethod('OPTIONS')
->withRequestTarget('*')
->withUri(new Uri('https://example.org/'));
This example may ultimately result in an HTTP request that looks like this:
OPTIONS * HTTP/1.1
But the HTTP client will be able to use the effective URL (from getUri()),
to determine the protocol, hostname and TCP port.
An HTTP client MUST ignore the values of Uri::getPath() and Uri::getQuery(),
and instead use the value returned by getRequestTarget(), which defaults
to concatenating these two values.
Clients that choose to not implement 1 or more of the 4 request-target forms,
MUST still use getRequestTarget(). These clients MUST reject request-targets
they do not support, and MUST NOT fall back on the values from getUri().
RequestInterface provides methods for retrieving the request-target or
creating a new instance with the provided request-target. By default, if no
request-target is specifically composed in the instance, getRequestTarget()
will return the origin-form of the composed URI (or "/" if no URI is composed).
withRequestTarget($requestTarget) creates a new instance with the
specified request target, and thus allows developers to create request messages
that represent the other three request-target forms (absolute-form,
authority-form, and asterisk-form). When used, the composed URI instance can
still be of use, particularly in clients, where it may be used to create the
connection to the server.
1.5 Server-side Requests
RequestInterface provides the general representation of an HTTP request
message. However, server-side requests need additional treatment, due to the
nature of the server-side environment. Server-side processing needs to take into
account Common Gateway Interface (CGI), and, more specifically, PHP's
abstraction and extension of CGI via its Server APIs (SAPI). PHP has provided
simplification around input marshaling via superglobals such as:
-
$_COOKIE, which deserializes and provides simplified access for HTTP
cookies. -
$_GET, which deserializes and provides simplified access for query string
arguments. -
$_POST, which deserializes and provides simplified access for urlencoded
parameters submitted via HTTP POST; generically, it can be considered the
results of parsing the message body. -
$_FILES, which provides serialized metadata around file uploads. -
$_SERVER, which provides access to CGI/SAPI environment variables, which
commonly include the request method, the request scheme, the request URI, and
headers.
ServerRequestInterface extends RequestInterface to provide an abstraction
around these various superglobals. This practice helps reduce coupling to the
superglobals by consumers, and encourages and promotes the ability to test
request consumers.
The server request provides one additional property, "attributes", to allow
consumers the ability to introspect, decompose, and match the request against
application-specific rules (such as path matching, scheme matching, host
matching, etc.). As such, the server request can also provide messaging between
multiple request consumers.
1.6 Uploaded files
ServerRequestInterface specifies a method for retrieving a tree of upload
files in a normalized structure, with each leaf an instance of
UploadedFileInterface.
The $_FILES superglobal has some well-known problems when dealing with arrays
of file inputs. As an example, if you have a form that submits an array of files
— e.g., the input name "files", submitting files[0] and files[1] — PHP will
represent this as:
array(
'files' => array(
'name' => array(
0 => 'file0.txt',
1 => 'file1.html',
),
'type' => array(
0 => 'text/plain',
1 => 'text/html',
),
/* etc. */
),
)
instead of the expected:
array(
'files' => array(
0 => array(
'name' => 'file0.txt',
'type' => 'text/plain',
/* etc. */
),
1 => array(
'name' => 'file1.html',
'type' => 'text/html',
/* etc. */
),
),
)
The result is that consumers need to know this language implementation detail,
and write code for gathering the data for a given upload.
Additionally, scenarios exist where $_FILES is not populated when file uploads
occur:
- When the HTTP method is not
POST. - When unit testing.
- When operating under a non-SAPI environment, such as ReactPHP.
In such cases, the data will need to be seeded differently. As examples:
- A process might parse the message body to discover the file uploads. In such
cases, the implementation may choose not to write the file uploads to the
file system, but instead wrap them in a stream in order to reduce memory,
I/O, and storage overhead. - In unit testing scenarios, developers need to be able to stub and/or mock the
file upload metadata in order to validate and verify different scenarios.
getUploadedFiles() provides the normalized structure for consumers.
Implementations are expected to:
- Aggregate all information for a given file upload, and use it to populate a
Psr\Http\Message\UploadedFileInterfaceinstance. - Re-create the submitted tree structure, with each leaf being the appropriate
Psr\Http\Message\UploadedFileInterfaceinstance for the given location in
the tree.
The tree structure referenced should mimic the naming structure in which files
were submitted.
In the simplest example, this might be a single named form element submitted as:
<input type="file" name="avatar" />
In this case, the structure in $_FILES would look like:
array(
'avatar' => array(
'tmp_name' => 'phpUxcOty',
'name' => 'my-avatar.png',
'size' => 90996,
'type' => 'image/png',
'error' => 0,
),
)
The normalized form returned by getUploadedFiles() would be:
array(
'avatar' => /* UploadedFileInterface instance */
)
In the case of an input using array notation for the name:
<input type="file" name="my-form[details][avatar]" />
$_FILES ends up looking like this:
array(
'my-form' => array(
'details' => array(
'avatar' => array(
'tmp_name' => 'phpUxcOty',
'name' => 'my-avatar.png',
'size' => 90996,
'type' => 'image/png',
'error' => 0,
),
),
),
)
And the corresponding tree returned by getUploadedFiles() should be:
array(
'my-form' => array(
'details' => array(
'avatar' => /* UploadedFileInterface instance */
),
),
)
In some cases, you may specify an array of files:
Upload an avatar: <input type="file" name="my-form[details][avatars][]" />
Upload an avatar: <input type="file" name="my-form[details][avatars][]" />
(As an example, JavaScript controls might spawn additional file upload inputs to
allow uploading multiple files at once.)
In such a case, the specification implementation must aggregate all information
related to the file at the given index. The reason is because $_FILES deviates
from its normal structure in such cases:
array(
'my-form' => array(
'details' => array(
'avatars' => array(
'tmp_name' => array(
0 => '...',
1 => '...',
2 => '...',
),
'name' => array(
0 => '...',
1 => '...',
2 => '...',
),
'size' => array(
0 => '...',
1 => '...',
2 => '...',
),
'type' => array(
0 => '...',
1 => '...',
2 => '...',
),
'error' => array(
0 => '...',
1 => '...',
2 => '...',
),
),
),
),
)
The above $_FILES array would correspond to the following structure as
returned by getUploadedFiles():
array(
'my-form' => array(
'details' => array(
'avatars' => array(
0 => /* UploadedFileInterface instance */,
1 => /* UploadedFileInterface instance */,
2 => /* UploadedFileInterface instance */,
),
),
),
)
Consumers would access index 1 of the nested array using:
$request->getUploadedFiles()['my-form']['details']['avatars'][1];
Because the uploaded files data is derivative (derived from $_FILES or the
request body), a mutator method, withUploadedFiles(), is also present in the
interface, allowing delegation of the normalization to another process.
In the case of the original examples, consumption resembles the following:
$file0 = $request->getUploadedFiles()['files'][0];
$file1 = $request->getUploadedFiles()['files'][1];
printf(
"Received the files %s and %s",
$file0->getClientFilename(),
$file1->getClientFilename()
);
// "Received the files file0.txt and file1.html"
This proposal also recognizes that implementations may operate in non-SAPI
environments. As such, UploadedFileInterface provides methods for ensuring
operations will work regardless of environment. In particular:
-
moveTo($targetPath)is provided as a safe and recommended alternative to calling
move_uploaded_file()directly on the temporary upload file. Implementations
will detect the correct operation to use based on environment. -
getStream()will return aStreamInterfaceinstance. In non-SAPI
environments, one proposed possibility is to parse individual upload files
intophp://tempstreams instead of directly to files; in such cases, no
upload file is present.getStream()is therefore guaranteed to work
regardless of environment.
As examples:
// Move a file to an upload directory
$filename = sprintf(
'%s.%s',
create_uuid(),
pathinfo($file0->getClientFilename(), PATHINFO_EXTENSION)
);
$file0->moveTo(DATA_DIR . '/' . $filename);
// Stream a file to Amazon S3.
// Assume $s3wrapper is a PHP stream that will write to S3, and that
// Psr7StreamWrapper is a class that will decorate a StreamInterface as a PHP
// StreamWrapper.
$stream = new Psr7StreamWrapper($file1->getStream());
stream_copy_to_stream($stream, $s3wrapper);
2. Package
上面討論的接口和類庫已經(jīng)整合成為擴(kuò)展包:
psr/http-message。
3. Interfaces
3.1 Psr\Http\Message\MessageInterface
<?php
namespace Psr\Http\Message;
/**
*
* HTTP 消息值得是客戶端發(fā)起的「請求」和服務(wù)器端返回的「響應(yīng)」,此接口
* 定義了他們通用的方法。
*
* HTTP 消息是被視為無法修改的,所有能修改狀態(tài)的方法,都 **必須** 有一套
* 機(jī)制,在內(nèi)部保持好原有的內(nèi)容,然后把修改狀態(tài)后的信息返回。
*
* @see http://www.ietf.org/rfc/rfc7230.txt
* @see http://www.ietf.org/rfc/rfc7231.txt
*/
interface MessageInterface
{
/**
* 獲取字符串形式的 HTTP 協(xié)議版本信息
*
* 字符串必須包含 HTTP 版本數(shù)字,如:"1.1", "1.0"。
*
* @return string HTTP 協(xié)議版本
*/
public function getProtocolVersion();
/**
* 返回指定 HTTP 版本號的消息實(shí)例。
*
* 傳參的版本號必須 **只** 包含 HTTP 版本數(shù)字,如:"1.1", "1.0"。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息對象,然后返回
* 一個新的帶有傳參進(jìn)去的 HTTP 版本的實(shí)例
*
* @param string $version HTTP 版本信息
* @return self
*/
public function withProtocolVersion($version);
/**
* 獲取所有的頭信息
*
* 返回的二維數(shù)組中,第一維數(shù)組的「鍵」代表單條頭信息的名字,「值」是
* 以數(shù)據(jù)形式返回的,見以下實(shí)例:
*
* // 把「值」的數(shù)據(jù)當(dāng)成字串打印出來
* foreach ($message->getHeaders() as $name => $values) {
* echo $name . ': ' . implode(', ', $values);
* }
*
* // 迭代的循環(huán)二維數(shù)組
* foreach ($message->getHeaders() as $name => $values) {
* foreach ($values as $value) {
* header(sprintf('%s: %s', $name, $value), false);
* }
* }
*
* 雖然頭信息是沒有大小寫之分,但是使用 `getHeaders()` 會返回保留了原本
* 大小寫形式的內(nèi)容。
*
* @return string[][] 返回一個兩維數(shù)組,第一維數(shù)組的「鍵」 **必須** 為單條頭信息的
* 名稱,對應(yīng)的是由字串組成的數(shù)組,請注意,對應(yīng)的「值」 **必須** 是數(shù)組形式的。
*/
public function getHeaders();
/**
* 檢查是否頭信息中包含有此名稱的值,不區(qū)分大小寫
*
* @param string $name 不區(qū)分大小寫的頭信息名稱
* @return bool 找到返回 true,未找到返回 false
*/
public function hasHeader($name);
/**
* 根據(jù)給定的名稱,獲取一條頭信息,不區(qū)分大小寫,以數(shù)組形式返回
*
* 此方法以數(shù)組形式返回對應(yīng)名稱的頭信息。
*
* 如果沒有對應(yīng)的頭信息,**必須** 返回一個空數(shù)組。
*
* @param string $name 不區(qū)分大小寫的頭部字段名稱。
* @return string[] 返回頭信息中,對應(yīng)名稱的,由字符串組成的數(shù)組值,如果沒有對應(yīng)
* 的內(nèi)容,**必須** 返回空數(shù)組。
*/
public function getHeader($name);
/**
* 根據(jù)給定的名稱,獲取一條頭信息,不區(qū)分大小寫,以逗號分隔的形式返回
*
* 此方法返回所有對應(yīng)的頭信息,并將其使用逗號分隔的方法拼接起來。
*
* 注意:不是所有的頭信息都可使用逗號分隔的方法來拼接,對于那些頭信息,請使用
* `getHeader()` 方法來獲取。
*
* 如果沒有對應(yīng)的頭信息,此方法 **必須** 返回一個空字符串。
*
* @param string $name 不區(qū)分大小寫的頭部字段名稱。
* @return string 返回頭信息中,對應(yīng)名稱的,由逗號分隔組成的字串,如果沒有對應(yīng)
* 的內(nèi)容,**必須** 返回空字符串。
*/
public function getHeaderLine($name);
/**
* 返回指定頭信息「鍵/值」對的消息實(shí)例。
*
* 雖然頭信息是不區(qū)分大小寫的,但是此方法必須保留其傳參時的大小寫狀態(tài),并能夠在
* 調(diào)用 `getHeaders()` 的時候被取出。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息對象,然后返回
* 一個新的帶有傳參進(jìn)去頭信息的實(shí)例
*
* @param string $name Case-insensitive header field name.
* @param string|string[] $value Header value(s).
* @return self
* @throws \InvalidArgumentException for invalid header names or values.
*/
public function withHeader($name, $value);
/**
* 返回一個頭信息增量的 HTTP 消息實(shí)例。
*
* 原有的頭信息會被保留,新的值會作為增量加上,如果頭信息不存在的話,會被加上。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息對象,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param string $name 不區(qū)分大小寫的頭部字段名稱。
* @param string|string[] $value 頭信息對應(yīng)的值。
* @return self
* @throws \InvalidArgumentException 頭信息字段名稱非法時會被拋出。
* @throws \InvalidArgumentException 頭信息的值非法的時候,會被拋出。
*/
public function withAddedHeader($name, $value);
/**
* 返回被移除掉指定頭信息的 HTTP 消息實(shí)例。
*
* 頭信息字段在解析的時候,**必須** 保證是不區(qū)分大小寫的。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息對象,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param string $name 不區(qū)分大小寫的頭部字段名稱。
* @return self
*/
public function withoutHeader($name);
/**
* 獲取 HTTP 消息的內(nèi)容。
*
* @return StreamInterface 以數(shù)據(jù)流的形式返回。
*/
public function getBody();
/**
* 返回拼接了內(nèi)容的 HTTP 消息實(shí)例。
*
* 內(nèi)容 **必須** 是 StreamInterface 接口的實(shí)例。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息對象,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param StreamInterface $body 數(shù)據(jù)流形式的內(nèi)容。
* @return self
* @throws \InvalidArgumentException 當(dāng)消息內(nèi)容不正確的時候。
*/
public function withBody(StreamInterface $body);
}
3.2 Psr\Http\Message\RequestInterface
<?php
namespace Psr\Http\Message;
/**
* 代表客戶端請求的 HTTP 消息對象。
*
* 根據(jù)規(guī)范,每一個 HTTP 請求都包含以下信息:
*
* - HTTP 協(xié)議版本號 (Protocol version)
* - HTTP 請求方法 (HTTP method)
* - URI
* - 頭信息 (Headers)
* - 消息內(nèi)容 (Message body)
*
* 在構(gòu)造 HTTP 請求對象的時候,實(shí)現(xiàn)類庫 **必須** 從給出的 URI 中去提取 HOST 信息。
*
* HTTP 請求是被視為無法修改的,所有能修改狀態(tài)的方法,都 **必須** 有一套機(jī)制,在內(nèi)部保
* 持好原有的內(nèi)容,然后把修改狀態(tài)后的,新的 HTTP 請求實(shí)例返回。
*/
interface RequestInterface extends MessageInterface
{
/**
* 獲取消息請求的目標(biāo)。
*
* 在大部分情況下,此方法會返回完整的 URI,除非 `withRequestTarget()` 被設(shè)置過。
*
* 如果沒有提供 URI,并且沒有提供任何的請求目標(biāo),此方法 **必須** 返回 "/"。
*
* @return string
*/
public function getRequestTarget();
/**
* 返回一個指定目標(biāo)的請求實(shí)例。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 請求實(shí)例,然后返回
* 一個新的修改過的 HTTP 請求實(shí)例。
*
* @see 關(guān)于請求目標(biāo)的各種允許的格式,請見 http://tools.ietf.org/html/rfc7230#section-2.7
*
* @param mixed $requestTarget
* @return self
*/
public function withRequestTarget($requestTarget);
/**
* 獲取當(dāng)前請求使用的 HTTP 方法
*
* @return string HTTP 方法字符串
*/
public function getMethod();
/**
* 返回更改了請求方法的消息實(shí)例。
*
* 雖然,在大部分情況下,HTTP 請求方法都是使用大寫字母來標(biāo)示的,但是,實(shí)現(xiàn)類庫 **一定不可**
* 修改用戶傳參的大小格式。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 請求實(shí)例,然后返回
* 一個新的修改過的 HTTP 請求實(shí)例。
*
* @param string $method 大小寫敏感的方法名
* @return self
* @throws \InvalidArgumentException 當(dāng)非法的 HTTP 方法名傳入時會拋出異常。
*/
public function withMethod($method);
/**
* 獲取 URI 實(shí)例。
*
* 此方法必須返回 `UriInterface` 的 URI 實(shí)例。
*
* @see http://tools.ietf.org/html/rfc3986#section-4.3
* @return UriInterface 返回與當(dāng)前請求相關(guān) `UriInterface` 類型的 URI 實(shí)例。
*/
public function getUri();
/**
* 返回修改了 URI 的消息實(shí)例。
*
* 當(dāng)傳入的 `URI` 包含有 `HOST` 信息時,**必須** 更新 `HOST` 頭信息,如果 `URI`
* 實(shí)例沒有附帶 `HOST` 信息,任何之前存在的 `HOST` 信息 **必須** 作為候補(bǔ),應(yīng)用
* 更改到返回的消息實(shí)例里。
*
* 你可以通過傳入第二個參數(shù)來,來干預(yù)方法的處理,當(dāng) `$preserveHost` 設(shè)置為 `true`
* 的時候,會保留原來的 `HOST` 信息。
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 請求實(shí)例,然后返回
* 一個新的修改過的 HTTP 請求實(shí)例。
*
* @see http://tools.ietf.org/html/rfc3986#section-4.3
* @param UriInterface $uri `UriInterface` 類型的 URI 實(shí)例
* @param bool $preserveHost 是否保留原有的 HOST 頭信息
* @return self
*/
public function withUri(UriInterface $uri, $preserveHost = false);
}
3.2.1 Psr\Http\Message\ServerRequestInterface
<?php
namespace Psr\Http\Message;
/**
* Representation of an incoming, server-side HTTP request.
*
* Per the HTTP specification, this interface includes properties for
* each of the following:
*
* - Protocol version
* - HTTP method
* - URI
* - Headers
* - Message body
*
* Additionally, it encapsulates all data as it has arrived to the
* application from the CGI and/or PHP environment, including:
*
* - The values represented in $_SERVER.
* - Any cookies provided (generally via $_COOKIE)
* - Query string arguments (generally via $_GET, or as parsed via parse_str())
* - Upload files, if any (as represented by $_FILES)
* - Deserialized body parameters (generally from $_POST)
*
* $_SERVER values MUST be treated as immutable, as they represent application
* state at the time of request; as such, no methods are provided to allow
* modification of those values. The other values provide such methods, as they
* can be restored from $_SERVER or the request body, and may need treatment
* during the application (e.g., body parameters may be deserialized based on
* content type).
*
* Additionally, this interface recognizes the utility of introspecting a
* request to derive and match additional parameters (e.g., via URI path
* matching, decrypting cookie values, deserializing non-form-encoded body
* content, matching authorization headers to users, etc). These parameters
* are stored in an "attributes" property.
*
* HTTP 請求是被視為無法修改的,所有能修改狀態(tài)的方法,都 **必須** 有一套機(jī)制,在內(nèi)部保
* 持好原有的內(nèi)容,然后把修改狀態(tài)后的,新的 HTTP 請求實(shí)例返回。
*/
interface ServerRequestInterface extends RequestInterface
{
/**
* Retrieve server parameters.
*
* Retrieves data related to the incoming request environment,
* typically derived from PHP's $_SERVER superglobal. The data IS NOT
* REQUIRED to originate from $_SERVER.
*
* @return array
*/
public function getServerParams();
/**
* Retrieve cookies.
*
* Retrieves cookies sent by the client to the server.
*
* The data MUST be compatible with the structure of the $_COOKIE
* superglobal.
*
* @return array
*/
public function getCookieParams();
/**
* Return an instance with the specified cookies.
*
* The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
* be compatible with the structure of $_COOKIE. Typically, this data will
* be injected at instantiation.
*
* This method MUST NOT update the related Cookie header of the request
* instance, nor related values in the server params.
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param array $cookies Array of key/value pairs representing cookies.
* @return self
*/
public function withCookieParams(array $cookies);
/**
* Retrieve query string arguments.
*
* Retrieves the deserialized query string arguments, if any.
*
* Note: the query params might not be in sync with the URI or server
* params. If you need to ensure you are only getting the original
* values, you may need to parse the query string from `getUri()->getQuery()`
* or from the `QUERY_STRING` server param.
*
* @return array
*/
public function getQueryParams();
/**
* Return an instance with the specified query string arguments.
*
* These values SHOULD remain immutable over the course of the incoming
* request. They MAY be injected during instantiation, such as from PHP's
* $_GET superglobal, or MAY be derived from some other value such as the
* URI. In cases where the arguments are parsed from the URI, the data
* MUST be compatible with what PHP's parse_str() would return for
* purposes of how duplicate query parameters are handled, and how nested
* sets are handled.
*
* Setting query string arguments MUST NOT change the URI stored by the
* request, nor the values in the server params.
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param array $query Array of query string arguments, typically from
* $_GET.
* @return self
*/
public function withQueryParams(array $query);
/**
* Retrieve normalized file upload data.
*
* This method returns upload metadata in a normalized tree, with each leaf
* an instance of Psr\Http\Message\UploadedFileInterface.
*
* These values MAY be prepared from $_FILES or the message body during
* instantiation, or MAY be injected via withUploadedFiles().
*
* @return array An array tree of UploadedFileInterface instances; an empty
* array MUST be returned if no data is present.
*/
public function getUploadedFiles();
/**
* Create a new instance with the specified uploaded files.
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param array An array tree of UploadedFileInterface instances.
* @return self
* @throws \InvalidArgumentException if an invalid structure is provided.
*/
public function withUploadedFiles(array $uploadedFiles);
/**
* Retrieve any parameters provided in the request body.
*
* If the request Content-Type is either application/x-www-form-urlencoded
* or multipart/form-data, and the request method is POST, this method MUST
* return the contents of $_POST.
*
* Otherwise, this method may return any results of deserializing
* the request body content; as parsing returns structured content, the
* potential types MUST be arrays or objects only. A null value indicates
* the absence of body content.
*
* @return null|array|object The deserialized body parameters, if any.
* These will typically be an array or object.
*/
public function getParsedBody();
/**
* Return an instance with the specified body parameters.
*
* These MAY be injected during instantiation.
*
* If the request Content-Type is either application/x-www-form-urlencoded
* or multipart/form-data, and the request method is POST, use this method
* ONLY to inject the contents of $_POST.
*
* The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
* deserializing the request body content. Deserialization/parsing returns
* structured data, and, as such, this method ONLY accepts arrays or objects,
* or a null value if nothing was available to parse.
*
* As an example, if content negotiation determines that the request data
* is a JSON payload, this method could be used to create a request
* instance with the deserialized parameters.
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @param null|array|object $data The deserialized body data. This will
* typically be in an array or object.
* @return self
* @throws \InvalidArgumentException if an unsupported argument type is
* provided.
*/
public function withParsedBody($data);
/**
* Retrieve attributes derived from the request.
*
* The request "attributes" may be used to allow injection of any
* parameters derived from the request: e.g., the results of path
* match operations; the results of decrypting cookies; the results of
* deserializing non-form-encoded message bodies; etc. Attributes
* will be application and request specific, and CAN be mutable.
*
* @return mixed[] Attributes derived from the request.
*/
public function getAttributes();
/**
* Retrieve a single derived request attribute.
*
* Retrieves a single derived request attribute as described in
* getAttributes(). If the attribute has not been previously set, returns
* the default value as provided.
*
* This method obviates the need for a hasAttribute() method, as it allows
* specifying a default value to return if the attribute is not found.
*
* @see getAttributes()
* @param string $name The attribute name.
* @param mixed $default Default value to return if the attribute does not exist.
* @return mixed
*/
public function getAttribute($name, $default = null);
/**
* Return an instance with the specified derived request attribute.
*
* This method allows setting a single derived request attribute as
* described in getAttributes().
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @see getAttributes()
* @param string $name The attribute name.
* @param mixed $value The value of the attribute.
* @return self
*/
public function withAttribute($name, $value);
/**
* Return an instance that removes the specified derived request attribute.
*
* This method allows removing a single derived request attribute as
* described in getAttributes().
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @see getAttributes()
* @param string $name The attribute name.
* @return self
*/
public function withoutAttribute($name);
}
3.3 Psr\Http\Message\ResponseInterface
<?php
namespace Psr\Http\Message;
/**
* Representation of an outgoing, server-side response.
*
* Per the HTTP specification, this interface includes properties for
* each of the following:
*
* - Protocol version
* - Status code and reason phrase
* - Headers
* - Message body
*
* Responses are considered immutable; all methods that might change state MUST
* be implemented such that they retain the internal state of the current
* message and return an instance that contains the changed state.
*
* HTTP 響應(yīng)是被視為無法修改的,所有能修改狀態(tài)的方法,都 **必須** 有一套機(jī)制,在內(nèi)部保
* 持好原有的內(nèi)容,然后把修改狀態(tài)后的,新的 HTTP 響應(yīng)實(shí)例返回。
*/
interface ResponseInterface extends MessageInterface
{
/**
* Gets the response status code.
*
* The status code is a 3-digit integer result code of the server's attempt
* to understand and satisfy the request.
*
* @return int Status code.
*/
public function getStatusCode();
/**
* Return an instance with the specified status code and, optionally, reason phrase.
*
* If no reason phrase is specified, implementations MAY choose to default
* to the RFC 7231 or IANA recommended reason phrase for the response's
* status code.
*
* 此方法在實(shí)現(xiàn)的時候,**必須** 保留原有的不可修改的 HTTP 消息實(shí)例,然后返回
* 一個新的修改過的 HTTP 消息實(shí)例。
*
* @see http://tools.ietf.org/html/rfc7231#section-6
* @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
* @param int $code The 3-digit integer result code to set.
* @param string $reasonPhrase The reason phrase to use with the
* provided status code; if none is provided, implementations MAY
* use the defaults as suggested in the HTTP specification.
* @return self
* @throws \InvalidArgumentException For invalid status code arguments.
*/
public function withStatus($code, $reasonPhrase = '');
/**
* Gets the response reason phrase associated with the status code.
*
* Because a reason phrase is not a required element in a response
* status line, the reason phrase value MAY be empty. Implementations MAY
* choose to return the default RFC 7231 recommended reason phrase (or those
* listed in the IANA HTTP Status Code Registry) for the response's
* status code.
*
* @see http://tools.ietf.org/html/rfc7231#section-6
* @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
* @return string Reason phrase; must return an empty string if none present.
*/
public function getReasonPhrase();
}