PHP Fastroute - 处理 404
PHP Fastroute - Handle 404s
在我的应用程序中,我正在使用 FastRoute,我希望有不同类型的 404 响应:
- 当调用以
/api
开头的 不存在的 端点时,应用程序应该 return JSON 404响应。
- 当调用不存在的端点时,应用程序应该 return 通用 404。
为了获得通用的 404 响应,我按照文档做了:
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
break;
但我无法找到在 /api
端点不存在的情况下获得 404 JSON 响应的方法。
我取得的成就是这样的:
$router->addGroup('/api', function (RouteCollector $r) {
$r->post('/login', 'ApiController@login');
$r->addRoute('*', '[/{str}]', 'ApiController@notFound');
});
例如:
- 当调用
/api/not-existing-endpoint
时,它 return 是一个 JSON 404 响应(所以没关系)。
- 当调用
/api/not-existing-endpoint/aaa/bbb/ccc
时它没有捕捉到它并且它 return 是一个通用的 404。
如何修复路由 $r->addRoute('*', '[/{str}]', 'ApiController@notFound');
的模式,以便同时捕获 /api/aaa/bbb/ccc/ddd
之类的嵌套 URI?
使用带正则表达式的路由路径。
$r->addRoute('*', '[/{any:.*}]', 'ApiController@notFound');
我的完整代码。
require 'vendor/autoload.php';
$dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
echo 'hello';
});
$r->addRoute('GET', '/hello/{name}', function($attribute) {
echo 'hello ' . $attribute['name'];
});
$r->addGroup('/api', function (\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'hello API']);
});
$r->addRoute('*', '[/{any:.*}]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
});
});
});
// Fetch method and URI from somewhere
// for dynamic subfolder. https://github.com/nikic/FastRoute/issues/110
$base = dirname($_SERVER['PHP_SELF']);
ltrim($base, '/') ? $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) : '';
// end dynamic subfolder.
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
$uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
echo 'not found';
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
$allowedMethods = $routeInfo[1];
// ... 405 Method Not Allowed
http_response_code(405);
echo 'method not allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// ... call $handler with $vars
$handler($vars);
break;
}
已测试:
- https:///localhost/api => JSON 'not found'
- https:///localhost/api/hello => JSON 'hello API'
- https:///localhost/api/notfound => JSON 'not found'
- https:///localhost/api/notfound/notfound => JSON 'not found'
- https:///localhost/notfound => HTML 'not found'
备选
我建议您改为使用 404 路由来处理此问题。因为它不会与普通路由.
混在一起,所以以后管理代码会更好更容易
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
$expUri = explode('/', $uri);
if ($expUri[1] === 'api') {
// if first url segment is api. please check this again in your application that it is [1] or [0] and correct it.
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
} else {
echo 'not found';
}
break;
// ...
}
我的完整代码。
<?php
require 'vendor/autoload.php';
$dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
echo 'hello';
});
$r->addRoute('GET', '/hello/{name}', function($attribute) {
echo 'hello ' . $attribute['name'];
});
$r->addGroup('/api', function (\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'hello API']);
});
});
});
// Fetch method and URI from somewhere
// for dynamic subfolder. https://github.com/nikic/FastRoute/issues/110
$base = dirname($_SERVER['PHP_SELF']);
ltrim($base, '/') ? $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) : '';
// end dynamic subfolder.
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
$uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
$expUri = explode('/', $uri);
if ($expUri[1] === 'api') {
// if first url segment is api. please check this again in your application that it is [1] or [0] and correct it.
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
} else {
echo 'not found';
}
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
$allowedMethods = $routeInfo[1];
// ... 405 Method Not Allowed
http_response_code(405);
echo 'method not allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// ... call $handler with $vars
$handler($vars);
break;
}
在我的应用程序中,我正在使用 FastRoute,我希望有不同类型的 404 响应:
- 当调用以
/api
开头的 不存在的 端点时,应用程序应该 return JSON 404响应。 - 当调用不存在的端点时,应用程序应该 return 通用 404。
为了获得通用的 404 响应,我按照文档做了:
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
break;
但我无法找到在 /api
端点不存在的情况下获得 404 JSON 响应的方法。
我取得的成就是这样的:
$router->addGroup('/api', function (RouteCollector $r) {
$r->post('/login', 'ApiController@login');
$r->addRoute('*', '[/{str}]', 'ApiController@notFound');
});
例如:
- 当调用
/api/not-existing-endpoint
时,它 return 是一个 JSON 404 响应(所以没关系)。 - 当调用
/api/not-existing-endpoint/aaa/bbb/ccc
时它没有捕捉到它并且它 return 是一个通用的 404。
如何修复路由 $r->addRoute('*', '[/{str}]', 'ApiController@notFound');
的模式,以便同时捕获 /api/aaa/bbb/ccc/ddd
之类的嵌套 URI?
使用带正则表达式的路由路径。
$r->addRoute('*', '[/{any:.*}]', 'ApiController@notFound');
我的完整代码。
require 'vendor/autoload.php';
$dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
echo 'hello';
});
$r->addRoute('GET', '/hello/{name}', function($attribute) {
echo 'hello ' . $attribute['name'];
});
$r->addGroup('/api', function (\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'hello API']);
});
$r->addRoute('*', '[/{any:.*}]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
});
});
});
// Fetch method and URI from somewhere
// for dynamic subfolder. https://github.com/nikic/FastRoute/issues/110
$base = dirname($_SERVER['PHP_SELF']);
ltrim($base, '/') ? $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) : '';
// end dynamic subfolder.
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
$uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
echo 'not found';
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
$allowedMethods = $routeInfo[1];
// ... 405 Method Not Allowed
http_response_code(405);
echo 'method not allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// ... call $handler with $vars
$handler($vars);
break;
}
已测试:
- https:///localhost/api => JSON 'not found'
- https:///localhost/api/hello => JSON 'hello API'
- https:///localhost/api/notfound => JSON 'not found'
- https:///localhost/api/notfound/notfound => JSON 'not found'
- https:///localhost/notfound => HTML 'not found'
备选
我建议您改为使用 404 路由来处理此问题。因为它不会与普通路由.
混在一起,所以以后管理代码会更好更容易switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
$expUri = explode('/', $uri);
if ($expUri[1] === 'api') {
// if first url segment is api. please check this again in your application that it is [1] or [0] and correct it.
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
} else {
echo 'not found';
}
break;
// ...
}
我的完整代码。
<?php
require 'vendor/autoload.php';
$dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
echo 'hello';
});
$r->addRoute('GET', '/hello/{name}', function($attribute) {
echo 'hello ' . $attribute['name'];
});
$r->addGroup('/api', function (\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'hello API']);
});
});
});
// Fetch method and URI from somewhere
// for dynamic subfolder. https://github.com/nikic/FastRoute/issues/110
$base = dirname($_SERVER['PHP_SELF']);
ltrim($base, '/') ? $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) : '';
// end dynamic subfolder.
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
$uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
$expUri = explode('/', $uri);
if ($expUri[1] === 'api') {
// if first url segment is api. please check this again in your application that it is [1] or [0] and correct it.
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
} else {
echo 'not found';
}
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
$allowedMethods = $routeInfo[1];
// ... 405 Method Not Allowed
http_response_code(405);
echo 'method not allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// ... call $handler with $vars
$handler($vars);
break;
}