8ctopus / nano-router
实验性的PSR-7, PSR-17路由器
13.0.0
2024-08-07 07:49 UTC
Requires
- php: >=8.1
- psr/http-message: ^1.0|^2.0
Requires (Dev)
- 8ctopus/nano-timer: ^4.0
- filp/whoops: ^2.14
- friendsofphp/php-cs-fixer: ^3.8
- httpsoft/http-emitter: ^1.0
- httpsoft/http-message: ^1.1
- httpsoft/http-server-request: ^1.0
- phpmd/phpmd: ^2.13
- phpstan/phpstan: ^1.9
- phpunit/phpunit: ^9.5|^10.0
This package is auto-updated.
Last update: 2024-09-07 08:03:39 UTC
README
实验性的PSR-7, PSR-17路由器
特性
- 非常快(简单路由低于2ms)
- 使用PSR-7和PSR-17标准
- 除了PSR-7/17外无任何依赖
虽然我认为它仍然是实验性的,但我已经在生产环境中使用它来托管legend.octopuslabs.io,迄今为止没有遇到任何问题。
初学者介绍
路由器的作用是将用户(客户端)的HTTP请求匹配到特定的函数,该函数将处理用户请求并向客户端发送响应。
PSR-7 定义了请求和响应接口,而 PSR-17 定义了创建它们的工厂。换句话说,工厂用于创建请求和响应对象。
以下是一些伪代码,用于解释这个概念
$router = new Router(); $router->addRoute(new Route(RouteType::Exact, 'GET', '/test.php', function (ServerRequestInterface $request) : ResponseInterface { return new Response(200, ['content-type' => 'text/plain'], 'You\'ve reached page /test.php'); })); // create user request from globals $request = ServerRequestCreator::createFromGlobals($_SERVER, $_FILES, $_COOKIE, $_GET, $_POST); // resolve finds the function that handles the user request, calls it and returns the function's response $response = $router->resolve($request); // send response to client (echoes internally) (new SapiEmitter()) ->emit($response);
演示
要玩演示,请克隆仓库,运行 php -S localhost:80 demo/public/index.php -t demo/public/
并在浏览器中打开 http://localhost
。或者您可以在Docker容器中运行演示 docker-compose up &
。
安装
-
composer require 8ctopus/nano-router
-
如果您对PSR-7实现没有偏好,请安装 HttpSoft
composer require httpsoft/http-message httpsoft/http-emitter
-
对于使用Apache的用户,在
.htaccess
中将所有流量(除现有文件外)重定向到路由器
RewriteEngine on # redirect all not existing files and directories to router RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [END]
以及对于nginx(未经测试)
location / { try_files $uri $uri/ /index.php$is_args$args; }
- 创建
index.php
use Oct8pus\NanoRouter\NanoRouter; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; // use any PSR-7, PSR-17 implementations, here HttpSoft use HttpSoft\Emitter\SapiEmitter; use HttpSoft\Message\Response; use HttpSoft\Message\ServerRequestFactory; use HttpSoft\Message\Stream; use HttpSoft\ServerRequest\ServerRequestCreator; require_once __DIR__ . '/vendor/autoload.php'; $router = new NanoRouter(Response::class, ServerRequestFactory::class); $router // add simple route ->addRoute(new Route(RouteType::Exact, 'GET', '/test.php', function (ServerRequestInterface $request) : ResponseInterface { $stream = new Stream(); $stream->write('test.php'); return new Response(200, [], $stream); })) // add starts with route ->addRoute(new Route(RouteType::StartsWith, ['GET', 'POST'], '/test/', function (ServerRequestInterface $request) : ResponseInterface { $stream = new Stream(); $stream->write('request target - '. $request->getRequestTarget()); return new Response(200, [], $stream); })) // add regex route ->addRoute(new Route(RouteType::Regex, '*', '~/php(.*)/~', function (ServerRequestInterface $request) : ResponseInterface { $stream = new Stream(); $stream->write('request target - '. $request->getRequestTarget()); return new Response(200, [], $stream); })) ->addErrorHandler(404, function (ServerRequestInterface $request) : ResponseInterface { $stream = new Stream(); $stream->write('page not found - ' . $request->getRequestTarget()); return new Response(404, [], $stream); }) ->addMiddleware('*', '~(.*)~', MiddlewareType::Post, function (ResponseInterface $response, ServerRequestInterface $request) : ResponseInterface { return $response->withHeader('X-Powered-By', '8ctopus'); }); // create request from globals $request = ServerRequestCreator::createFromGlobals($_SERVER, $_FILES, $_COOKIE, $_GET, $_POST); // resolve request into a response $response = $router->resolve($request); // send response to client (new SapiEmitter()) ->emit($response);
高级功能
还有很多其他的功能,但还没有在README中说明,例如
- 前置和后置中间件
- 路由异常和通用异常处理
但大部分都可以在演示中尝试
运行测试
composer test
代码整洁
composer fix(-risky)
待办事项想法
- 添加basePath
- 子路由的类包装器
- 前置中间件是否只应该对有效请求起作用?现在无效路由仍然通过中间件,我们可能需要两者
- 检查PSR-15中间件
- 添加startsWith中间件
- 如何在类内部轻松路由?