news 2026/6/1 4:12:52

PHPAPI网关实现与请求路由

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHPAPI网关实现与请求路由

PHP API网关实现与请求路由

API网关是微服务架构的入口。它负责请求路由、认证、限流、日志等功能。今天从零实现一个简单的API网关。

网关的核心功能是接收客户端请求,根据路由规则转发到对应的后端服务。

```php
class APIGateway
{
private array $routes = [];
private array $middlewares = [];
private array $rateLimits = [];

public function addRoute(string $path, string $targetUrl, array $methods = ['GET', 'POST', 'PUT', 'DELETE']): void
{
$this->routes[] = compact('path', 'targetUrl', 'methods');
}

public function addMiddleware(callable $middleware): void
{
$this->middlewares[] = $middleware;
}

public function setRateLimit(string $path, int $maxRequests, int $window): void
{
$this->rateLimits[$path] = compact('maxRequests', 'window');
}

public function handle(): void
{
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// 执行中间件
foreach ($this->middlewares as $middleware) {
$result = $middleware($method, $uri);
if ($result !== null) {
echo json_encode($result);
return;
}
}

// 路由匹配
foreach ($this->routes as $route) {
if (!in_array($method, $route['methods'])) continue;

$pattern = preg_replace('/\{(\w+)\}/', '(\w+)', $route['path']);
$pattern = '#^' . $pattern . '$#';

if (preg_match($pattern, $uri, $matches)) {
$this->forward($route['targetUrl'], $method, $uri);
return;
}
}

http_response_code(404);
echo json_encode(['error' => 'Route not found']);
}

private function forward(string $targetUrl, string $method, string $uri): void
{
$url = rtrim($targetUrl, '/') . $uri;

$ch = curl_init($url);
$options = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HEADER => true,
];

if ($method === 'POST' || $method === 'PUT') {
$options[CURLOPT_CUSTOMREQUEST] = $method;
$options[CURLOPT_POSTFIELDS] = file_get_contents('php://input');
}

curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);

$headers = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);

http_response_code($httpCode);
echo $body;
}
}
?>

// 限流中间件
class RateLimitMiddleware
{
private Redis $redis;
private int $maxRequests;
private int $window;

public function __construct(Redis $redis, int $maxRequests = 100, int $window = 60)
{
$this->redis = $redis;
$this->maxRequests = $maxRequests;
$this->window = $window;
}

public function __invoke(string $method, string $uri): ?array
{
$key = 'ratelimit:' . $_SERVER['REMOTE_ADDR'];
$current = $this->redis->get($key);

if ($current === false) {
$this->redis->setex($key, $this->window, 1);
return null;
}

if ($current >= $this->maxRequests) {
$ttl = $this->redis->ttl($key);
header('Retry-After: ' . $ttl);
http_response_code(429);
return ['error' => '请求过于频繁', 'retry_after' => $ttl];
}

$this->redis->incr($key);
return null;
}
}

// 认证中间件
class AuthMiddleware
{
private string $jwtSecret;

public function __construct(string $jwtSecret)
{
$this->jwtSecret = $jwtSecret;
}

public function __invoke(string $method, string $uri): ?array
{
// 公开路由跳过认证
$publicRoutes = ['/api/login', '/api/register', '/health'];
if (in_array($uri, $publicRoutes)) {
return null;
}

$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$token = str_replace('Bearer ', '', $token);

if (empty($token)) {
http_response_code(401);
return ['error' => '未提供认证token'];
}

// 验证JWT
$parts = explode('.', $token);
if (count($parts) !== 3) {
http_response_code(401);
return ['error' => '无效的token格式'];
}

$payload = json_decode(base64_decode($parts[1]), true);
if (!$payload || $payload['exp'] < time()) {
http_response_code(401);
return ['error' => 'token已过期'];
}

return null;
}
}

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$gateway = new APIGateway();

$gateway->addMiddleware(new RateLimitMiddleware($redis));
$gateway->addMiddleware(new AuthMiddleware('your-jwt-secret'));

$gateway->addRoute('/api/users', 'http://user-service:9001');
$gateway->addRoute('/api/orders', 'http://order-service:9002');
$gateway->addRoute('/api/products', 'http://product-service:9003');

$gateway->setRateLimit('/api/users', 60, 60);
$gateway->setRateLimit('/api/orders', 30, 60);

$gateway->handle();
?>

API网关作为系统的统一入口,可以集中处理横切关注点。认证、限流、日志、监控都在网关层实现,后端服务可以专注于业务逻辑。但网关也可能成为性能瓶颈和单点故障,设计时要注意容错和扩展。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/1 4:08:13

避坑指南:Node-RED处理Modbus-RTU负温度补码与数据解析的完整流程

Node-RED实战&#xff1a;Modbus-RTU负温度补码解析与数据处理的深度剖析在工业物联网和自动化控制领域&#xff0c;Modbus协议因其简单可靠而广受欢迎&#xff0c;但协议中负数的补码表示方式常常成为开发者数据解析路上的"绊脚石"。我曾在一个冷链监控项目中&#…

作者头像 李华