symfony配置文件之三:routing和路由配置
目录
4、添加requirements (针对url占位符或host占位符)
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方法,而不是GET
和POST
,那么你需要包括一个_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标头:
|
|
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