Flash Messages

最后更新于:2022-04-01 22:34:24

# Flash Messages Coming soon.
';

CSRF 保护

最后更新于:2022-04-01 22:34:22

# CSRF 保护 [Edit This Page](https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/features/csrf.md) Slim 3 使用独立可选的 PHP 组件 [slimphp/Slim-Csrf](https://github.com/slimphp/Slim-Csrf) 来保护应用程序免遭 CSRF(跨站请求伪造)。本组件为每个请求生成一个唯一 token ,验证来源于客户端 HTML 表单产生的 POST 请求。 ## 安装 在你的项目的根目录下执行这个bash命令: ``` composer require slim/csrf ``` ## 用法 这个 `slimphp/Slim-Csrf` 组件包含一个应用程序中间件。像这样将它添加到你的应用程序中: ``` // Add middleware to the application $app = new \Slim\App; $app->add(new \Slim\Csrf\Guard); // Create your application routes... // Run application $app->run(); ``` ## 提取 CSRF token 的名称和值 最新的 CSRF token 作为 PSR7 请求对象的属性,其名称和值是可获取的。每个请求的CSRF token 都是唯一的。你可以像这样提取当前的 CSRF token 的名称和值: ``` $app->get('/foo', function ($req, $res, $args) { // Fetch CSRF token name and value $name = $req->getAttribute('csrf_name'); $value = $req->getAttribute('csrf_value'); // TODO: Render template with HTML form and CSRF token hidden field }); ``` 你应该将 CSRF token 的名称和值船体给模板,这样它们就能和 HTML 表单 POST 请求一起被提交。它们经常被存储为 HTML 表单的一个隐藏字段。
';

HTTP 缓存

最后更新于:2022-04-01 22:34:19

# HTTP 缓存 [Edit This Page](https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/features/caching.md) Slim 3 使用 [slimphp/Slim-HttpCache](https://github.com/slimphp/Slim-HttpCache) 这款独立的 PHP 组件作为可选的 HTTP 缓存工具。可以使用这个组件创建并返回包含 `Cache`, `Expires`, `ETag`, 和 `Last-Modified` 头的 HTTP 响应,以控制何时以及如何使用客户端缓存保留应用程序的输出。 ## 安装 在你的项目的根目录下执行这个bash命令: ``` composer require slim/http-cache ``` ## 用法 这个 `slimphp/Slim-HttpCache` 组件包含一个服务提供程序和一个应用程序中间件。你必须在你的应用程序中添加这两个玩意,像这样: ``` // Register service provider with the container $container = new \Slim\Container; $container['cache'] = function () { return new \Slim\HttpCache\CacheProvider(); }; // Add middleware to the application $app = new \Slim\App($container); $app->add(new \Slim\HttpCache\Cache('public', 86400)); // Create your application routes... // Run application $app->run(); ``` ## ETag 使用服务提供程序的 `withEtag()` 方法创建一个带有指定 `ETag` 头的响应对象。这个方法接收一个 PSR7 响应对象,而且它返回一个带有新 HTTP 头的 PSR7 响应的拷贝。 ``` $app->get('/foo', function ($req, $res, $args) { $resWithEtag = $this->cache->withEtag($res, 'abc'); return $resWithEtag; }); ``` ## Expires 使用服务提供程序的 `withExpires()` 方法创建一个带有指定 `Expires` 头的响应对象。这个方法接收一个 PSR7 响应对象,而且它返回一个带有新的 HTTP 头的 PSR7 响应的拷贝。 ``` $app->get('/bar',function ($req, $res, $args) { $resWithExpires = $this->cache->withExpires($res, time() + 3600); return $resWithExpires; }); ``` ## Last-Modified 使用服务提供程序的`withLastModified()` 方法创建一个带有指定 `Last-Modified` 头的响应对象。这个方法接收一个 PSR7 响应对象,而且它返回一个带有新 HTTP 头的 PSR7 响应的拷贝。 ``` //Example route with LastModified $app->get('/foobar',function ($req, $res, $args) { $resWithLastMod = $this->cache->withLastModified($res, time() - 3600); return $resWithLastMod; }); ```
';

模板

最后更新于:2022-04-01 22:34:17

# 模板 Slim 没有传统 MVC 框架的视图(view)层。相反,Slim 的“视图”就是 HTTP 响应。Slim 应用程序的每个路由都为准备和返回恰当的 PSER 7 响应对象负责。 > Slim’s “view” is the HTTP response. 话虽如此,但 Slim 项目提供了 [Twig-View](#the-slimtwig-view-component) 和 [PHP-View](#the-slimphp-view-component) 组件帮助你将模版渲染为 PSR7 响应对象。 ## The slim/twig-view 组件 [Twig-View](https://github.com/slimphp/Twig-View) PHP 组件帮助你渲染应用程序中的 [Twig](http://twig.sensiolabs.org/) 模版。这个组件可以在 Packageist 上找到。可以像这样使用 composer 轻易地安装: ``` composer require slim/twig-view ``` Figure 1: Install slim/twig-view component. 下一步,你需要在 Slim 应用容器中将此组将注册为服务,像这样: ``` getContainer(); // Register component on container $container['view'] = function ($container) { $view = new \Slim\Views\Twig('path/to/templates', [ 'cache' => 'path/to/cache' ]); $view->addExtension(new \Slim\Views\TwigExtension( $container['router'], $container['request']->getUri() )); return $view; }; ``` Figure 2: Register slim/twig-view component with container. 记住:“cache” 可以设置为 false 禁用它,‘auto_reload’ 选项也是如此,这在开发环境中很有用。了解更多信息,查阅: [Twig environment options](http://twig.sensiolabs.org/api/master/Twig_Environment.html#method___construct) 现在你可以使用应用程序内部的 `slim/twig-view` 组件服务并将其写入到 PSR 7 响应对象中,像这样: ``` // Render Twig template in route $app->get('/hello/{name}', function ($request, $response, $args) { return $this->view->render($response, 'profile.html', [ 'name' => $args['name'] ]); })->setName('profile'); // Run app $app->run(); ``` Figure 3: Render template with slim/twig-view container service. 在这个例子中,在路由回调中被调用的 `$this->view`,是容器服务返回的 `\Slim\Views\Twig` 实例的一个参考(reference)。`\Slim\Views\Twig` 实例的 `render()` 方法接收一个 PSR7 响应对象作为它的第一个参数,Twig 模版路径作为它的第二个参数,模板变量的数组作为它的最后一个参数。这个 `render()` 方法返回一个新的 PSR7 响应对象,它的响应体是由 Twig 模版渲染的。 ### path_for() 方法 `slim/twig-view` 组件为 Twig 模版暴露了一个自定义 `path_for()` 函数。你可以使用这个函数生成完整的指向应用程序中任意已命名路由的 URL。`path_for()` 函数接收两个参数: 1. 路由名称 2. 路由占位符和替换值的散列(hash) 第二个参数的关键字须与已选择的路由的模式占位符一致。这是一个示例的 Twig 模版,它描述了上面的示例 Slim 应用程序中的 “profile” 路由的链接 URL。 ``` {% extends "layout.html" %} {% block body %}

