Slim应用的路由和中间件都通过一个PSR 7请求对象来表示当前从你的Web服务器中接收的HTTP请求.这个请求是PSR 7 ServerRequestInterface 接口的实现,你可以通过它去检查和操作请求的方法(method),头部(headers)和主体(body).

怎么获得请求对象

在Slim 3中,PSR 7请求对象作为路由回调的第一个参数已经被注入到你的Slim应用路由中.

<?php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

$app = new \Slim\App;
$app->get('/foo', function (ServerRequestInterface $request, ResponseInterface $response) {
		// Use the PSR 7 $request object

		return $response;
});
$app->run();

在Slim 3中,PSR 7请求对象作为中间件回调的第一个参数已经被注入到你的Slim应用中间件中.

<?php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

$app = new \Slim\App;
$app->add(function (ServerRequestInterface $request, ResponseInterface $response, callable $next) {
		// Use the PSR 7 $request object

		return $next($request, $response);
});
// Define app routes...
$app->run();

请求对象方法

任何一个HTTP请求都有以下方法:

* GET
* POST
* PUT
* DELETE
* HEAD
* PATCH
* OPTIONS

你可以通过Request请求对象的方法(getMethod())检测HTTP 请求中有的方法:

$method = $request->getMethod();

此外,Slim内置了PSR 7的实现,还提供了一些专有的方法返回 true 或者 false

* $request->isGet()
* $request->isPost()
* $request->isPut()
* $request->isDelete()
* $request->isHead()
* $request->isPatch()
* $request->isOptions()

你还看去伪造或者重载HTTP请求方式。这在一些环境中是非常重要的,比如你需要一个PUT请求,但是传统的HTTP请求只支持 GETPOST.

我们有两种方式去实现伪造HTTP请求方式,你可以把一个_METHOD参数放在请求的body里面,请求必须使用application/x-www-form-urlencoded类型(content-type),示例:

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

data=value&_METHOD=PUT

你也可以通过修改HTTP请求方式,通过修改请求头,增加X-Http-Method-Override,这种方式可以使用任何类型(content-type),示例:

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

{"data":"value"}

修改完之后,你也可以通过PSR 7对象的方法,获取原始的请求方式,方法名:getOriginalMethod().

请求URI

任何一个HTTP请求都有一个URI标识请求应用的资源,请求URI有几个部分组成:

* Scheme (e.g. http or https) //协议
* Host (e.g. example.com) //域名host
* Port (e.g. 80 or 443) //端口
* Path (e.g. /users/1) //路径
* Query string (e.g. sort=created&dir=asc) //请求参数

你可以通过PSR 7请求对象的方法 getUri() 获取PSR 7请求对象URI:

$uri = $request->getUri();

PSR 7请求对象URI是PSR 7自身的一个对象,它提供了一些方法去检查请求url的各个部分:

* getScheme()
* getHost()
* getPort()
* getPath()
* getBasePath()
* getQuery() (returns string)
* getQueryParams() (returns associative array)

如果你的Slim应用的前端控制器是在服务器根目录下的子目录里面,你可以通过 getBasePath() 获取到一个相当于服务器目录的路径。如果你的Slim应用是在服务器根目录下面,则返回空字符串

请求头

任何一个HTTP请求都有请求头,请求头描述了一个HTTP请求,但是不可以在请求主体中看到,Slim 的PSR 7请求对象提供了一些方法查看请求头。

获取请求头所有信息

你可以通过PSR 7 请求对象的方法 getHeaders() 获得HTTP请求的请求头的所有信息,结果将以数组形式返回.结果数组键名是请求头的名,值是以数字索引数组的形式返回.

$headers = $request->getHeaders();
foreach ($headers as $name => $values) {
	echo $name . ": " . implode(", ", $values);
}

示例:

