欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

symfony配置文件之三:routing和路由配置

程序员文章站 2024-02-13 19:46:40
...

目录

1、创建路由

2、查看路由列表

3、本地化路由(i18n)

4、添加requirements (针对url占位符或host占位符)

1)类正则 Regex Requirements

2)HTTP Method Requirements

3)Host-Based Requirements

        在主机名中使用占位符

        导入路由的主机匹配

        测试控制器

4)Dynamic Requirements with Condition Expressions 通过条件限制路由匹配


        漂亮的路由对任何一个WEB应用而言都是刚需。这意味着我们要抛弃类似 index.php?article_id=57 这样丑陋的URL, 而使用像 /read/intro-to-symfony 语义化的url。

        灵活性也是非常重要的。 如果你需要把你页面所有的/blog变成/news?,你要查找多少次, 替换多少次? 如果你使用Symfony的路由器, 那改个URL什么的就变得非常非常简单。

        Symfony路由器可以让你定义出各种个性化的URL, 映射到你应用的各个地方。了解完这个章节后, 你会:

    创建复杂的路由映射到控制器

    在控制器和模板中生成URL

    从包中加载路由资源(或者说任何地方)
 
    调试路由

1、创建路由

        简单说,路由就是一个从URL路径到控制器映射。 如果你想匹配 /blog,以及类似 /blog/my-post 或 /blog/all-about-symfony 的URL路径,并且将它们分发到对应的控制器,并且渲染一个blog实体.。要实现这个功能非常简单,主要有一下几种方法:

--------通过注释定义路由 
--------通过yaml配置文件定义路由 
--------通过xml配置文件定义路由 
--------通过php配置文件定义路由

        路由可以在YAML,XML和PHP中配置,所有格式都提供相同的功能和性能,因此请选择您喜欢的格式。如果选择PHP注释,请在应用程序中运行此命令一次以添加对它们的支持:

  $ composer require annotations

       现在,您可以配置路由:

注释形式

// src/Controller/BlogController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class BlogController extends AbstractController
{
    /**
     * Matches /blog exactly
     *
     * @Route("/blog", name="blog_list")
     */
    public function list()
    {
        // ...
    }

    /**
     * Matches /blog/*
     *
     * @Route("/blog/{slug}", name="blog_show")
     */
    public function show($slug)
    {
        // $slug will equal the dynamic part of the URL
        // e.g. at /blog/yay-routing, then $slug='yay-routing'

        // ...
    }
}

YAML文件

# config/routes.yaml
blog_list:
    path:     /blog
    controller: App\Controller\BlogController::list

blog_show:
    path:     /blog/{slug}
    controller: App\Controller\BlogController::show

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="blog_list" path="/blog" controller="App\Controller\BlogController::list">
        <!-- settings -->
    </route>

    <route id="blog_show" path="/blog/{slug}" controller="App\Controller\BlogController::show">
        <!-- settings -->
    </route>
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\BlogController;

return function (RoutingConfigurator $routes) {
    $routes->add('blog_list', '/blog')
        ->controller([BlogController::class, 'list'])
    ;
    $routes->add('blog_show', '/blog/{slug}')
        ->controller([BlogController::class, 'show'])
    ;
};
  • 如果去匹配路径 /blog,那么将执行第一条路由,并且 list() 方法被调用。
  • 如果去匹配 /blog/*,那么将执行第一条路由,并且 show() 方法被调用。由于路由的路径设置为 /blog/{slug},那么 /blog/ 后面的字符串,将传递给 show() 方法的参数 $slug。例如,如果去匹配 /blog/yay-routing,那么参数 $slug 将被赋值为字符串"yay-routing"

        只要您的路径中有一个{placeholder}占位符,该部分就会成为通配符:它匹配任何值。现在,您的控制器可以拥有一个$placeholder参数(此处,通配符和参数名称必须匹配)。

2、查看路由列表

        随着应用程序的开发,最终将拥有大量的路由。要查看所有的路由列表,请运行:

$ php bin/console debug:router
------------------------------ -------- -------------------------------------
Name Method Path
------------------------------ -------- -------------------------------------
app_lucky_number ANY /lucky/number/{max}
...
------------------------------ -------- -------------------------------------

3、本地化路由(i18n)

        路由可以本地化,以提供一个与区域相关的唯一路径。Symfony提供了一种方便的方式来声明本地化路由,且无需重复声明。

注释

// src/Controller/CompanyController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class CompanyController extends AbstractController
{
    /**
     * @Route({
     *     "nl": "/over-ons",
     *     "en": "/about-us"
     * }, name="about_us")
     */
    public function about()
    {
        // ...
    }
}