User List

{% endblock %} ``` ## slim/php-view 组件 [PHP-View](https://github.com/slimphp/PHP-View) PHP 组件帮助你渲染 PHP 模版。该组件可以在 Packagist 上找到,像这样使用 Composer 安装: ``` composer require slim/php-view ``` Figure 4: Install slim/php-view component. 在 Slim App 的容器中,将此组件注册为服务,这么做: ``` getContainer(); // Register component on container $container['view'] = function ($container) { return new \Slim\Views\PhpRenderer('path/to/templates/with/trailing/slash/'); }; ``` Figure 5: Register slim/php-view component with container. 使用 view 组件渲染 PHP 视图: ``` // Render Twig template in route $app->get('/hello/{name}', function ($request, $response, $args) { return $this->view->render($response, 'profile.html', [ 'name' => $args['name'] ]); })->setName('profile'); // Run app $app->run(); ``` Figure 6: Render template with slim/twig-view container service. ## 其他模版系统 并不限于使用 `Twig-View` 和 `PHP-View` 组件。你可以使用任意 PHP 模版系统,只要它能渲染你的模版,并最终输出到 PSR7 响应对象的 body 中。
';

附加组件

最后更新于:2022-04-01 22:34:15

# 附加组件
';

在 Slim 中使用 Eloquent

最后更新于:2022-04-01 22:34:13

# 在 Slim 中使用 Eloquent 你可以使用 [Eloquent](https://laravel.com/docs/5.1/eloquent) 这种数据库 ORM 将你的 Slim 应用程序连接到数据库。 ## 为你的应用程序添加 Eloquent ``` composer require illuminate/database "~5.1" ``` Figure 1: Add Eloquent to your application. ## 配置 Eloquent 在 Slim 的 setting 数组中添加数据库设置项。 ``` [ // Slim Settings 'determineRouteBeforeAppMiddleware' => false, 'displayErrorDetails' => true, 'db' => [ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'database', 'username' => 'user', 'password' => 'password', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ] ], ]; ``` Figure 2: Settings array. 在 `dependencies.php` 中,或者其他任意位置添加你的 Service Factories: ``` // Service factory for the ORM $container['db'] = function ($container) { $capsule = new \Illuminate\Database\Capsule\Manager; $capsule->addConnection($container['settings']['db']); $capsule->setAsGlobal(); $capsule->bootEloquent(); return $capsule; }; ``` Figure 3: Configure Eloquent. ## 传递数据表实例到控制器 ``` $container[App\WidgetController::class] = function ($c) { $view = $c->get('view'); $logger = $c->get('logger') $table = $c->get('db')->table('table_name'); return new \App\WidgetController($view, $logger, $table); }; ``` Figure 4: Pass table object into a controller. ## 从控制器中查询数据表 ``` view = $view; $this->logger = $logger; $this->table = $table; } public function __invoke(Request $request, Response $response, $args) { $widgets = $this->table->get(); $this->view->render($response, 'app/index.twig', [ 'widgets' => $widgets ]); return $response; } } ``` Figure 5: Sample controller querying the table. ### 使用 where 查询数据表 ``` ... $records = $this->table->where('name', 'like', '%foo%')->get(); ... ``` Figure 6: Query searching for names matching foo. ### 通过 id 查询数据表 ``` ... $record = $this->table->find(1); ... ``` Figure 7: Selecting a row based on id. ## 了解更多 [Eloquent](https://laravel.com/docs/5.1/eloquent) 文档
';

检索当前路由

最后更新于:2022-04-01 22:34:10

# 检索当前路由 如果你需要在应用程序中获取当前的路由,你所需要做但就是,调用 HTTP 请求类的带有 `'route'` 参数的 `getAttribute` 方法,它将返回当前的路由,这个路由是 `Slim\Route` 类的实例。class. 可以使用 `getName()` 获取路由的名称,或者使用 `getMethods()`获取此路由支持的方法, etc。 Note: 如果你需要在 app 中间件中访问路由,必须在配置中将 `'determineRouteBeforeAppMiddleware'` 设置为 true。否则,`getAttribute('route')` 将会返回 null。该路由在路由中间件中永远可用。 Example: ``` use Slim\Http\Request; use Slim\Http\Response; use Slim\App; $app = new App([ 'settings' => [ // Only set this if you need access to route within middleware 'determineRouteBeforeAppMiddleware' => true ] ]) // routes... $app->add(function (Request $request, Response $response, callable $next) { $route = $request->getAttribute('route'); $name = $route->getName(); $groups = $route->getGroups(); $methods = $route->getMethods(); $arguments = $route->getArguments(); // do something with that information return $next($request, $response); }); ```
';

检索 IP 地址

最后更新于:2022-04-01 22:34:08

# 检索 IP 地址 检索客户端当前 IP 地址的最佳方式,是利用使用了类似 [rka-ip-address-middleware](https://github.com/akrabat/rka-ip-address-middleware) 这种组件的中间件。 这个组件可以通过 composer 来安装: ``` composer require akrabat/rka-ip-address-middleware ``` 要使用这个组件,需要使用 `App` 注册中间件,这里提供了一个可信赖的代理列表(e.g. varnish 服务器), 如果你再使用它们: ``` $checkProxyHeaders = true; $trustedProxies = ['10.0.0.1', '10.0.0.2']; $app->add(new RKA\Middleware\IpAddress($checkProxyHeaders, $trustedProxies)); $app->get('/', function ($request, $response, $args) { $ipAddress = $request->getAttribute('ip_address'); return $response; }); ``` 这个中间件把客户端 IP 地址存储在一个 HTTP 请求属性中,所以需要通过 `$request->getAttribute('ip_address')` 来访问。
';

以 / 结尾的路由模式

最后更新于:2022-04-01 22:34:06

