guahanweb/php-router

PHP项目的轻量级路由器

v1.2 2016-10-14 20:36 UTC

This package is not auto-updated.

Last update: 2024-09-28 18:16:06 UTC


README

PHP Router是一个轻量级的库,用于管理HTTP请求、响应和路由,以快速构建健壮的应用程序。此库使用了在流行的Node.js库(如Express和Hapi)中最常见的模式。

为了从实现这种路由模式中获得最大收益,您可能需要对Apache或Nginx配置进行一些调整。

安装

使用 Composer 安装

$ composer require guahanweb/php-router

用法

安装并配置项目以使用Composer的自动加载后,您就可以开始路由了。

<?php
// Include the namespace
use GuahanWeb\Http;

// Get a router instance
$router = Http\Router::instance();

// Register a route
$router->get('/', function ($req, $res) {
    $res->send('Hello, world!');
});

// Tell the router to start
$router->process();

路由器

路由支持与Express.js相同的基本模式。提供HTTP动词、路由模式和处理器,当模式与动词组合匹配已注册的路由时,将执行处理器。

注册路由

路由可以通过两种方式之一进行注册。第一种是显式动词方法

$router->get($route, $handler);
$router->post($route, $handler);
$router->put($route, $handler);
$router->delete($route, $handler);

第二种选项是在单个注册调用中注册一个或多个动词(或使用*注册所有动词)

// multiple verbs
$router->route(['POST', 'PUT'], $route, $handler);

// wildcard for all supported verbs
$router->route('*', $route, $handler);

路由模式和参数

如果您想从路由URI捕获参数,您可以使用括号来命名参数。这些参数将作为请求对象的属性应用

// capture a username
$router->get('/profile/{username}', function ($req, $res) {
    var_dump($req->username);
});

您还可以选择贪婪地匹配路径块进行手动解析。例如,如果我们想区分URI内部的匹配,但不区分json扩展,我们可以这样做

// match a path with json extension
// URI: /api/v1/my_method/json
$router->get('/api/{path*}/json', function ($req, $res) {
    $res->send($req->path); // v1/my_method
});

这种匹配类型对于将请求静态文件(不由Apache或Nginx配置管理)传递给请求非常有用

// route all image requests to a handler
$router->get('/img/{image*}', function ($req, $res) {
    ImageManager::serve($req->image);
});

请求和响应对象

每个路由处理器将传递两个参数:一个请求对象和一个响应对象。这些对象可用于获取详细信息并计算适当的响应。在大多数情况下,路由处理器应最终调用$res->send()

请求对象

当初始化路由器时,将创建一个新的Http\Request对象并将其传递给处理器。此对象包含许多预解析的属性,有助于管理响应。

HTTP请求类型

HTTP方法(或动词)将分配给请求对象,并可以通过属性访问

echo $req->method;

支持的有效类型有GETPOSTPUTDELETE

HTTP请求头

所有请求头都可通过请求对象访问。而不是使用原生的PHP getallheaders() 方法,我们使用自定义polyfill以允许在Apache和Nginx环境中检索头信息。

一些请求头将由路由器用于在响应对象上设置默认值。要访问头信息,您可以引用请求对象的headers属性

$router->post('/api/user', function ($req, $res) {
    if ($req->headers['Content-Type'] == 'application/json') {
        // request has JSON payload
    }
});

查询字符串

请求对象将预解析查询字符串并将其分配给query属性。如果您正在基于预期的查询参数进行逻辑操作,请使用此属性。

$router->post('/calendar', function ($req, $res) {
    if (!isset($req->query['month'])) {
        $res->send('Please select a month!');
    } else {
        $res->send(Calendar::render($req->query['month']));
    }
});

请求URI

完全匹配的URI将分配给请求对象的uri属性。

$router->get('/profile/{username}', function ($req, $res) {
    $res->send($req->uri);
});