YAML文件

# config/routes.yaml
about_us:
    path:
        nl: /over-ons
        en: /about-us
    controller: App\Controller\CompanyController::about

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="about_us" controller="App\Controller\CompanyController::about">
        <path locale="nl">/over-ons</path>
        <path locale="en">/about-us</path>
    </route>
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\CompanyController;

return function (RoutingConfigurator $routes) {
    $routes->add('about_us', ['nl' => '/over-ons', 'en' => '/about-us'])
        ->controller([CompanyController::class, 'about']);
};

        当本地化路由被匹配时,Symfony就会自动知道在请求期间应使用哪个区域的设置。以这种方式定义路由,消除了对路由重复注册的需要,同时最小化了由定义不一致引起的任何错误风险。

notes

        如果应用程序使用 “完整语言 + 领土区域设置”(例如fr_FR, fr_BE),你可以在你的路由中仅仅使用语言部分(如fr)。当您希望为共享相同语言的语言环境使用相同的路径时,这可以防止必须定义多个路径。

        国际化应用程序的一个常见要求是,为所有路由添加前缀。这可以通过为每个语言环境定义不同的前缀来完成(如果您愿意,可以为默认语言环境设置一个空前缀):

YAML文件

# config/routes/annotations.yaml
controllers:
    resource: '../../src/Controller/'
    type: annotation
    prefix:
        en: '' # don't prefix URLs for English, the default locale
        nl: '/nl'

XML文件

<!-- config/routes/annotations.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <import resource="../src/Controller/" type="annotation">
        <!-- don't prefix URLs for English, the default locale -->
        <prefix locale="en"></prefix>
        <prefix locale="nl">/nl</prefix>
    </import>
</routes>

PHP文件

// config/routes/annotations.php
namespace Symfony\Component\Routing\Loader\Configurator;

return function (RoutingConfigurator $routes) {
    $routes->import('../src/Controller/', 'annotation')
        ->prefix([
            // don't prefix URLs for English, the default locale
            'en' => '',
            'nl' => '/nl'
        ])
    ;
};

4、添加requirements (针对url占位符或host占位符)

        想象一下,该 blog_list路由将包含一个分页的 blog post 列表,其中包含/blog/2和/blog/3来表示第2页和第3页的URL 。如果您更改路由的路径为 /blog/{page},则会遇到问题:

  • blog_list: /blog/{page} 会匹配 /blog/* ;
  • blog_show:/blog/{slug} 将同样匹配 /blog/* 。

        当两个路由匹配相同的URL时,加载的第一个路由获胜。不幸的是,这意味着/blog/yay-routing 将匹配 blog_list。这是个比较严重的问题。

        为了解决这个问题,增加 requirements 属性来限制通配符{page}只能匹配数字:

注释形式

// src/Controller/BlogController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class BlogController extends AbstractController
{
    /**
     * @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"})
     */
    public function list($page)
    {
        // ...
    }

    /**
     * @Route("/blog/{slug}", name="blog_show")
     */
    public function show($slug)
    {
        // ...
    }
}

YAML文件

# config/routes.yaml
blog_list:
    path:      /blog/{page}
    controller: App\Controller\BlogController::list
    requirements:
        page: '\d+'

blog_show:
    # ...

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="blog_list" path="/blog/{page}" controller="App\Controller\BlogController::list">
        <requirement key="page">\d+</requirement>
    </route>

    <!-- ... -->
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\BlogController;

return function (RoutingConfigurator $routes) {
    $routes->add('blog_list', '/blog/{page}')
        ->controller([BlogController::class, 'list'])
        ->requirements(['page' => '\d+'])
    ;
    // ...
};

        这个\d+是一个匹配任意长度数字正则表达式。现在:

 

           网址