# 以 / 结尾的路由模式 [Edit This Page](https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/cookbook/route-patterns.md) Slim 处理带有斜线结尾的 URL 和不带斜线的 URL 的方式不同。意思就是 `/user` 和 `/user/` 不是一回事,它们可以有不同的回调。 如果你想通过重定向让所有以 `/` 结尾的 URL 和不以 `/` 结尾的 URL 相等,你可以添加这个中间件: ``` use Psr\Http\Message\RequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; $app->add(function (Request $request, Response $response, callable $next) { $uri = $request->getUri(); $path = $uri->getPath(); if ($path != '/' && substr($path, -1) == '/') { // permanently redirect paths with a trailing slash // to their non-trailing counterpart $uri = $uri->withPath(substr($path, 0, -1)); return $response->withRedirect((string)$uri, 301); } return $next($request, $response); }); ``` 或者,也可以使用 [oscarotero/psr7-middlewares’ TrailingSlash](//github.com/oscarotero/psr7-middlewares#trailingslash) 中间件强制为所有 URL 添加结尾的斜线: ``` use Psr7Middlewares\Middleware\TrailingSlash; $app->add(new TrailingSlash(true)); // true 则添加结尾斜线 (false 移除斜线) ```
';

烹饪书

最后更新于:2022-04-01 22:34:04

# 烹饪书
';

405 Not Allowed 处理器

最后更新于:2022-04-01 22:34:01

# 405 Not Allowed 处理器 [Edit This Page](https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/handlers/not-allowed.md) 如果你的 Slim 框架应用程序有一个路由匹配到了当前的 HTTP 请求 URI **而非 HTTP 请求方法**,程序将调用 Not Allowed 处理器并返回一个 `HTTP/1.1 405 Not Allowed` 响应到 HTTP 客户端。 ## 默认的 Not Allowed 处理器 每个 Slim 框架应用程序都有一个默认的 Not Allowed 处理器。该处理器将 HTTP 响应状态设置为 `405`,将内容类型设置为 `text/html`,它还会添加一个包含由逗号分隔的已被允许访问的 HTTP 方法组成的列表的 `Allowed:` HTTP 头它还会在 HTTP 响应体中写入一个简单的注释。 ## 自定义 Not Allowed 处理器 Slim 框架应用程序的 Not Allowed 处理器是一个 Pimple 服务。你可以通过应用程序容器对自定义 Pimple factory 方法进行定义,来创建自定义的 Not Allowed 处理器取代默认的 ``` // Create Slim $app = new \Slim\App(); // get the app's di-container $c = $app->getContainer(); $c['notAllowedHandler'] = function ($c) { return function ($request, $response, $methods) use ($c) { return $c['response'] ->withStatus(405) ->withHeader('Allow', implode(', ', $methods)) ->withHeader('Content-type', 'text/html') ->write('Method must be one of: ' . implode(', ', $methods)); }; ``` > **注意** Check out [Not Found](/docs/handlers/not-found.html) docs for pre-slim creation method using a new instance of `\Slim\Container` 在这个例子中,我们定义了一个新的 `notAllowedHandler` factory ,它将返回一个 callable 。返回的 callable 接收两个参数: 1. 一个 `\Psr\Http\Message\ServerRequestInterface` 实例 2. 一个 `\Psr\Http\Message\ResponseInterface` 实例 3. 一个由已允许访问的 HTTP 方法名组成的数组 这个 callable **必须** 返回一个恰当的 `\Psr\Http\Message\ResponseInterface` 实例。
';

404 Not Found 处理器

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

# 404 Not Found 处理器 [Edit This Page](https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/handlers/not-found.md) 如果你的 Slim 应用程序没有可以匹配到当前 HTTP 请求 URI 的路由,程序会调用 Not Found 处理器,并返回一个 `HTTP/1.1 404 Not Found` 响应到 HTTP 客户端。 ## 默认的 Not Found 处理器 每个 Slim 框架应用程序都有一个默认的 Not Found 处理器。这个处理器将响应状态设置为 `404`,并将内容类型设置为 `text/html` ,它将写入一个简单的异常信息到响应体。 ## 自定义 Not Found 处理器 Slim 框架应用程序的 Not Found 处理器是一个 Pimple 服务。 你可以通过应用程序容器对自定义 Pimple factory 方法进行定义,来创建自定义的 Not Found 处理器取代默认的。 ``` $c = new \Slim\Container(); //Create Your container //Override the default Not Found Handler $c['notFoundHandler'] = function ($c) { return function ($request, $response) use ($c) { return $c['response'] ->withStatus(404) ->withHeader('Content-Type', 'text/html') ->write('Page not found'); }; }; //Create Slim $app = new \Slim\App($c); //... Your code ``` 在这个例子中,我们定义了一个新的 `notFoundHandler` factory ,它将返回一个 callable 。返回的 callable 接收2个参数: 1. 一个 `\Psr\Http\Message\ServerRequestInterface` 实例 2. 一个 `\Psr\Http\Message\ResponseInterface` 实例 这个 callable **必须** 返回一个恰当的 `\Psr\Http\Message\ResponseInterface` 实例。
';

500 系统错误处理器

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

# 500 系统错误处理器 [Edit This Page](https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/handlers/error.md) 出问题了!你并不能预知错误,但你可以预料到。每个 Slime 框架应用程序都有一个错误处理器用于接收所有未抓取的 PHP 异常。这个错误处理器同样能接收当前 HTTP 的请求对象和响应对象。这个错误处理器必须预备并返回一个适当的响应对象,这个对象会被返回到 HTTP 客户端。 ## 默认的错误处理器 默认的错误处理器非常基础。它将响应状态编码设置为 `500`,并将响应内容类型设置为 `text/html`,并将一个通用的错误信息加入到响应体中。 这个对于生产应用_大概_不太合适。强烈建议你实现专用于你的 Slim 应用程序的错误处理器。 默认的错误处理程序还可以包括详细的错误诊断信息。要启用这个功能你需要将 `displayErrorDetails` 设置为 true : ``` $configuration = [ 'settings' => [ 'displayErrorDetails' => true, ], ]; $c = new \Slim\Container($configuration); $app = new \Slim\App($c); ``` ## 自定义错误处理器 Slim 框架应用程序的错误处理器是一种 Pimple 服务。你可以通过应用程序容器对自定义 Pimple factory 方法进行定义,来创建自定义的错误处理器取代默认的。 有两种注入处理器的方法: ### Pre App ``` $c = new \Slim\Container(); $c['errorHandler'] = function ($c) { return function ($request, $response, $exception) use ($c) { return $c['response']->withStatus(500) ->withHeader('Content-Type', 'text/html') ->write('Something went wrong!'); }; }; $app = new \Slim\App($c); ``` ### Post App ``` $app = new \Slim\App(); $c = $app->getContainer(); $c['errorHandler'] = function ($c) { return function ($request, $response, $exception) use ($c) { return $c['response']->withStatus(500) ->withHeader('Content-Type', 'text/html') ->write('Something went wrong!'); }; }; ``` 在这个例子中,我们定义了一个新的 `errorHandler` factory ,它将返回一个 callable 。返回的 callable 接收三个参数: 1. 一个 `\Psr\Http\Message\ServerRequestInterface` 实例 2. 一个 `\Psr\Http\Message\ResponseInterface` 实例 3. 一个 `\Exception` 实例 这个 callable **必须** 返回一个新的 `\Psr\Http\Message\ResponseInterface` 实例,对于给定的异常也是如此。 **务必注意**:下面这三个类型的异常不会被自定义的 `errorHandler` 处理: * `Slim\Exception\MethodNotAllowedException`: 这个可以用自定义的 [`notAllowedHandler`](/docs/handlers/not-allowed.html) 来处理。 * `Slim\Exception\NotFoundException`: 这个可以用自定义的 [`notFoundHandler`](/docs/handlers/not-found.html) 来处理。 * `Slim\Exception\SlimException`: 这种类型的异常是 Slim 内置的,它的处理不能被覆写。 ### 禁用 要想彻底地禁用 Slim 的错误处理器,只需从容器中移除错误处理器即可: ``` unset($app->getContainer()['errorHandler']); ``` 现在,你需要负责处理所有异常了,因为 Slim 已经不再处理它们。
';

