PHP项目Symfony RequestMatcher

wen PHP项目 3

Symfony RequestMatcher 详解

RequestMatcher 是 Symfony 中用于匹配 HTTP 请求的工具类,常用于访问控制、路由匹配、防火墙配置等场景。

PHP项目Symfony RequestMatcher

基本用法

use Symfony\Component\HttpFoundation\RequestMatcher;
use Symfony\Component\HttpFoundation\Request;
// 创建匹配器
$matcher = new RequestMatcher();
// 匹配路径(支持正则)
$matcher->matchPath('/admin/*');
$matcher->matchPath('^/api/');
// 匹配主机名
$matcher->matchHost('example.com');
$matcher->matchHost('*.example.com');
// 匹配HTTP方法
$matcher->matchMethod('GET');
$matcher->matchMethod(['GET', 'POST']);
// 匹配IP地址
$matcher->matchIp('192.168.1.0/24');
$matcher->matchIp(['192.168.1.1', '10.0.0.0/8']);
// 匹配请求属性
$matcher->matchAttribute('_route', 'admin_dashboard');
// 执行匹配
$request = Request::create('/admin/users', 'GET');
$isMatched = $matcher->matches($request); // true/false

完整示例

use Symfony\Component\HttpFoundation\RequestMatcher;
// 复杂匹配规则
class AccessController
{
    public function checkAccess(Request $request): bool
    {
        $matcher = new RequestMatcher();
        // 设置多条规则(全部满足才匹配)
        $matcher
            ->matchPath('^/api/')
            ->matchMethod('POST')
            ->matchHost('api.example.com')
            ->matchIp(['192.168.1.0/24', '10.0.0.0/8']);
        return $matcher->matches($request);
    }
    public function isAdminArea(Request $request): bool
    {
        $matcher = new RequestMatcher();
        $matcher->matchPath('^/admin');
        return $matcher->matches($request);
    }
}

在 Security 配置中使用

# config/packages/security.yaml
security:
    access_control:
        - { path: '^/admin', roles: ROLE_ADMIN }
        - { path: '^/api', roles: ROLE_API_USER, methods: [POST] }
        - { path: '^/public', roles: IS_AUTHENTICATED_ANONYMOUSLY }
// 在自定义防火墙中使用
use Symfony\Component\Security\Http\AccessMap;
use Symfony\Component\HttpFoundation\RequestMatcher;
$accessMap = new AccessMap();
$accessMap->add(
    new RequestMatcher('^/admin'),
    ['ROLE_ADMIN']
);
$accessMap->add(
    (new RequestMatcher())->matchPath('^/api')->matchMethod('POST'),
    ['ROLE_API_USER']
);

高级用法

组合多个匹配器

use Symfony\Component\HttpFoundation\ChainRequestMatcher;
// 创建多个匹配器
$pathMatcher = new RequestMatcher();
$pathMatcher->matchPath('^/api');
$methodMatcher = new RequestMatcher();
$methodMatcher->matchMethod('POST');
$hostMatcher = new RequestMatcher();
$hostMatcher->matchHost('api.example.com');
// 组合使用(全部满足)
$chainMatcher = new ChainRequestMatcher([
    $pathMatcher,
    $methodMatcher,
    $hostMatcher
]);
$request = Request::create('/api/users', 'POST', [], [], [], ['HTTP_HOST' => 'api.example.com']);
$result = $chainMatcher->matches($request); // true

自定义匹配器

use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\HttpFoundation\Request;
class CustomRequestMatcher implements RequestMatcherInterface
{
    private array $allowedUserAgents;
    public function __construct(array $allowedUserAgents)
    {
        $this->allowedUserAgents = $allowedUserAgents;
    }
    public function matches(Request $request): bool
    {
        $userAgent = $request->headers->get('User-Agent');
        return in_array($userAgent, $this->allowedUserAgents);
    }
}
// 使用
$customMatcher = new CustomRequestMatcher(['Symfony Browser', 'Chrome/91.0']);
$isMatched = $customMatcher->matches($request);

实际应用场景

// API版本控制
class ApiVersionMatcher
{
    public function matchVersion(Request $request, string $version): bool
    {
        $matcher = new RequestMatcher();
        $matcher->matchPath("^/api/v{$version}/");
        return $matcher->matches($request);
    }
}
// 多站点路由
class SiteRouter
{
    public function matchSite(Request $request): string
    {
        $sites = [
            'admin' => new RequestMatcher('^/admin'),
            'api' => new RequestMatcher('^/api'),
            'blog' => (new RequestMatcher())->matchPath('^/blog')->matchHost('blog.*'),
        ];
        foreach ($sites as $name => $matcher) {
            if ($matcher->matches($request)) {
                return $name;
            }
        }
        return 'default';
    }
}

性能建议

  1. 缓存匹配结果:对于频繁检查的规则
  2. 简化正则表达式:避免过于复杂的模式
  3. 优先使用精确匹配/admin^/admin/.* 更快
class CachedRequestMatcher
{
    private array $cache = [];
    private RequestMatcher $matcher;
    public function __construct()
    {
        $this->matcher = new RequestMatcher();
    }
    public function matches(Request $request): bool
    {
        $key = spl_object_id($request);
        if (!isset($this->cache[$key])) {
            $this->cache[$key] = $this->matcher->matches($request);
        }
        return $this->cache[$key];
    }
}

注意事项

  • matchPath() 支持正则表达式,但注意性能影响
  • matchHost() 支持通配符 ,但不支持正则
  • matchIp() 支持 CIDR 格式
  • 多个 match* 方法调用是 AND 关系
  • 新版本的 Symfony 推荐使用 RequestMatcherInterface 的实现

这就是 Symfony RequestMatcher 的完整使用方法!它在安全控制、路由匹配等场景中非常实用。

抱歉,评论功能暂时关闭!