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

基本用法
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';
}
}
性能建议
- 缓存匹配结果:对于频繁检查的规则
- 简化正则表达式:避免过于复杂的模式
- 优先使用精确匹配:
/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 的完整使用方法!它在安全控制、路由匹配等场景中非常实用。