错误处理

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

# 错误处理
';

路由

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

# 路由 Slim 框架的路由基于 [nikic/fastroute](https://github.com/nikic/FastRoute) 组件进行构建,它格外地快速稳定。 ## 如何创建路由 你在可以使用 `\Slim\App` 实例的代理(proxy)方法来定义应用程序路由。Slim 框架提供了最流行的HTTP方法。 ### Get 路由 使用 Slim 应用程序的 `get()` 方法添加一个只处理 `GET` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->get('/books/{id}', function ($request, $response, $args) { // Show book identified by $args['id'] }); ``` ### POST 路由 使用 Slim 应用程序的 `post()` 方法添加一个只处理 `POST` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->post('/books', function ($request, $response, $args) { // Create new book }); ``` ### PUT 路由 使用 Slim 应用程序的 `put()` 方法添加一个只处理 `PUT` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->put('/books/{id}', function ($request, $response, $args) { // Update book identified by $args['id'] }); ``` ### DELETE 路由 使用 Slim 应用程序的 `delete()` 方法添加一个只处理 `DELETE` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->delete('/books/{id}', function ($request, $response, $args) { // Delete book identified by $args['id'] }); ``` ### OPTIONS 路由 使用 Slim 应用程序的 `options()` 方法添加一个只处理 `OPTIONS` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->options('/books/{id}', function ($request, $response, $args) { // Return response headers }); ``` ### PATCH 路由 使用 Slim 应用程序的 `patch()` 方法添加一个只处理 `PATCH` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->patch('/books/{id}', function ($request, $response, $args) { // Apply changes to book identified by $args['id'] }); ``` ### 任意路由 使用 Slim 应用程序的 `any()` 方法添加一个可以处理处理所有 HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->any('/books/[{id}]', function ($request, $response, $args) { // Apply changes to books or book identified by $args['id'] if specified. // To check which method is used: $request->getMethod(); }); ``` 记住,第二个参数是一个回调。你需要指定一个类(Class,需要一个 `__invoke()` 实现方法。)来替换闭包(Closure)。接着,你可以映射到其他位置: ``` $app->any('/user', 'MyRestfulController'); ``` ### 自定义路由 使用 Slim 应用程序的 `map()` 方法来添加一个可以处理多个 HTTP 请求方法的路由。它接收三个参数: 1. HTTP 方法的数组 2. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 3. 路由回调 ``` $app = new \Slim\App(); $app->map(['GET', 'POST'], '/books', function ($request, $response, $args) { // Create new book or list all books }); ``` ## 路由回调 上述的每个路由方法都接收一个回调例程作为其最后一个参数。这个参数可以是任意 PHP 调用(callable),并且它默认接受三个参数。 **请求/Request** 第一个参数是一个 `Psr\Http\Message\ServerRequestInterface` 对象,表示当前的 HTTP 请求。 **响应/Response** 第二个参数是一个 `Psr\Http\Message\ResponseInterface` 对象,表示当前的 HTTP 响应。 **参数数组/Arguments** 第三个参数是一个关联数组,包含包含当前路由的命名占位符。 ### 将内容写入响应 有两种方式可以将内容写入 HTTP 响应。第一钟,可以使用 `echo()` 简单地从路由回调中输出内容。其内容将会呗追加到当前 HTTP 请求对象中。第二种,你可以返回一个 `Psr\Http\Message\ResponseInterface` 对象。 ### 闭包绑定/Closure binding 如果你使用一个`闭包(Closure)`实例作为路由回调,闭包的状态受`Container`实例约束。这意味着你将通过 `$this` 关键字访问闭包内部的 DI 容器实例: ``` $app = new \Slim\App(); $app->get('/hello/{name}', function ($request, $response, $args) { // Use app HTTP cookie service $this->get('cookies')->set('name', [ 'name' => $args['name'], 'expires' => '7 days' ]); }); ``` ## 路由策略 路由回调签名由路由策略决定。默认地,Slim 寄望路由回调来接收请求、响应和由路由占位符参数组成的数组。这称为请求响应策略(RequestResponse strategy)。然而,你可以通过使用另一个不同策略来改变这种寄望。例如,Slim 提供了一个另类的策略,叫做 RequestResponseArgs ,它接收请求和响应,加上由每一个路由占位符组成的单独参数。这里的例子展示了如何使用这个另类的策列;轻松替代了默认`\Slim\Container`提供的 `foundHandler` 依赖: ``` $c = new \Slim\Container(); $c['foundHandler'] = function() { return new \Slim\Handlers\Strategies\RequestResponseArgs(); }; $app = new \Slim\App($c); $app->get('/hello/{name}', function ($request, $response, $name) { return $response->write($name); }); ``` 通过实现 `\Slim\Interfaces\InvocationStrategyInterface` 你可以提供一个你自己的路由策略。 ## 路由占位符 上诉的每个路由方法都会收到一个 URL 模式(URL pattern),它将与当前 HTTP 请求的 URI 相匹配。路由模式将使用命名占位符(named placeholder)来动态匹配 HTTP 请求的URI 片段。 ### 格式 路由模式占位符起始与一个 `{`, 然后是占位符名称, 最后以 `}` 结束。这是一个名为 `name` 的占位符例子: ``` $app = new \Slim\App(); $app->get('/hello/{name}', function ($request, $response, $args) { echo "Hello, " . $args['name']; }); ``` ### 可选的分段 / Optional segments 使一个片段可选,只需用将其放在方括号中: ``` $app->get('/users[/{id}]', function ($request, $response, $args) { // reponds to both `/users` and `/users/123` // but not to `/users/` }); ``` 支持多个可选参数嵌套: ``` $app->get('/news[/{year}[/{month}]]', function ($request, $response, $args) { // reponds to `/news`, `/news/2016` and `/news/2016/03` }); ``` 对于数目不确定的可选参数,可以这样做: ``` $app->get('/news[/{params:.*}]', function ($request, $response, $args) { $params = explode('/', $request->getAttribute('params')); // $params is an array of all the optional segments }); ``` 在这个例子中,`/news/2016/03/20` 的 URI 将使得 `$params` 数组包含三个元素:`['2016', '03', '20']`. ### 正则表达式匹配 默认地,占位符被写在 `{}` 之中,并可以接收任意值。然而,占位符同样可以要求 HTTP 请求 URI 匹配特定的正则表达式。如果当前的HTTP 请求URI 不能与占位符的正则表达式匹配,路由路由将不会启动。下面这个示例占位符要求 `id` 必须是个数字: ``` $app = new \Slim\App(); $app->get('/users/{id:[0-9]+}', function ($request, $response, $args) { // Find user identified by $args['id'] }); ``` ## 路由名称 应用程序的路由可以被指定一个名称。这非常有用,如果你想要使用路由的 `pathFor()` 方法以编程的形式生成一个特定路由的 URL 。上述的每个路由方法都会返回一个 `\Slim\Route` 对象,这个对象带来了 `setName()` 方法。 ``` $app = new \Slim\App(); $app->get('/hello/{name}', function ($request, $response, $args) { echo "Hello, " . $args['name']; })->setName('hello'); ``` 使用应用程序路由的 `pathFor()` 方法,为已命名的路由生成一个 URL 。 ``` echo $app->router->pathFor('hello', [ 'name' => 'Josh' ]); // Outputs "/hello/Josh" ``` 路由的 `pathFor()` 方法接收两个参数: 1. 路由名称 2. 由路由模式占位符及替换值组成的关联数组。 ## 路由组 为了帮助将路由整理成条理分明的路由组, `\Slim\App` 还提供了一个 `group()` 方法。 每个路由组的路由模式预置于路由或路由组中的路由组,路由组模式的任何占位符参数最终使得嵌套的路由都是可用的: ``` $app = new \Slim\App(); $app->group('/users/{id:[0-9]+}', function () { $this->map(['GET', 'DELETE', 'PATCH', 'PUT'], '', function ($request, $response, $args) { // Find, delete, patch or replace user identified by $args['id'] })->setName('user'); $this->get('/reset-password', function ($request, $response, $args) { // Route for /users/{id:[0-9]+}/reset-password // Reset the password for user identified by $args['id'] })->setName('user-password-reset'); }); ``` 记住,在路由组闭包的内部,使用 `$this` 替代 `$app` 。Slim 将闭包绑定到应用程序实例,就像路由回调的情况那样。 ## 路由中间件 你可以将中间件与任意路由或路由组相连接。 [了解更多](/docs/concepts/middleware.html). ## 容器识别 / Container Resolution 你不必限于为路由定义函数。在 Slim 中,有一些不同的方式来定义你的路由行为函数。 除了函数外,你还可以使用: - 可调用的类 - `Class:method` 这个函数由 Slim 的 Callable 解角器(Resolver) 类提供支持。它将字符串入口(entry)转变为函数调用。例如: ``` $app->get('/home', '\HomeController:home'); ``` 在上面这段代码中,我们定义了一个 `/home` 路由,并告诉 Slim 执行 `\HomeController` 类中的 `home()` 方法。 Slim 首先在容器中寻找 `\HomeController` 的入口,如果找到了,它将使用该实例。否则,它将它的构造函数,并将容器作为第一个参数。一旦这个类的实例创建了,它将使用你已定义的策略(Strategy)去调用指定的方法。 作为另一种办法,你可以使用一个可调用的(invokable)类,比如: ``` class MyAction { protected $ci; //Constructor public function __construct(ContainerInterface $ci) { $this->ci = $ci; } public function __invoke($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } } ``` 你可以这样使用这个累: ``` $app->get('/home', '\MyAction'); ``` 在更为传统的 MVC 方法中,你构建包含许多行为(actions)的控制器来替代只能处理一个行为的可调用类。 ``` class MyController { protected $ci; //Constructor public function __construct(ContainerInterface $ci) { $this->ci = $ci; } public function method1($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } public function method2($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } public function method3($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } } ``` 你可以这样使用控制器方法: ``` $app->get('/method1', '\MyController:method1'); $app->get('/method2', '\MyController:method2'); $app->get('/method3', '\MyController:method3'); ```
';

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 状态码也会被替换。
';

