用户脚本中的@include 和@match 有什么区别?

What is the difference between @include and @match in userscripts?

GreaseSpot page on metadata blocks says that the two are very similar but @match "sets more strict rules on what the * character means." GreaseSpot then proceeds to teach using @include, but Chrome examples like this一般好像用@match表示支持@include只是为了兼容; @match 优先。

Apparently@include google.* 可以在 google.evil.com 上 运行 而 @match google.* 不能。
一个例子不足以真正了解通配符在这两者之间的行为有何不同,请在此处的答案中寻求更好的解释。

新的 GreaseMonkey 脚本 (Firefox) 默认使用 @include 而新的 TamperMonkey 脚本(例如 Chrome)默认使用 @match

这两者到底有什么区别?

例如,每个人如何处理通配符?
跨浏览器兼容性是否存在差异?
人们有什么理由选择使用其中之一?

您不能对 @match 使用正则表达式,而 can@include

但是,@include 将向您的用户发出有关该脚本适用于所有站点的更可怕的安全警告。

尽管 @include 表达式允许您对脚本适用的站点 更具限制性(例如指定 URL 使用正则表达式片段 [0-9]+ 或使用 ^https?:// 将这两个方案应用于脚本,而不是用于每个方案的更通用的非正则表达式 globbing 运算符 * @match 中的案例,这导致脚本的应用范围更广)。

TL;DR:刚度

最重要的区别是 @match@include 更严格、更严格,旨在成为更安全的替代方案。因此,@include 也可能会向最终用户生成更可怕的警告;整体使用起来也有点复杂,这取决于你如何看待它。

两者的实际用法实际上可以有很大的不同;下面是每个用法的完整细分。


@include(和@exclude

@include 可能是大多数人更熟悉的指令(连同它的对立双胞胎,@exclude,它们具有完全相同的语法特征)。这是两者中更强大的指令,主要是因为它可以处理 RegEx 模式(这也意味着它会生成更可怕的警告)。它的用法也是两者中最直接的。

模式

您可以通过两种方式指定模式/“模式”:

全局模式

星号 * 可用作 wildcard glob,即表示 任意 个字符,包括零。

For example:

  • @include http://www.example.com/foo/*:
    • 匹配 http://www.example.com/foo/http://www.example.com/foo/bar
    • 匹配http://www.example.com/baz

还有一个特殊模式可用于专门匹配任何顶级域后缀:.tld.

@include https://www.example.tld/* 这样的模式将匹配具有 任何顶级域 后缀的给定域,例如 .com.org、或 .co.uk.

正则表达式模式

@include/ 字符开头的指令将被解释为正则表达式,具有所有可用的标准 JavaScript RegEx 功能:

// ==UserScript==
// @include     /^https?://www\.example\.com/.*$/
// @include     /^http://www\.example\.(?:org|net)//
// ==/UserScript==

一些注意事项:

  • 由于 JavaScript 的 RegEx 解释,正斜杠 / 不需要在表达式中转义。
  • Other special characters还需要转义
  • @include 模式总是被视为 不区分大小写
  • 不以 EOL 标记结尾的表达式 $ 将隐式允许匹配项中的尾随字符。
    • 换句话说,表达式被视为以 .* 结尾。
    • @include /^https?://www\.google\.com/search/ 将匹配 https://www.google.com/search?q=Whosebug.

警告

请记住,@include 的强大特性意味着浏览器无法像使用 @match 的脚本那样保证给定脚本的目标;这意味着使用 @include 的脚本可能会为用户触发更可怕和严重的警告。

不使用 @include 的一个常见原因涉及 URL 片段(散列 # 字符后的 URL 部分),以及恶意行为者如何能够滥用它们在不需要的页面上执行脚本(例如 @include http://*.example.com/ 可以匹配 www.evil.com#www.example.com/),因为 @match 在设计上会忽略片段。

虽然这种攻击在理论上仍然是可能的,但值得记住的是,一些用户脚本管理器(包括 Tampermonkey)为了匹配目的故意完全忽略片段,即使在 @include 指令中也是如此。


@match

@match 指令是 Google 为 Chrome 创建的,被设计为 @include 指令的更安全、更沙盒化的版本,更多 更坚固的内置。

不是允许 glob 或 RegEx,@match 将模式解释为 3 个部分:方案主机、和 路径 Google's documentation 这样描述基本语法:

<url-pattern> := <scheme>://<host><path>
<scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'urn'
<host> := '*' | '*.' <any char except '/' and '*'>+
<path> := '/' <any chars>

模式的每一部分都有自己的注意事项,并且对通配符*的解释也不同

方案

URL 模式的方案部分必须与支持的方案之一(这似乎取决于浏览器)或通配符 *.

完全匹配
  • 在 Chrome 中,即:httphttpsfileftpurn
  • In Firefox,好像是 httphttpsfileftpwswss , data, 或 (chrome-)extension.

在这部分模式中,通配符 * 只匹配 httphttpsMDN mentions 它可能在某些浏览器中也匹配 WebSocket 方案 wswss

主持人

URL 模式的主机部分可以采用三种样式:

  • 完全明确:www.whosebug.com
  • 子域通配符:*.whosebug.com
  • 完全通配符:*

顶级域名后缀不能为通配符(如www.Whosebug.*); this is disallowed for security reasons。为了匹配多个 TLD 后缀,脚本需要为每个后缀包含一个特定的 @match 指令。

路径

URL 模式的路径部分是 3 种模式中最宽松的,因为唯一的规则是它必须以正斜杠 / 开头。其余可以是字符和通配符的任意组合。

在本节中,通配符 * 充当标准的 glob 运算符,仅匹配 0 个或多个字符。

与模式的路径部分匹配的值正式是 URL 路径 加上 URL 查询字符串(例如。在google.com/search?q=test中,查询字符串是q=test),包括?之间。对于旨在匹配给定域结尾的模式来说,这是一个潜在的陷阱,因为它们可能会被添加的查询字符串挫败。

另请注意,该路径 包括 URL 片段(末尾的 URL 部分跟随散列 #,例如 www.example.com#main); @match 指令故意忽略 URL 片段以防止滥用无意的匹配。


注意事项

这很明显,但值得重复的是,脚本应该小心 @include 完全 独占 URL 表示该脚本将 运行 启用。失控脚本的范围从无法检测到的小麻烦到大问题不等;始终仔细检查脚本 运行 只在它们应该在的位置,并在必要或方便时使用 @exclude 添加防护栏。