路线

            参数

/blog/2 blog_list $page = 2
/blog/yay-routing blog_show $slug = yay-routing

        如果您愿意,也可以使用{placeholder_name<requirements>}语法,在每个占位符中后面使用<>写成同行形式 。此功能使配置更简洁,但是当需求复杂时,它降低了路由的可读性:

注释形式

// src/Controller/BlogController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class BlogController extends AbstractController
{
    /**
     * @Route("/blog/{page<\d+>}", name="blog_list")
     */
    public function list($page)
    {
        // ...
    }
}

YAML形式

# config/routes.yaml
blog_list:
    path:      /blog/{page<\d+>}
    controller: App\Controller\BlogController::list

XML形式

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="blog_list" path="/blog/{page<\d+>}" controller="App\Controller\BlogController::list" />

    <!-- ... -->
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\BlogController;

return function (RoutingConfigurator $routes) {
    $routes->add('blog_list', '/blog/{page<\d+>}')
        ->controller([BlogController::class, 'list'])
    ;
    // ...
};

定义requirements的语法总结:

1)类正则 Regex Requirements

        如多语言本地化枚举的实现:

注释形式 

// src/Controller/MainController.php

// ...
class MainController extends AbstractController
{
    /**
     * @Route("/{_locale}", defaults={"_locale"="en"}, requirements={
     *     "_locale"="en|fr"
     * })
     */
    public function homepage($_locale)
    {
    }
}

YAML文件

# config/routes.yaml
homepage:
    path:       /{_locale}
    controller: App\Controller\MainController::homepage
    defaults:   { _locale: en }
    requirements:
        _locale:  en|fr

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="homepage" path="/{_locale}" controller="App\Controller\MainController::homepage">
        <default key="_locale">en</default>
        <requirement key="_locale">en|fr</requirement>
    </route>
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\MainController;

return function (RoutingConfigurator $routes) {
    $routes->add('homepage', '/{_locale}')
        ->controller([MainController::class, 'homepage'])
        ->defaults([
            '_locale' => 'en',
        ])
        ->requirements([
            '_locale' => 'en|fr',
        ])
    ;
};

        对于传入的请求,URL 的{_locale}部分与正则表达式(en|fr)匹配。

路径 参数
/ {_locale} = "en"
/en {_locale} = "en"
/fr {_locale} = "fr"
/es 不符合这条路线

注意

        在声明或导入路由时,通过设置utf8选项,可以启用UTF-8路由匹配。这将使得例如 在requirements中的 . 将匹配任何UTF-8字符而不是单个字节。

提示:

        路由requirements还可以包括容器参数,如本文中所述。当正则表达式非常复杂,并在您的应用程序中重复使用时,这会派上用场。如:

# config/routes.yaml
contact:
    path:       /{_locale}/contact
    controller: App\Controller\MainController::contact
    requirements:
        _locale: '%app.locales%'

2)HTTP Method Requirements

        除了URL之外,您还可以匹配传入请求的方法(即GET,HEAD,POST,PUT,DELETE)。假设,您为博客创建了一个API,并且您有两条路由:一条用于显示帖子(在GET或HEAD请求上),另一条用于更新帖子(在PUT请求中)。这可以通过以下路由配置来完成:

注释形式

// src/Controller/BlogApiController.php
namespace App\Controller;

// ...

class BlogApiController extends AbstractController
{
    /**
     * @Route("/api/posts/{id}", methods={"GET","HEAD"})
     */
    public function show($id)
    {
        // ... return a JSON response with the post
    }

    /**
     * @Route("/api/posts/{id}", methods={"PUT"})
     */
    public function edit($id)
    {
        // ... edit a post
    }
}

YAML文本

# config/routes.yaml
api_post_show:
    path:       /api/posts/{id}
    controller: App\Controller\BlogApiController::show
    methods:    GET|HEAD

api_post_edit:
    path:       /api/posts/{id}
    controller: App\Controller\BlogApiController::edit
    methods:    PUT