HTTP 请求

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

# HTTP 请求 Slim 应用程序的路由和中间件给出了一个 PSR 7 请求对象,它表示当前的 HTTP 请求是由 Web 服务器 接收到的。该请求对象遵循 [PSR 7 服务器请求接口(ServerRequestInterface )](http://www.php-fig.org/psr/psr-7/#3-2-1-psr-http-message-serverrequestinterface) 实现,因此你可以检查和操作该 HTTP 请求对象的方法、头和体。 ## 如何获取请求对象 该 PSR 7 请求对象作为路由回调的第一个参数注入到你的 Slim 应用程序的路由中,像这样: ``` get('/foo', function (ServerRequestInterface $request, ResponseInterface $response) { // 使用 PSR 7 $request 对象 return $response; }); $app->run(); ``` Figure 1: 将 PSR 7 请求注入到应用程序的路由回调中。 该 PSR 7 请求对象作为中间件 callable 的第一个参数注入到 Slim 应用程序的_中间件_中,像这样: ``` add(function (ServerRequestInterface $request, ResponseInterface $response, callable $next) { // Use the PSR 7 $request object return $next($request, $response); }); // Define app routes... $app->run(); ``` Figure 2: 注入 PSR 7 请求到应用程序中间件 ## 请求的方法 每个 HTTP 请求都有相应的方法,通常是这些中的一个: * GET * POST * PUT * DELETE * HEAD * PATCH * OPTIONS 你可以恰当地使用 `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 请求方法。这非常有用,例如你需要在一个只支持 `GET` 或 `POST` 请求的传统浏览器中模拟一个 `PUT` 请求。 有两种方法来覆写 HTTP 请求方法。你可以在一个 `POST` 请求体中引入(include)一个 `_METHOD` 参数。该 HTTP 请求必须使用 `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 ``` Figure 3: 使用 _METHOD 参数覆写 HTTP 请求。 你也可以使用自定义的 `X-Http-Method-Override` HTTP请求头来覆写 HTTP 请求方法。这个方式可以用于任意 HTTP 请求内容类型(content type)。 ``` POST /path HTTP/1.1 Host: example.com Content-type: application/json Content-length: 16 X-Http-Method-Override: PUT {"data":"value"} ``` Figure 4: 使用 X-Http-Method-Override 请求头覆写 HTTP 方法。 你可以使用 PSR 7 请求对象的方法 `getOriginalMethod()` 来提取_原有_ (不是覆写后的)的 HTTP 方法。 ## 请求 URI 每个 HTTP 请求都有一个识别被请求的应用程序资源的 URI 。HTTP 请求 URI 分为这几部分: * Scheme (e.g. `http` or `https`) * Host (e.g. `example.com`) * Port (e.g. `80` or `443`) * Path (e.g. `/users/1`) * Query string (e.g. `sort=created&dir=asc`) 你可以使用 `getUri()` 方法来提取 PSR 7 请求对象的 URI : ``` $uri = $request->getUri(); ``` PSR 7 请求对象的 URI 本身就是一个对象,提供了以下方法来检查 HTTP 请求的 URL : * `getScheme()` * `getAuthority()` * `getUserInfo()` * `getHost()` * `getPort()` * `getPath()` * `getBasePath()` * `getQuery()` <small>(返回整个查询字符串,e.g. `a=1&b=2`)</small> * `getFragment()` * `getBaseUrl()` **基准路径**如果你的 Slim 应用程序的前端控制器放置在文件根目录的物理子目录中,你可以使用 URI 对象的 `getBasePath()` 方法来提取 HTTP 请求的物理基准路径(相对于文件根目录)。如果 Slim 应用程序安装在文件根目录的最上层目录中,它将返回一个空字符串。 ## 请求头 每个 HTTP 请求都有请求头。这些元数据描述了 HTTP 请求,但在请求体中不可见。Slim 的 PSR 7 请求对象提供了几个检查请求头的方法。 ### 获取所有请求头 使用 PSR 7 请求对象的`getHeaders()`方法提取所有 HTTP 请求头并放入一个关联数组中。此关联数组的键值是请求头的名称,其值是各请求头对应的由字符串值组成的数值数组。 ``` $headers = $request->getHeaders(); foreach ($headers as $name => $values) { echo $name . ": " . implode(", ", $values); } ``` Figure 5: 提取并迭代所有 HTTP 请求头作为一个关联数组。 ### 获取单个请求头 你可以使用 PSR 7 请求对象的 `getHeader($name)` 方法获取一个单独的请求头的值。它将返回一个由指定请求头名称对应的值组成的数组。记住,单独的请求头可不一定只有一个值。 ``` $headerValueArray = $request->getHeader('Accept'); ``` Figure 6: 获取指定 HTTP 请求的值。 你同样可以使用 PSR 7 请求对象的 `getHeaderLine($name)` 方法提取指定请求头的值,并以逗号分隔。这不同于 `getHeader($name)` 方法,这个方法返回一个由逗号分隔的字符串。 ``` $headerValueString = $request->getHeaderLine('Accept'); ``` Figure 7: 获取单个请求头的值,返回逗号分隔的字符串。 ### 检测请求头 使用 PSR 7 请求对象的 `hasHeader($name)` 方法检查某请求头是否存在。 ``` if ($request->hasHeader('Accept')) { // Do something } ``` Figure 8: Detect presence of a specific HTTP request header. ## 请求体 每个 HTTP 请求都有一个请求体。如果你的 Slim 应用程序是通过 JSON 或 XML 数据进行通信的,你可以使用 PSR 7 请求对象的 `getParsedBody()` 方法将 HTTP 请求体解析成原生 PHP 格式。Slim 可以解析 JSON, XML, 和 URL-encoded 数据,开箱即用。 ``` $parsedBody = $request->getParsedBody(); ``` Figure 9: Parse HTTP request body into native PHP format * JSON 请求通过 `json_decode($input)` 转换成 PHP 对象。 * XML 请求通过 `simplexml_load_string($input)` 转换成 `SimpleXMLElement` 。 * URL-encoded 请求通过 `parse_str($input)` 转换成 PHP 数组。 从技术上说,Slim 的 PSR 7 请求对象将 HTTP 请求体表示为 `\Psr\Http\Message\StreamInterface` 的一个实例。你可以通过使用 PSR 7 请求对象的 `getBody()` 方法获取 HTTP 请求体的 `StreamInterface` 实例。该 `getBody()` 方法在处理未知大小或对于可用内存来说太大的 HTTP 请求时,是个很好的方法。 ``` $body = $request->getBody(); ``` Figure 10: 获取 HTTP 请求体 生成的 `\Psr\Http\Message\StreamInterface` 实例提供了以下方法来读取或迭代未知的 `资源(resource)`。 * `getSize()` * `tell()` * `eof()` * `isSeekable()` * `seek()` * `rewind()` * `isWritable()` * `write($string)` * `isReadable()` * `read($length)` * `getContents()` * `getMetadata($key = null)` ## 请求助手/Request Helpers Slim 的 PSR 7 请求实现方法提供了额外的专有方法来帮助你进一步检查 HTTP 请求。 ### 检测 XHR 请求 你可以使用请求对象的 `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 ``` Figure 11: XHR 请求示例. ``` if ($request->isXhr()) { // Do something } ``` ### 内容类型/Content Type 你可以使用请求对象的 `getContentType()` 方法提取 HTTP 请求的内容类型。它将通过 HTTP 客户端返回 `Content-Type` 头的完整值。 ``` $contentType = $request->getContentType(); ``` ### 媒体类型/Media Type 你或许不会想要完整的 `Content-Type` 头。加入说你只想要媒体类型?你可以使用响应对象的 `getMediaType()`方法取得 HTTP 请求的媒体类型。 ``` $mediaType = $request->getMediaType(); ``` 可以使用请求对象的 `getMediaTypeParams()` 方法,以关联数组的形式获取附加的没提类型参数。 ``` $mediaParams = $request->getMediaTypeParams(); ``` ### 字符集/Character Set HTTP 请求字符集是最常用的媒体类型参数之一。请求对象提供了一个专用的方法来获取这个媒体类型参数。 ``` $charset = $request->getContentCharset(); ``` ### 内容长度/Content Length 使用请求对象的 `getContentLength()` 方法获取 HTTP 请求的内容长度。 ``` $length = $request->getContentLength(); ``` ### 路由对象/Route Object 有时在中间件中你需要路由的参数。 在这个例子中,我们首先检查用户是否登录,然后检查用户有否有权限浏览他们正试图浏览的视频。 ``` $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'); ``` ## 媒体类型解析 如果 HTTP 请求的媒体类型被识别,将通过 `$request->getParsedBody()` 解析成为结构化的可用数据。通常是解析成一个数组,或者是 XML 媒体类型的对象。 以下媒体类型是可识别和解析的: * application/x-www-form-urlencoded’ * application/json * application/xml & text/xml 如果你想要用 Slim 来解析其它媒体类型,那么你可以自行解析原生的 HTTP 请求体,或者新注册一个媒体解析器。媒体解析器都是简单的 callable ,它接收一个 `$input` 字符串并返回一个解析后的对象或数组。 在应用程序或者路由中间件中注册新的媒体解析器。注意,你必须在首次尝试访问解析后的 HTTP 请求体前注册该解析器。 例如,要自动解析带有 `text/javascript` 内容类型的 JSON,你可以像这样在中间件中注册媒体解析器: ``` // 添加中间件 $app->add(function ($request, $response, $next) { // add media parser $request->registerMediaTypeParser( "text/javascript", function ($input) { return json_decode($input, true); } ); return $next($request, $response); }); ```
';

