oasis / http

Silex 的扩展,用于 HTTP 相关的路由、中间件等。


README

oasis/http 是一个 composer 组件,提供了一种简单而实用的框架来构建 Web 应用程序。这个组件是对广泛使用的 [Silex 微框架] Silex 的扩展。正如 Silex 所述,oasis/http 同样是一个巨人肩膀上的微框架:SilexSymfonyPimple

安装

使用以下命令安装最新版本

$ composer require oasis/http

Web 服务器配置

本文档中的所有示例都依赖于一个配置良好的 Web 服务器。

请参阅 Silex Web 服务器配置 以获取示例 Web 服务器配置。

基本用法

使用 oasis/http 的第一步是实例化一个 Oasis\Mlib\Http\SilexKernel 对象。

<?php

use Oasis\Mlib\Http\SilexKernel;
use Symfony\Component\HttpFoundation\Response;

$config = [];
$isDebug = true;
$kernel = new SilexKernel($config, $isDebug);

$kernel->get('/', function() {
    return new Response("Hello world!");
});

$kernel->run();

$config 是配置值的数组。一个空的默认值将很好地工作。然而,您可以通过提供详细的 [引导配置] (#bootstrap-configuration) 轻松实例化一个配置良好的内核。

Silex

由于 oasis/http 的核心类 Oasis\Mlib\Http\SilexKernelSilex 的扩展,因此在开始使用 oasis/http 之前,建议您先了解一些有关 Silex 的知识。

引导配置

引导配置可以分为以下几部分

路由

默认情况下,Silex 支持动态添加路由

<?php

use Oasis\Mlib\Http\SilexKernel;

/** @var SilexKernel $kernel */
$kernel->get('/', function() {
    // return Response
});
$kernel->match('/patch', function() {
    // return Response
})->method('PATCH');

然而,上述路由机制的最大的缺点是缺乏缓存能力。因此,oasis/http 使用了 symfony/routing 组件来支持缓存路由。

为了实现这一点,我们需要使用 routing 参数配置引导,并同时提供一个路由 yaml 文件。

<?php

$config = [
    "routing" => [
        "path" => "routes.yml",
        "namespaces" => [
            "Oasis\\Mlib\\TestControllers\\"
        ],
    ],
];

// initialize SilexKernel with $config

《routes.yml》文件看起来像这样

home:
    path: /
    defaults:
        _controller: TestController::homeAction

_controller 属性确定在匹配某些路径时调用的函数。它由一个类名和一个方法名组成,两者由一个 "::" 符号分隔。

注意:除非您指定默认命名空间前缀,否则 _controller 中的类名应该是完全限定的(即包括完整的命名空间前缀)。默认命名空间在 routing 参数的 namespaces 参数下定义。

由于《routes.yml》文件完全符合 symfony,我们可以使用高级路由功能。有关更多信息,请参阅 [高级路由配置] (docs/AdvancedRoutingConfiguration.md)。

安全

当部署Web应用程序时,我们通常会希望保护某些资源(路径、主机等)在安全规则之后。在 oasis/http 中,我们使用 security 引导参数来强制检查传入的请求的安全性。

让我们先简单看一下一个简单的安全配置

<?php

$config = [
    "security" => [
        "firewalls" => [
            "http.auth" => [
                "pattern" => "^/admin/",
                "policies" => [
                    "http" => true
                ],
                "users" => [
                    // raw password is foo
                    'admin' => array('ROLE_ADMIN', '$2y$10$3i9/lVd8UOFIJ6PAMFt8gu3/r5g0qeCJvoSlLCsvMTythye19F77a'),
                ],
            ],
        ],
    ],
];

// initialize SilexKernel with $config

上述示例定义了一个名为 http.auth 的防火墙,它保护以 "/admin/" 开头的路径。将 http 策略设置为 true,所有传入请求都必须有 HTTP Basic 认证。最终,为这个防火墙提供的唯一用户是名为 admin、密码为 'foo' 的用户。

有关更高级的安全方案,请参阅详细安全配置

跨源资源共享

当您的资源被除托管域之外的域名访问时,现代浏览器将执行同源限制检查。默认情况下,请求将静默失败。一般来说,这在大多数情况下是一种安全行为。然而,有时您只想允许这种访问。您可能需要托管字体,以便在 CSS 中使用。您可能需要提供其他 JavaScript 应用程序可访问的 API。这就是为什么我们需要为我们的应用程序配置跨源资源共享(CORS)规则。

oasis/http 中,这已经变得非常简单。

<?php

$config = [
    "security" => [
        "cors" => [
            'pattern' => '^/cors/.*',
            'origins' => ["my.second.domain.tld"],
        ],
    ],
];

// initialize SilexKernel with $config

使用上述配置,任何对以 "/cors/" 开头的路径的请求都将被拒绝,除非它来自 my.second.domain.tld

可以为 CORS 配置更多规则。请参阅此处获取更详细的指南。

渲染模板

MVC 可能是软件开发中最知名的设计模式之一。在 Web 应用程序中,视图层通常使用某种模板引擎实现。 oasis/http 使用 Twig 作为主要的模板引擎。这是与 SilexSymfony 保持一致的决定。

在此文档中,我们将不讨论如何编写 Twig 模板。但下面是一个如何启用 Twig 支持的示例

<?php

/** @var Symfony\Component\Security\Core\User\User $user */
$config = [
    "twig" => [
        "template_dir" => "path to your twig templates",
        "asset_base" => "http://my.domain.tld/assets/",
        "globals" => [
            "user" => $user,
        ], // global varialbes accessible in twig
    ],
];

// initialize SilexKernel with $config
中间件

Silex 允许您通过 中间件 在请求处理的不同阶段运行代码,从而改变默认的 Silex 行为。

除了动态添加中间件的 Silex 方法外,您还可以实现 Oasis\Mlib\Http\Middlewares\MiddlewareInterface 并在引导阶段安装中间件

<?php
/** @var Oasis\Mlib\Http\Middlewares\MiddlewareInterface $mid */
$config = [
    "middlewares" => [
        $mid,
    ],
];

// initialize SilexKernel with $config
服务提供者

[服务提供者] (http://silex.sensiolabs.org/doc/master/providers.html#service-providers) 是 Silex 允许开发者将应用程序的部分内容重用到另一个应用程序中的机制。

服务提供者可以通过 Silex 提供的 register 方法动态安装

<?php

use Oasis\Mlib\Http\SilexKernel;
use Silex\Provider\HttpCacheServiceProvider;

/** @var SilexKernel $kernel */
$kernel->register(new HttpCacheServiceProvider());

或者使用引导配置参数 providers 进行安装

<?php

use Silex\Provider\HttpCacheServiceProvider;

$config = [
    "providers" => [
        new HttpCacheServiceProvider(),
    ],
];

// initialize SilexKernel with $config
视图处理器

视图处理器是一个可调用对象(即实现__invoke()魔术方法),当路由控制器没有返回有效的Symfony\Component\HttpFoundation\Response对象时会被调用。

以下是一个视图处理器的示例:

<?php

use Symfony\Component\HttpFoundation\JsonResponse;

class MyViewHandler
{
    function __invoke($rawResult, Symfony\Component\HttpFoundation\Request $request)
    {
        return new JsonResponse($rawResult);
    }
}

__invoke函数接收一个原始结果并返回一个Symfony\Component\HttpFoundation\Response对象,这是Silex的有效响应类型。

注意:如果视图处理器没有返回Symfony\Component\HttpFoundation\Response或其子类的对象,则返回值将被传递到下一个视图处理器(如果提供了的话)。如果没有更多的视图处理器,或者返回了一个有效的Response对象,则此循环将停止。

要安装视图处理器,我们可以通过SilexKernelview()方法来注册它:

<?php

use Oasis\Mlib\Http\SilexKernel;

/** @var SilexKernel $kernel*/
/** @var callable $viewHandler*/
$kernel->view($viewHandler);

或者使用view_handlers引导配置参数。

<?php

/** @var callable $viewHandler*/
$config = [
    "view_handlers" => [
        $viewHandler,
    ],
];

// initialize SilexKernel with $config
错误处理器

与视图处理器类似,错误处理器也是一个可调用对象,在请求处理过程中抛出任何异常时会被调用。这不仅仅限于路由控制器执行,还包括中间件的前后阶段。

错误处理器应该接收一个\Exception对象和一个HTTP代码作为参数。返回值可以是任何东西。如果返回值不是Symfony\Component\HttpFoundation\Response类型,它也会经过视图处理器。

示例

class MyErrorHandler
{
    function __invoke(\Exception $e, $code)
    {
        return [
            'message' => $e->getMessage(),
            'code' => $code,
        ];
    }
}

要安装错误处理器,我们可以通过SilexKernelerror()方法来注册它:

<?php

use Oasis\Mlib\Http\SilexKernel;

/** @var SilexKernel $kernel*/
/** @var callable $errorHandler*/
$kernel->error($errorHandler);

或者使用error_handlers引导配置参数。

<?php

/** @var callable $errorHandler*/
$config = [
    "error_handlers" => [
        $errorHandler,
    ],
];

// initialize SilexKernel with $config

注意:如果错误处理器返回null,则相同的\Exception对象和代码将被传递到下一个错误处理器。然而,任何非null的返回值都将结束错误处理阶段,并且返回值将要么作为有效的Symfony\Component\HttpFoundation\Response对象发送回客户端,要么被传递到视图处理阶段

注入参数

当我们实现路由控制器时,我们总是需要访问不同类型的对象,例如DB连接、Cache实例、请求对象,有时甚至是SilexKernel本身。

oasis/http维护了一个可注入参数列表,并在调用控制器之前执行类型检查:它会遍历控制器中每个类型提示的参数,并检查是否有在可注入列表中该类型的对象。如果有,这个参数将被传递到控制器中。如果没有找到可注入参数,将抛出\RuntimeException

默认情况下,oasis/http将注入以下对象:

  • Symfony\Component\HttpFoundation\Request对象:当前正在处理请求
  • Oasis\Mlib\Http\SilexKernel对象:内核对象本身

要访问其他变量,我们可以通过使用injected_args引导配置参数将它们注入为控制器参数的候选者。

<?php

use Symfony\Component\HttpFoundation\Request;

/** @var \Memcached $memcached */
$config = [
    "injected_args" => [
        'cache' => $memcached,
    ],
];

// initialize SilexKernel with $config

class MyController
{
    public function testAction(\Memcached $cache, Request $request)
    {
    }
}

在上面的示例中,testAction()将使用一个\Memcached对象和当前请求被调用。

注意:控制器中参数的顺序不重要,重要的是它们的类型。

可信代理

在尝试获取请求的IP地址时,我们总是需要过滤作为可信代理的某些地址。这些代理将真实发送者的IP地址以逆序(即最近的地址在末尾)放在HTTP头X-Forwarded-For中。我们可以使用trusted_proxies设置来指定应该考虑为可信的地址。

trusted_proxies 的格式是一个 IP 地址数组。此外,如果您想信任一个 IP 地址子网,可以使用 CIDR 表示法来代替 IP 地址。

AWS ELB 信任的代理

如果您的服务器位于 AWS ELB 之后,您应该将 REMOTE_ADDR 变量作为一个信任的代理,因为这是 ELB 的 IP 地址。

为了简化设置,存在一个名为 behind_elb 的快捷设置,默认值为 false。如果此设置设置为 true,则 REMOTE_ADDR 中设置的直接 IP 将被视为信任的,并且当从请求中获取 IP 地址时会忽略。

AWS Cloudfront 信任的代理

存在一个名为 trust_cloudfront_ips 的设置,默认值为 false。如果此参数设置为 true,则所有 AWS CloudFront IP 地址也将被视为信任的代理。因此,在请求上的 getClientIp() 将返回第一个到达 AWS CloudFront 的 IP 地址。