XML文本

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="api_post_show"
        path="/api/posts/{id}"
        controller="App\Controller\BlogApiController::show"
        methods="GET|HEAD" />

    <route id="api_post_edit"
        path="/api/posts/{id}"
        controller="App\Controller\BlogApiController::edit"
        methods="PUT" />
</routes>

PHP文本

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\BlogApiController;

return function (RoutingConfigurator $routes) {
    $routes->add('api_post_show', '/api/posts/{id}')
        ->controller([BlogApiController::class, 'show'])
        ->methods(['GET', 'HEAD'])
    ;
    $routes->add('api_post_edit', '/api/posts/{id}')
        ->controller([BlogApiController::class, 'edit'])
        ->methods(['PUT'])
    ;

    // or use collection
    $api = $routes->collection('api_post_')
        ->prefix('/api/posts/{id}')
    ;
    $api->add('show')
        ->controller([BlogApiController::class, 'show'])
        ->methods(['GET', 'HEAD'])
    ;
    $api->add('edit')
        ->controller([BlogApiController::class, 'edit'])
        ->methods(['PUT'])
    ;
};

        尽管这两条路由具有相同的路径(/api/posts/{id}),但第一条路径仅匹配GET或HEAD请求,第二条路径仅匹配PUT请求。这意味着,您可以使用相同的URL显示和编辑帖子,同时为这两个操作使用不同的控制器。

注意

        如果未指定methods,则路由将匹配所有方法。

提示:

        如果您使用HTML表单和HTTP方法,而不是GETPOST,那么你需要包括一个_method参数来伪装HTTP方法。有关更多信息,请参见 如何更改窗体的操作和方法

3)Host-Based Requirements

        您还可以对传入请求的HTTP 主机,进行路由匹配。这种Requirements主要用于限制请求的来源。如:

注释形式

// src/Controller/MainController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class MainController extends AbstractController
{
    /**
     * @Route("/", name="mobile_homepage", host="m.example.com")
     */
    public function mobileHomepage()
    {
        // ...
    }

    /**
     * @Route("/", name="homepage")
     */
    public function homepage()
    {
        // ...
    }
}

YAML文件

# config/routes.yaml
mobile_homepage:
    path:       /
    host:       m.example.com
    controller: App\Controller\MainController::mobileHomepage

homepage:
    path:       /
    controller: App\Controller\MainController::homepage

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="mobile_homepage"
        path="/"
        host="m.example.com"
        controller="App\Controller\MainController::mobileHomepage" />

    <route id="homepage" path="/" controller="App\Controller\MainController::homepage" />
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\MainController;

return function (RoutingConfigurator $routes) {
    $routes->add('mobile_homepage', '/')
        ->controller([MainController::class, 'mobileHomepage'])
        ->host('m.example.com')
    ;
    $routes->add('homepage', '/')
        ->controller([MainController::class, 'homepage'])
    ;
};

return $routes;

        两条路径匹配相同的路径/,但第一条路径仅在主机为m.example.com时匹配。

在主机名中使用占位符

        此外,主机名与路径匹配系统拥有相同的语法,这就意味着可以在主机名中使用占位符,如{project}等。占位符也可以使用defaults设置和requirements设置,并且占位符的requirements规则也可使用服务参数。如下所示:

注释形式

// src/Controller/MainController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class MainController extends AbstractController
{
    /**
     * @Route(
     *     "/",
     *     name="mobile_homepage",
     *     host="m.{domain}",
     *     defaults={"domain"="%domain%"},
     *     requirements={"domain"="%domain%"}
     * )
     */
    public function mobileHomepage()
    {
        // ...
    }

    /**
     * @Route("/", name="homepage")
     */
    public function homepage()
    {
        // ...
    }
}

YAML形式

# config/routes.yaml
mobile_homepage:
    path:       /
    host:       "m.{domain}"
    controller: App\Controller\MainController::mobileHomepage
    defaults:
        domain: '%domain%'
    requirements:
        domain: '%domain%'