Application

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

# Application Application ,(或者 `Slim\App` ) 是你的 Slim 应用程序的入口,它被用于注册那些链接到回调和控制器的路由。 ``` // 实例化 App 对象 $app = new \Slim\App(); // 添加路由回调 $app->get('/', function ($request, $response, $args) { return $response->withStatus(200)->write('Hello World!'); }); // 运行应用 $app->run(); ``` ## Application 配置 Application 只接收一个参数。该参数可以是[容器](/docs/concepts/di.html)实例或者用于配置自动创建的默认容器的数组。 Slim 还用到了一系列的设置项。它们被存放在 `settings` 配置关键字中。你还可以添加你的应用程序私有的设置项。 例如,我们可以将 Slim的设置项 `displayErrorDetails` 设置为 true,并配置 Monolog,像这样: ``` $config = [ 'settings' => [ 'displayErrorDetails' => true, 'logger' => [ 'name' => 'slim-app', 'level' => Monolog\Logger::DEBUG, 'path' => __DIR__ . '/../logs/app.log', ], ], ]; $app = new \Slim\App($config); ``` ### 获取 Settings 由于设置项都被存放在依赖注入容器中,所以你可以通过容器工厂方法(container factories)的 `settings` 关键字来访问它们。例如: ``` $settings = $container->get('settings')['logger']; ``` 还可以在路由回调(route callable)中通过 `$this` 来访问它们: ``` $app->get('/', function ($request, $response, $args) { $loggerSettings = $this->get('settings')['logger']; // ... }); ``` ## Slim 的默认设置 Slim 拥有以下默认设置,你可以按需覆写它们: `httpVersion` [HTTP 响应](/docs/objects/response.html)对象使用的 HTTP 协议版本 (默认: `'1.1'`) `responseChunkSize` 从响应体读取并发送到浏览器的数据包的大小。 (默认: `4096`) `outputBuffering` 当设置为 `false` 时,那么没有输出缓冲被启用。如果 `'append'` 或 `'prepend'`,那么任意 `echo` 或 `print` 状态都会被捕获,并且会 appended 或 prepended 到从路由回调(route callable)中返回的响应中。 (默认: `'append'`) `determineRouteBeforeAppMiddleware` 当设置为 true 时,那么在中间件执行前即已确定路由是否正确。这意味着你如果有需要,可以在中间件中检查路由参数。 (默认: `false`) `displayErrorDetails` 当设置为 true 时, 关于异常的附加信息都会通过 [默认的错误处理器](/docs/handlers/error.html)显示出来。 (默认: `false`)
';