在这个例子中,如果您导航到http://yourdomain.com/profile/guahanweb,您将得到响应/profile/guahanweb

请求体(数据负载)

我们尝试对解析请求体进行了一些优化。我们不会总是解析负载,而是仅在第一次请求时静态解析它。换句话说,只有当第一次引用 body 属性时,才会解析正文。如果您再次引用 body 属性,则不会第二次解析负载。

此外,还基于 HTTP 动词和 Content-Type 头的组合对正文做了一些假设。

GET 和 DELETE

根据 HTTP/1.1 规范,如果存在,GETDELETE 请求体不应有任何意义。因此,请求对象将对这些动词使用 null 值短路任何正文解析。

PUT

PUT 请求的正文将从 STDIN 读取。如果请求的 Content-Type 是 application/json,正文也将解析为 JSON 内容,并将返回的结果对象。

POST

POST 动词的行为类似于 PUT,但有一个额外的注意事项。除了 JSON 负载之外,POST 动词还可以接受以 mulipart/form-data 开头的 Content-Type。在这种情况下,由于 PHP 已经将负载处理为 $_POST 变量,正文将简单地返回该变量。

PUTPOST 两种情况下,如果未指定 JSON 或表单内容,则返回正文的原生字符串。

响应对象

响应对象允许对发送到浏览器的 HTTP 响应进行细粒度控制。

方法

setHeader($k, $v)

允许您在发送响应之前设置或覆盖默认头。默认内容类型取决于要发送的数据。如果传递了一个字符串,则内容类型默认为 text/html,但如果传递了一个数组或对象,则内容将被 JSON 编码,并以 application/json 类型发送。

setHeaders($headers)

同时设置多个头的快捷方式。此方法接受一个头数组,其中键是头名称,值是头内容。

send($content, [$code])

此方法将发送最终构建的响应回用户。可选的 $code 参数允许您指定除默认的 200 Success 响应之外的状态码。

$router->route('*', '/admin', function ($req, $res) {
    $res->send('What do you think you are doing?', 500);
});

以下是一个端点的示例,允许您检查所有动词的所有请求的属性。

// examine request from any verbs
$router->route('*', '/info', function ($req, $res) {
    $res->send(array(
        'method' => $req->method,
        'uri' => $req->uri,
        'query' => $req->query,
        'headers' => $req->headers,
        'body' => $req->body
    ));
});

服务器配置

为了最大限度地利用手动路由,建议您将服务器配置为将所有希望处理的请求都导入一个单独的 PHP 文件。

Nginx 示例

如果您计划在路由中使用 PUTDELETE 动词,请确保您的 Nginx 已经通过 --with-webdav 构建,并已安装。然后,在您的配置中,您需要启用额外的方法

dav_methods PUT DELETE;

我还建议提供一个基本位置,从中 Nginx 可以提供所有静态内容,这样您就只需要处理受保护的或需要额外逻辑的内容的 PHP。

location ~* ^/(css|js|img|font)/ {
    root /var/www/<my-project>/assets;
}

另一件事是我喜欢做的,就是只将不明确匹配磁盘上另一个文件的流量导向。因此,完整的配置可能如下所示

server {
    charset UTF-8;
    listen 80;
    server_name <project-domain>;
    access_log /var/www/logs/<project-domain>/access.log;

    location ~* ^/(css|js|img|font)/ {
        root /var/www/<project-domain>/assets;
    }

    location / {
        root /var/www/<project-domain>;
        index index.php index.html index.htm;
        include /usr/local/etc/nginx/conf.d/php-fpm;

        dav_methods PUT DELETE;

        if (!-e $request_filename) {
            rewrite ^(.+)$ /index.php last;
        }

        error_page 404 /index.php;
    }
}

结论

解决这个挑战有很多不同的方法,我只是研究了最适合我个人偏好的模型。如果您有可以改进此项目或只是想让我知道它帮了您的想法,请随时联系我。