请求

您的 Slim 应用程序的路由和中间件会出现一个 PSR-7 请求对象,该对象表示您的 Web 服务器收到的当前 HTTP 请求。该请求对象实现了 PSR-7 ServerRequestInterface,使用它您可以检查和操作 HTTP 请求方法、头和正文。

如何获取请求对象

PSR-7 请求对象作为路由回调的第一个参数注入到 Slim 应用程序路由中,如下所示

<?php

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->get('/hello', function (Request $request, Response $response) {
    $response->getBody()->write('Hello World');
    return $response;
});

$app->run();

PSR-7 请求对象作为中间件可调用项的第一个参数注入到 Slim 应用程序中间件中,如下所示

向应用中间件注入 PSR-7 请求

<?php

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->add(function (Request $request, RequestHandler $handler) {
   return $handler->handle($request);
});

// ...define app routes...

$app->run();

请求 HTTP 方法

每个 HTTP 请求都有一个方法,通常是一个方法

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • PATCH
  • OPTIONS

您可以使用正确命名的 Request 对象方法 getMethod() 检查 HTTP 请求的方法。

$method = $request->getMethod();

可以伪造或覆盖 HTTP 请求方法。举例而言,如果您需要模仿仅支持 GETPOST 请求的传统网络浏览器使用 PUT 请求时,这会非常有用。

注意:要启用请求方法覆盖,必须将 Method Overriding Middleware 注入您的应用程序。

有两种方法可以覆盖 HTTP 请求方法。您可以在 POST 请求的主体中包含一个 METHOD 参数。HTTP 请求必须使用 application/x-www-form-urlencoded 内容类型。

使用 _METHOD 参数覆盖 HTTP 方法

POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 22

data=value&_METHOD=PUT

您也可以使用自定义 X-Http-Method-Override HTTP 请求头覆盖 HTTP 请求方法。这适用于任何 HTTP 请求内容类型。

POST /path HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 16
X-Http-Method-Override: PUT

{"data":"value"}

服务器参数

若要请求与传入请求环境相关的数据,您需要使用 getServerParams()。举例而言,若要获取单个服务器参数

$params = $request->getServerParams();
$authorization = $params['HTTP_AUTHORIZATION'] ?? null;

POST 参数

如果请求方法为 POSTContent-Typeapplication/x-www-form-urlencodedmultipart/form-data,您可以如下方式检索所有 POST 参数

// Get all POST parameters
$params = (array)$request->getParsedBody();

// Get a single POST parameter
$foo = $params['foo'];

请求 URI