依赖容器(Dependency Container)

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

# 依赖容器(Dependency Container) Slim 使用依赖容器来准备、管理和注入应用程序的相关依赖。Slim 支持 [Container-Interop](https://github.com/container-interop/container-interop) 接口实现的容器。你可以使用 Slim 的内置容器(基于 [Pimple](http://pimple.sensiolabs.org/))或者第三方的容器,比如 [Acclimate](https://github.com/jeremeamia/acclimate-container) 或 [PHP-DI](http://php-di.org/)。 ## 如何使用容器 你并不_必须_提供一个依赖容器。如果你提供了,那么,你必须注入此容器的实例到 Slim 应用程序的构造函数中。 ``` $container = new \Slim\Container; $app = new \Slim\App($container); ``` 你可以显式或隐式地从依赖容器中获取服务。你可以像下面这样子从 Slim 应用程序的路由中获取一个显示的容器实例。 ``` /** * Example GET route * * @param \Psr\Http\Message\ServerRequestInterface $req PSR7 request * @param \Psr\Http\Message\ResponseInterface $res PSR7 response * @param array $args Route parameters * * @return \Psr\Http\Message\ResponseInterface */ $app->get('/foo', function ($req, $res, $args) { $myService = $this->get('myService'); return $res; }); ``` 你可以这样隐式地从容器中取得服务: ``` /** * Example GET route * * @param \Psr\Http\Message\ServerRequestInterface $req PSR7 request * @param \Psr\Http\Message\ResponseInterface $res PSR7 response * @param array $args Route parameters * * @return \Psr\Http\Message\ResponseInterface */ $app->get('/foo', function ($req, $res, $args) { $myService = $this->myService; return $res; }); ``` Slim uses `__get()` and `__isset()` magic methods that defer to the application’s container for all properties that do not already exist on the application instance. ## 必需的服务 你的容器必须实现这些必需的服务。如果你使用的是 Slim 内置的容器,这些服务都是已经准备好了的。如果你选择使用第三方容器,那么你必须自己来实现这些服务。 settings 应用程序设置项的关联数组(Associative array),包括以下关键字: * `httpVersion` * `responseChunkSize` * `outputBuffering` * `determineRouteBeforeAppMiddleware`. * `displayErrorDetails`. environment `\Slim\Interfaces\Http\EnvironmentInterface` 的实例. request `\Psr\Http\Message\ServerRequestInterface`的实例. response `\Psr\Http\Message\ResponseInterface`的实例. router `\Slim\Interfaces\RouterInterface`的实例. foundHandler `\Slim\Interfaces\InvocationStrategyInterface` 的实例. phpErrorHandler PHP 7 错误被抛出时调用的 Callable。这个 callable **必须**返回一个 `\Psr\Http\Message\ResponseInterface` 的实例,并接收三个参数: 1. `\Psr\Http\Message\ServerRequestInterface` 2. `\Psr\Http\Message\ResponseInterface` 3. `\Error` errorHandler 抛出异常时调用的 Callable。这个 callable **必须**返回一个 `\Psr\Http\Message\ResponseInterface` 的实例,并接收三个参数: 1. `\Psr\Http\Message\ServerRequestInterface` 2. `\Psr\Http\Message\ResponseInterface` 3. `\Exception` notFoundHandler 如果当前的 HTTP 请求 URI 未能匹配到应用程序路由,则调用这个 Callable。这个 callable **必须**返回一个 `\Psr\Http\Message\ResponseInterface` 的实例,并接收三个参数: 1. `\Psr\Http\Message\ServerRequestInterface` 2. `\Psr\Http\Message\ResponseInterface` notAllowedHandler 如果一个应用程序路由匹配到当前 HTTP 请求的路径而不是它的方法,则调用这个 Callable。这个 callable **必须** 返回一个 `\Psr\Http\Message\ResponseInterface` 的实例并接收三个参数: 1. `\Psr\Http\Message\ServerRequestInterface` 2. `\Psr\Http\Message\ResponseInterface` 3. Array of allowed HTTP methods callableResolver `\Slim\Interfaces\CallableResolverInterface` 的实例.
';