homepage:
    path:       /
    controller: App\Controller\MainController::homepage

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="mobile_homepage"
        path="/"
        host="m.{domain}"
        controller="App\Controller\MainController::mobileHomepage">
        <default key="domain">%domain%</default>
        <requirement key="domain">%domain%</requirement>
    </route>

    <route id="homepage" path="/" controller="App\Controller\MainController::homepage" />
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\MainController;

return function (RoutingConfigurator $routes) {
    $routes->add('mobile_homepage', '/')
        ->controller([MainController::class, 'mobileHomepage'])
        ->host('m.{domain}')
        ->defaults([
            'domain' => '%domain%',
        ])
        ->requirements([
            'domain' => '%domain%',
        ])
    ;
    $routes->add('homepage', '/')
        ->controller([MainController::class, 'homepage'])
    ;
};

导入路由的主机匹配

        最后,我们还可以使用导入路由的主机匹配,在导入路由的路径上设置主机选项。如下所示:

注释形式

// src/Controller/MainController.php
namespace Acme\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route(host="hello.example.com")
 */
class MainController extends AbstractController
{
    // ...
}

YAML文件

# config/routes.yaml
app_hello:
    resource: '@AcmeHelloBundle/Resources/config/routing.yaml'
    host:     "hello.example.com"
    controller: Acme\HelloBundle\Controller\MainController # 自行修改后添加,???
# 以上注释形式的路由定义,是在MainController下的路由代入,为什么在配置文件中没有体现呢?

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd"> 
    <import resource="@AcmeHelloBundle/Resources/config/routing.xml" host="hello.example.com" />
</routes>

PHP文件

// config/routes.php
$routes = $loader->import("@AcmeHelloBundle/Resources/config/routing.php");
$routes->setHost('hello.example.com');

return $routes;

 

测试控制器

如果要在功能测试中获取过去的url匹配,则需要在请求对象上设置Host HTTP标头:

1
2
3
4
5
6
7
$crawler = $client->request(
    'GET',
    '/homepage',
    [],
    [],
    ['HTTP_HOST' => 'm.' . $client->getContainer()->getParameter('domain')]
);

4)Dynamic Requirements with Condition Expressions 通过条件限制路由匹配

        路由匹配,除了可以通过"路由占位符"、"HTTP方法"或"主机名"外,如果需要更灵活地定义任意匹配逻辑,还可以使用conditions路由选项。如下所示:

注释形式

// src/Controller/DefaultController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends AbstractController
{
    /**
     * @Route(
     *     "/contact",
     *     name="contact",
     *     condition="context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"
     * )
     *
     * expressions can also include config parameters
     * condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'"
     */
    public function contact()
    {
        // ...
    }
}

YAML文件

# config/routes.yaml
contact:
    path:       /contact
    controller: 'App\Controller\DefaultController::contact'
    condition:  "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"
    # expressions can also include config parameters
    # condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'"

XML文件

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="contact" path="/contact" controller="App\Controller\DefaultController::contact">
        <condition>context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'</condition>
        <!-- expressions can also include config parameters -->
        <!-- <condition>request.headers.get('User-Agent') matches '%app.allowed_browsers%'</condition> -->
    </route>
</routes>

PHP文件

// config/routes.php
namespace Symfony\Component\Routing\Loader\Configurator;

use App\Controller\DefaultController;

return function (RoutingConfigurator $routes) {
    $routes->add('contact', '')
        ->controller([DefaultController::class, 'contact'])
        ->condition('context.getMethod() in ["GET", "HEAD"] and request.headers.get("User-Agent") matches "/firefox/i"')
        // expressions can also include config parameters
        // 'request.headers.get("User-Agent") matches "%app.allowed_browsers%"'
    ;
};

         这个condition是一个表达式,您可以在此处了解有关其语法的更多信息:表达式语法https://symfony.com/doc/current/components/expression_language/syntax.html。此处的匹配逻辑是,HTTP方法是GET或HEAD,并且请求的User-Agent 报头中含有firefox字样

         您可以通过利用传递到表达式中的两个变量,来执行表达式中所需的任何复杂逻辑:

context

        一个实例RequestContext,其中包含有关匹配路由的最基本信息。

request

        Symfony Request对象(请参阅请求)。