HTTP 响应

最后更新于:2022-04-01 22:33:50

# HTTP 响应 Slim 应用程序的路由和中间件给出了一个 PSR 7 响应对象,它表示当前的 HTTP 响应将被返回给客户端。该响应对象遵循 [PSR 7 响应接口](http://www.php-fig.org/psr/psr-7/#3-2-1-psr-http-message-responseinterface)实现,因此你可以检查和操作该 HTTP 响应的状态、响应头和响应体。 ## 如何获取 HTTP 响应对象 PSR 7 响应对象作为路由回调的第二个参数注入到 Slim 应用程序的路由中: ``` get('/foo', function (ServerRequestInterface $request, ResponseInterface $response) { // Use the PSR 7 $response object return $response; }); $app->run(); ``` Figure 1: Inject PSR 7 response into application route callback. PSR 7 请求对象作为中间件 callable 的第二个参数注入到 Slim 应用程序的_中间件_: ``` add(function (ServerRequestInterface $request, ResponseInterface $response, callable $next) { // Use the PSR 7 $response object return $next($request, $response); }); // Define app routes... $app->run(); ``` Figure 2: Inject PSR 7 response into application middleware. ## HTTP 响应状态 每个 HTTP 响应都有一个数字 [状态编码](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)。状态编码用于识别返回客户端的 HTTP 响应的_类型_。PSR 7 响应对象的默认状态编码是 `200` (OK)。你可以像这样使用 `getStatusCode()` 方法获取 PSR 7 响应对象的状态编码: ``` $status = $response->getStatusCode(); ``` Figure 3: Get response status code. 你可以拷贝一个 PSR 7 响应对象,并指定一个新的状态编码,像这样: ``` $newResponse = $response->withStatus(302); ``` Figure 4: Create response with new status code. ## HTTP 响应头 每个 HTTP 响应都有其相应的响应头。这些元数据描述了 HTTP 响应,但在响应体中不可见。Slim 的 PSR 7 响应对象提供了几种检查和操作响应头的方法。 ### 获取所有响应头 使用 PSR 7 响应对象的 `getHeaders()` 方法提取所有 HTTP 响应头并存入一个关联数组中。该关联数组的键名即为响应头的名称,键值是与其响应头对应的值的字符串数组。 ``` $headers = $response->getHeaders(); foreach ($headers as $name => $values) { echo $name . ": " . implode(", ", $values); } ``` Figure 5: Fetch and iterate all HTTP response headers as an associative array. ### 获取单个响应头 使用 PSR 7 响应对象的 `getHeader($name)` 方法获取单个响应头的值。它将返回指定响应头的值组成的数组。记住,单个 HTTP 响应不止一个值。 ``` $headerValueArray = $response->getHeader('Vary'); ``` Figure 6: Get values for a specific HTTP header. 同样,可以是 PSR 7 响应对象的 `getHeaderLine($name)` 方法获取指定响应头的所有值,由逗号隔开。不同于 `getHeader($name)` 方法,此方法返回的是由逗号隔开的字符串。 ``` $headerValueString = $response->getHeaderLine('Vary'); ``` Figure 7: Get single header's values as comma-separated string. ### 检查响应头 使用 PSR 7 响应对象的 `hasHeader($name)` 方法检查响应头存在与否。 ``` if ($response->hasHeader('Vary')) { // Do something } ``` Figure 8: Detect presence of a specific HTTP header. ### 设置响应头 使用 PSR 7 响应对象的 `withHeader($name, $value)` 方法设置响应头的值。 ``` $newResponse = $oldResponse->withHeader('Content-type', 'application/json'); ``` Figure 9: Set HTTP header **提示**响应对象是不可改的。此方法返回一个响应对象的_拷贝(copy)_,它拥有新的值。**此方法是破坏性的**,它替换了已有的同名响应头现有的值。 ### 追加响应头/Append Header 使用 PSR 7 响应对象的 `withAddedHeader($name, $value)` 方法追加一个响应头的值。 ``` $newResponse = $oldResponse->withAddedHeader('Allow', 'PUT'); ``` Figure 10: Append HTTP header **提示**不同于 `withHeader()` 方法,此方法是_追加(append)_新的值到响应头已有的值中。该响应对象是不可修改的。此方法返回一个已添加新值的该对象的_拷贝_。 ### 移除响应头 使用 HTTP 响应对象的 `withoutHeader($name)` 方法移除响应头。 ``` $newResponse = $oldResponse->withoutHeader('Allow'); ``` Figure 11: Remove HTTP header **提示**响应对象是不可改的。此方法返回一个带有追加的响应头的值的响应对象的_拷贝(copy)_。 ## HTTP 响应体 HTTP 响应通常有一个响应体。Slim 提供了一个 PSR 7 响应对象,你可以用它检查或操作可能会有的响应体。 类似 PSR 7 请求对象,PSR 7 响应对象将响应体作为`\Psr\Http\Message\StreamInterface` 的实例来实现。你可以使用 PSR 7 响应对象的 `getBody()` 方法来获取 HTTP 响应体 `StreamInterface` 的实例。该 `getBody()` 方法完美适用于未知大小或对于可用内容来说太大的输出(outgoing) HTTP 响应。 ``` $body = $response->getBody(); ``` Figure 12: Get HTTP response body 所得的 `\Psr\Http\Message\StreamInterface` 实例提供以下方法来读取、迭代、写入到潜在的 PHP`资源(resource)`。 * `getSize()` * `tell()` * `eof()` * `isSeekable()` * `seek()` * `rewind()` * `isWritable()` * `write($string)` * `isReadable()` * `read($length)` * `getContents()` * `getMetadata($key = null)` 大多数情况下,你会需要写入到 PSR 7 响应对象。你可以像这样使用 `write()` 方法将内容写入到 `StreamInterface` 实例: ``` $body = $response->getBody(); $body->write('Hello'); ``` Figure 13: Write content to the HTTP response body 你同样可以完整新建一个 `StreamInterface` 实例来_替换_ PSR 7 响应对象的响应体。这玩意特别有用,尤其是你想要从远程地址传输内容到 HTTP 响应中时(例如,文件系统或远程API)。你可以使用 `withBody(StreamInterface $body)` 方法替换 PSR 7 响应对象的响应体。它的参数**必须**是 `\Psr\Http\Message\StreamInterface` 的实例。 ``` $newStream = new \GuzzleHttp\Psr7\LazyOpenStream('/path/to/file', 'r'); $newResponse = $oldResponse->withBody($newStream); ``` Figure 14: Replace the HTTP response body **提示**响应对象不可改变。这个方法返回的是包含新响应体的对象的_拷贝(copy)_。 ## 返回 JSON Slim 的响应对象拥有一个自定义方法 `withJson($data, $status, $encodingOptions)` 来帮助优化返回 JSON 数据的过程。 其中 `$data` 参数包含你希望返回的 JSON 的数据结构。`$status` 是可选的,并能返回一个自定义的 HTTP 代码。`$encodingOptions` 是可选的,它是与[`json_encode()`](http://php.net/manual/en/function.json-encode.php) 相同的编码选项。 最简单的形式,可以返回带默认的 200 HTTP 状态代码的 JSON 数据。 ``` $data = array('name' => 'Bob', 'age' => 40); $newResponse = $oldResponse->withJson($data); ``` Figure 15: Returning JSON with a 200 HTTP status code. 还可以返回带有自定义 HTTP 状态码的 JSON 数据。 ``` $data = array('name' => 'Rob', 'age' => 40); $newResponse = $oldResponse->withJson($data, 201); ``` Figure 16: Returning JSON with a 201 HTTP status code. HTTP 响应的 `Content-Type` 自动设置为 `application/json;charset=utf-8`。 如果 JSON 存在数据编码问题,`\RuntimeException($message, $code)`将抛出异常,包含将 [`json_last_error_msg()`](http://php.net/manual/en/function.json-last-error-msg.php) 的值作为 `$message`的值以及将 [`json_last_error()`](http://php.net/manual/en/function.json-last-error.php) 作为 the `$code`的值。 **提示**响应对象是不可改的。此方法返回一个响应对象的_拷贝(copy)_,该拷贝带有新的 Content-Type 头。**该方法是毁灭性的**,它将_替换(replaces)_已存在的 Content-Type 头。当 `withJson()` 被调用,如果传递了 $status ,HTTP 状态码也会被替换。
';