中间件

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

# 中间件 你可以在你的 Slim 应用_之前(before)_ 和 _之后(after)_ 运行代码来处理你认为合适的请求和响应对象。这就叫做_中间件_。为什么要这么做呢?比如你想保护你的应用不遭受跨站请求伪造。也许你想在应用程序运行前验证请求。中间件对这些场景的处理简直完美。 ## 什么是中间件? 从技术上来讲,中间件是一个接收三个参数的_可回调(callable)_对象: 1. `\Psr\Http\Message\ServerRequestInterface` - PSR7 请求对象 2. `\Psr\Http\Message\ResponseInterface` - PSR7 响应对象 3. `callable` - 下一层中间件的回调对象 它可以做任何与这些对象相应的事情。唯一硬性要求就是中间件**必须**返回一个 `\Psr\Http\Message\ResponseInterface` 的实例。 每个中间件都 **应当**调用下一层中间件,并讲请求和响应对象作为参数传递给它(下一层中间件)。 ## 中间件是如何工作的? 不同的框架使用中间件的方式不同。在 Slim 框架中,中间件层以同心圆的方式包裹着核心应用。由于新增的中间件层总会包裹所有已经存在的中间件层。当添加更多的中间件层时同心圆结构会不断的向外扩展。 当 Slim 应用运行时,请求对象和响应对象从外到内穿过中间件结构。它们首先进入最外层的中间件,然后然后进入下一层,(以此类推)。直到最后它们到达了 Slim 应用程序自身。在 Slim 应用分派了对应的路由后,作为结果的响应对象离开 Slim 应用,然后从内到外穿过中间件结构。最终,最后出来的响应对象离开了最外层的中间件,被序列化为一个原始的 HTTP 响应消息,并返回给 HTTP 客户端。下图清楚的说明了中间件的工作流程: ![Middleware architecture](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-23_5629d1b6da0db.png) ## 如何编写中间件? 中间件是一个接收三个参数的可回调(callable)对象,三个参数是:请求对象、响应对象以及下一层中间件。中间件**必须**返回一个 `\Psr\Http\Message\ResponseInterface` 的实例。 ### 闭包中间件示例。 这个示例中间件是一个闭包。 ``` getBody()->write('BEFORE'); $response = $next($request, $response); $response->getBody()->write('AFTER'); return $response; }; ``` ### 可调用类的中间件示例。 这个示例中间件是一个实现了 `__invoke()` 魔术方法的可调用类。 ``` getBody()->write('BEFORE'); $response = $next($request, $response); $response->getBody()->write('AFTER'); return $response; } } ``` 要使用这个类作为中间件,你可以使用 `->add( new ExampleMiddleware() );` 函数连接在 `$app`, `Route`, 或 `group()` 之后,在下面的代码中,它们中的任意一个都可以表示 $subject。 ``` $subject->add( new ExampleMiddleware() ); ``` ## 如何添加中间件? 你可以在 Slim 应用中添加中间件,或者添加到一个单独的 Slim 应用路由,或者是路由组。所有场景都能接受相同的中间件和实现相同的中间件接口。 ### 应用程序中间件 应用程序中间件被每个_传入(incoming)_ HTTP 请求调用。应用中间件可以通过 Slim 应用实例的 `add()` 方法来添加。下面这是一个添加上面那个闭包中间件的例子: ``` add(function ($request, $response, $next) { $response->getBody()->write('BEFORE'); $response = $next($request, $response); $response->getBody()->write('AFTER'); return $response; }); $app->get('/', function ($req, $res, $args) { echo ' Hello '; }); $app->run(); ``` 输出的 HTTP 响应主体为: ``` BEFORE Hello AFTER ``` ### 路由中间件 路由中间件_只有_在当前 HTTP 请求的方法和 URI 都与中间件所在路由相匹配时才会被调用。路由中间件会在你调用了任意 Slim 应用的路由方法(e.g., `get()` 或 `post()`)后被立即指定。 每个路由方法返回一个 `\Slim\Route` 的实例,这个类提供了相同的中间件接口作为 Slim 应用的实例。使用路由实例的 `add()` 方法将中间件添加到路由中。下面这是一个添加上面那个闭包中间件的例子: ``` getBody()->write('BEFORE'); $response = $next($request, $response); $response->getBody()->write('AFTER'); return $response; }; $app->get('/', function ($req, $res, $args) { echo ' Hello '; })->add($mw); $app->run(); ``` 输出的 HTTP 响应主体为: ``` BEFORE Hello AFTER ``` ### Group Middleware 除了整个应用,以及标准的路由可用接收中间件,还有 `group()` 多路由定义功能同样允许在其内部存在独立的路由。路由组中间件_只有_在其路由与已定义的 HTTP 请求和 URI 中的一个相匹配时才会被调用。要在回调中添加中间件,以及整组中间件,通过在 `group()` 方法后面连接 `add()` 来设置。 下面的示例程序,在一组 URL 处理程序(url-handlers)中使用了回调中间件。 ``` get('/', function ($request, $response) { return $response->getBody()->write('Hello World'); }); $app->group('/utils', function () use ($app) { $app->get('/date', function ($request, $response) { return $response->getBody()->write(date('Y-m-d H:i:s')); }); $app->get('/time', function ($request, $response) { return $response->getBody()->write(time()); }); })->add(function ($request, $response, $next) { $response->getBody()->write('It is now '); $response = $next($request, $response); $response->getBody()->write('. Enjoy!'); return $response; }); ``` 在调用 `/utils/date` 方法时,将输出类似下面这样子的字符串: ``` It is now 2015-07-06 03:11:01\. Enjoy! ``` 访问 `/utils/time` 将会输出类似下面这样子的字符串: ``` It is now 1436148762\. Enjoy! ``` 但访问 `/` _域名根目录(domain-root)_时,将会有如下输出,因为并没有分配中间件。 ``` Hello World ```
';