每个 HTTP 请求都有一个 URI,用于识别所请求的应用程序资源。HTTP 请求 URI 具有若干部分

  • 方案(例如 httphttps
  • 主机(例如 example.com
  • 端口(例如 80443
  • 路径(例如 /users/1
  • 查询字符串(例如 sort=created&dir=asc

您可以使用 getUri() 方法请求 PSR-7 请求对象的 URI 对象

$uri = $request->getUri();

PSR-7 请求对象的 URI 本身就是一个对象,提供以下方法来检查 HTTP 请求的 URL 部分

  • getScheme()
  • getAuthority()
  • getUserInfo()
  • getHost()
  • getPort()
  • getPath()
  • getQuery() (返回完整的查询字符串,例如 a=1&b=2
  • getFragment()

您可以使用 getQueryParams() 在请求对象上以关联数组的形式获取查询参数。

查询字符串参数

getQueryParams() 方法以关联数组的形式从 HTTP 请求的 URI 中检索所有查询参数。

如果没有查询参数,它会返回一个空数组。

在内部,此方法使用 parse_str 将查询字符串解析为数组。

用法

// URL: https://example.com/search?key1=value1&key2=value2
$queryParams = $request->getQueryParams();
Array
(
    [key1] => value1
    [key2] => value2
)

要从查询参数数组中读取单个值,可以使用参数的名称作为键。

// Output: value1
$key1 = $queryParams['key1'] ?? null;

// Output: value2
$key2 = $queryParams['key2'] ?? null;

// Output: null
$key3 = $queryParams['key3'] ?? null;

注意: ?? null 确保如果查询参数不存在,将返回 null,而不是引发警告。

请求头

每个 HTTP 请求都有头信息。这些是描述 HTTP 请求的元数据,但在请求正文中不可见。Slim 的 PSR-7 请求对象提供了很多方法来检查其头信息。

获取所有头信息

可以使用 PSR-7 请求对象的 getHeaders() 方法以关联数组形式获取所有 HTTP 请求头信息。结果关联数组的键是头信息名称,而它的值本身是其各自头信息名称的字符串值的数字数组。

$headers = $request->getHeaders();
foreach ($headers as $name => $values) {
    echo $name . ": " . implode(", ", $values);
}
图 5:获取并迭代所有 HTTP 请求头信息,将其作为关联数组。

获取单个头信息

可以使用 PSR-7 请求对象的 getHeader($name) 方法获取单个头信息的值。这会返回给定头信息名称的值数组。请记住,一个 HTTP 头信息可以有多个值!

获取指定 HTTP 头信息的值

$headerValueArray = $request->getHeader('Accept');

还可以使用 PSR-7 请求对象的 getHeaderLine($name) 方法获取用逗号分隔的字符串,其中包含给定头信息的所有值。与 getHeader($name) 方法不同,此方法返回用逗号分隔的字符串。

将单个头信息的值获取为用逗号分隔的字符串

$headerValueString = $request->getHeaderLine('Accept');

检测头信息

可以使用 PSR-7 请求对象的 hasHeader($name) 方法测试头信息是否存在。

if ($request->hasHeader('Accept')) {
    // Do something
}

检测 XHR 请求

可以使用请求的 getHeaderLine() 方法,通过检查头信息 X-Requested-With 是否为 XMLHttpRequest,来检测 XHR 请求。

XHR 请求示例

POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 7
X-Requested-With: XMLHttpRequest

foo=bar
if ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') {
    // Do something
}

Content-Type

可以使用请求对象的 getHeaderLine() 方法获取 HTTP 请求内容类型。

$contentType = $request->getHeaderLine('Content-Type');

内容长度

可以使用请求对象的 getHeaderLine() 方法获取 HTTP 请求内容长度。

$length = $request->getHeaderLine('Content-Length');

请求正文

每个 HTTP 请求都有正文。如果你正在构建一个使用 JSON 或 XML 数据的 Slim 应用程序,可以使用 PSR-7 请求对象的 getParsedBody() 方法将 HTTP 请求正文解析为原生 PHP 格式。请注意,正文解析因 PSR-7 的不同实现而异。

您可能需要实现中间件,以根据您已安装的 PSR-7 实现解析传入的输入。以下是一个解析传入的 JSON 输入的示例

<?php

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class JsonBodyParserMiddleware implements MiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response
    {
        $contentType = $request->getHeaderLine('Content-Type');

        if (strstr($contentType, 'application/json')) {
            $contents = json_decode(file_get_contents('php://input'), true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $request = $request->withParsedBody($contents);
            }
        }

        return $handler->handle($request);
    }
}

将 HTTP 请求正文解析为原生 PHP 格式

$parsedBody = $request->getParsedBody();

从技术上讲,PSR-7 Request 对象以 Psr\Http\Message\StreamInterface 的实例表示 HTTP 请求正文。您可以使用 PSR-7 Request 对象的 getBody() 方法获取 HTTP 请求正文 StreamInterface 实例。如果传入的 HTTP 请求大小未知或太大,以至于可用内存无法容纳,则此 getBody() 方法更可取。

获取 HTTP 请求正文

$body = $request->getBody();

生成的 Psr\Http\Message\StreamInterface 实例提供了以下方法来读取和迭代其底层的 PHP resource

  • getSize()
  • tell()
  • eof()
  • isSeekable()
  • seek()
  • rewind()
  • isWritable()
  • write($string)
  • isReadable()
  • read($length)
  • getContents()
  • getMetadata($key = null)

上传的文件

$_FILES 中的文件上传可从 Request 对象的 getUploadedFiles() 方法使用。此方法返回一个数组,其键是 input 元素的名称。

获取上传的文件

$files = $request->getUploadedFiles();

$files 数组中的每个对象都是 Psr\Http\Message\UploadedFileInterface 的一个实例,并支持以下方法

  • getStream()
  • moveTo($targetPath)
  • getSize()
  • getError()
  • getClientFilename()
  • getClientMediaType()

请参阅 手册,了解如何使用 POST 表单上传文件。

属性

使用 PSR-7 可以将对象/值注入请求对象以进一步进行处理。在您的应用程序中,中间件通常需要将信息传递给路由闭包,而实现此目的的方法是通过属性将其添加到请求对象。

示例,在请求对象上设置值。

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

$app->add(function (Request $request, RequestHandler $handler) {
    // Add the session storage to your request as [READ-ONLY]
    $request = $request->withAttribute('session', $_SESSION);
    
    return $handler->handle($request);
});

示例,如何检索值。

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

$app->get('/test', function (Request $request, Response $response) {
    // Get the session from the request
    $session = $request->getAttribute('session');
    
    $response->getBody()->write('Yay, ' . $session['name']);
    
    return $response;
});

请求对象还具有批量功能。 $request->getAttributes()$request->withAttributes()