Array
(
		[Host] => Array
				(
						[0] => z.slim.com
				)

		[HTTP_CONNECTION] => Array
				(
						[0] => keep-alive
				)

		[HTTP_CACHE_CONTROL] => Array
				(
						[0] => max-age=0
				)

		[HTTP_ACCEPT] => Array
				(
						[0] => text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
				)

		[HTTP_USER_AGENT] => Array
				(
						[0] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36
				)

		[HTTP_ACCEPT_ENCODING] => Array
				(
						[0] => gzip, deflate, sdch
				)

		[HTTP_ACCEPT_LANGUAGE] => Array
				(
						[0] => zh-CN,zh;q=0.8
				)

)

获取请求头中的一条信息

你可以通过PSR 7请求对象的方法 getHeader() 获得某一个请求头的值,它会返回一个由相对应的请求头的名称的值组成的数组.但是注意:一个请求头名称有可能有好多条值.

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

示例:

Array
(
		[0] => text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
)

当然你也可以通过PSR 7请求对象的方法 getHeaderLine($name) 选择以逗号分隔的字符串形式返回,不同于方法 getHeader(),此方法将值以逗号分隔的字符串形式返回:

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

示例:

text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

检测请求头

我们也可以通过 PSR 7请求对象的方法 hasHeader(),判断是否有某个请求头

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

请求正文

任何一条HTTP请求都有请求正文,如果你的Slim应用需要使用JSON 或则 XML 形式的数据,你可以通过 PSR 7请求对象的方法 getParsedBody()把请求正文解析成原生的PHP格式的.Slim可以解析 JSON,XML,URL编码格式的数据

$parsedBody = $request->getParsedBody();

PHP原生格式化方法:

JSON数据使用方法 json_decode($input,true) 解析成数组
XML通过方法 simplexml_load_string($input) 解析成一个 SimpleXMLElement对象
URL编码的通过方法 parse_str($input) 解析成数组

Slim PSR 7请求对象表示HTTP 请求正文是作为一个 \Psr\Http\Message\StreamInterface 接口的实现,你可以通过 StreamInterface在PSR 7请求对象中的实现方法 getBody() 获得HTTP 请求正文.getBody() 方法是当你请求携带的数据比较大或者未知的时候首选的方法:

$body = $request->getBody();

返回的结果,可以通过\Psr\Http\Message\StreamInterface 实现提供了下面的方法去读取和迭代PHP底层的资源:

* getSize()
* tell()
* eof()
* isSeekable()
* seek()
* rewind()
* isWriteable()
* write($string)
* isReadable()
* read($string)
* getContents()
* getMetadata($key = null)

一些请求帮助函数

Slim的PSR 7请求提供了一些特殊的方法,去帮助你检查特殊的HTTP请求

检测XHR请求(个人理解是Ajax请求)

你可以通过请求对象的 isXhr() 方法检测XHR请求,这个方法的作用主要是检测X-Requested-With请求头的存在以及确保这个请求头的值是XMLHttpRequest

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->isXhr()) {
// Do something
}

Content type

你可以通过通过请求对象的 getContentType() 方法获得HTTP 请求的Content type,这个函数返回客户端那边传过来的Content type的值

$contentType = $request->getContentType();

示例:

application/x-www-form-urlencoded

Media Type

也许你要的不是 Content type的值,你只是想要 Media Type 的值,你可以通过通过请求对象的 getMediaType() 方法获得HTTP 请求的Media Type

$mediaType = $request->getMediaType();

你也可以通过方法getMediaTypeParams()获得数组形式的参数值

$mediaParams = $request->getMediaTypeParams();

Character Set

最常用的一个Media类型参数就是字符串了,Slim请求对象提供了一个专用的方法去检索这个值

$charset = $request->getContentCharset();

Content 长度

你可以通过方法 getContentLength() 获取请求值的长度

$length = $request->getContentLength();

路由对象

有时候,在中间件里面需要参数

在这个示例里面我们首先验证用户是否登陆,其次验证用户是否有权限查看视频

$app->get('/course/{id}', Video::class.":watch")->add(Permission::class)->add(Auth::class);

//.. In the Permission Class's Invoke
/** @var $route \Slim\Route */
$route = $request->getAttribute('route');
$courseId = $route->getArgument('id');

文档翻译的并不是很专业,仅供个人学习作用,建议看官方文档。

如有兴趣,请看下一篇 SLIM 3 文档(八)-响应(RESPONSE)6)