我从未见过<base> HTML标签实际上在任何地方使用。它的使用是否存在意味着我应该避免使用的陷阱?

事实上,我从未注意到它在现代生产站点(或任何站点)上使用过,这让我对它持怀疑态度,尽管它似乎在简化我站点上的链接方面有有用的应用程序。


Edit

After using the base tag for a few weeks, I did end up finding some major gotchas with using the base tag that make it much less desirable than it first appeared. Essentially, the changes to href='#topic' and href='' under the base tag are very incompatible with their default behavior, and this change from the default behavior could easily make third party libraries outside of your control very unreliable in unexpected ways, since they will logically depend on the default behavior. Often the changes are subtle and lead to not-immediately-obvious problems when dealing with a large codebase. I have since created an answer detailing the issues that I experienced below. So test the link results for yourself before you commit to a widespread deployment of <base>, is my new advice!


当前回答

我将在为什么不应该设置<base href>标记的长长的原因列表中再添加一个参数。正如许多人在这里注意到的,设置<base href>会改变#anchor和?query URL的行为——它们附加到基本href,而不是文档自己的URL的回退基础。

您可能认为设置<base href="https://example.com/the/documents/own/url">可以解决这个问题,并且一切都将正常运行。你错了。

在现实世界的web中,?query=参数一直用于会话属性(如谷歌Analytics)和许多其他事情。这些参数中有许多是专门供脚本在客户端使用的;服务器不会关心它们,也不会对它们做任何事情。

假设您正在为example.com/landing-page提供服务,其中包含<base href="example.com/landing-page">,并且页面上有一个到#菜单的链接。然后有人通过URL example.com/landing-page?source=my-marketing-campaign到达那里。

如果没有<base href>,当他们单击#菜单时,浏览器将识别页面内导航并立即跳转到该部分。

但是,由于定义的base href example.com/landing-page缺少查询参数source=my-marketing-campaign,浏览器不能确定它是一个页面内链接。因此,单击#menu将触发一个新的HTTP请求,页面(及其所有非缓存资产)将重新加载。最好的情况是,这是对各方时间和带宽的毫无意义的浪费。在最坏的情况下,状态和数据可能会丢失。

对于静态站点来说,这是没有办法的。如果您正在使用CMS,您可能会想一下,您可以动态地将<base href>设置为请求URL,包括所有参数。虽然这可以解决刷新问题,但最终会遇到缓存问题和噩梦般的安全漏洞。

底线:<base href>会给你带来麻烦,不管你把它设置成什么。不要这样做。

如果你担心恶意脚本可能会注入自己的<base href="evil.com">标记(例如在nonce重定向攻击中),2022年的最佳解决方案似乎是将base-uri指令添加到你的内容安全策略中。

其他回答

要决定是否应该使用它,您应该了解它的功能以及是否需要它。这一点在我的回答中已经有了部分概述,我也对此做出了贡献。但是为了更容易理解和理解,这里有第二个解释。首先我们需要了解:

浏览器如何处理没有<BASE>被使用的链接?

对于一些例子,让我们假设我们有这些url:

一)http://www.example.com/index.html B) http://www.example.com/ C) http://www.example.com/page.html D) http://www.example.com/subdir/page.html

A和B都会将相同的文件(index.html)发送到浏览器,C当然发送page.html, D发送/subdir/page.html。

让我们进一步假设,两个页面都包含以下类型的链接:

完全限定的绝对链接(http://www…) 本地绝对链接(/some/dir/page.html) 相对链接,包括文件名(dir/page.html)和 只有“分段”的相对链接(#anchor, ?foo=bar)。

浏览器接收页面,并呈现HTML。如果它找到某个URL,它需要知道指向哪里。对于Link 1)来说,这一点总是很清楚的,因为它是按原样进行的。所有其他依赖于呈现页面的URL:

URL     | Type | Result
--------+------+--------------------------
A,B,C,D |    2 | http://www.example.com/some/dir/page.html
A,B,C   |    3 | http://www.example.com/dir/page.html
D       |    3 | http://www.example.com/subdir/dir/page.html
A       |    4 | http://www.example.com/index.html#anchor
B       |    4 | http://www.example.com/#anchor
C       |    4 | http://www.example.com/page.html#anchor
D       |    4 | http://www.example.com/subdir/page.html#anchor

现在使用<BASE>会有什么变化?

<BASE>应该替换浏览器显示的URL。因此,它呈现所有链接,就好像用户调用了<BASE>中指定的URL一样。这解释了其他几个答案中的一些困惑:

again, nothing changes for "fully qualified absolute links" ("type 1") for "local absolute links", the targeted server might change (if the one specified in <BASE> differs from the one being called initially from the user) "relative URLs" become critical here, so you've got to take special care how you set <BASE>: better avoid setting it to a directory. Doing so, links of "type 3" (relative dir + filename) might continue to work, but it most certainly breaks those of "type 4" (relative + segment); except for "case B" (no path or filename). setting it to the fully qualified file name produces, in most cases, the desired results.

举个例子最好地说明了这一点

假设你想用mod_rewrite“美化”一些URL:

<DOCUMENT_ROOT>/some/dir/file.php?lang = en 真实网址:http://www.example.com/some/dir/file.php?lang=en 友好的网址:http://www.example.com/en/file

让我们假设mod_rewrite用于透明地将用户友好的URL重写为真实的URL(没有外部重定向,因此“用户友好”的URL保留在浏览器的地址栏中,而真实的URL被加载)。现在该怎么办?

no <BASE> specified: breaks all relative links (as they would be based on http://www.example.com/en/file now) <BASE HREF='http://www.example.com/some/dir>: Absolutely wrong. dir would be considered the file part of the specified URL, so still, all relative links are broken. <BASE HREF='http://www.example.com/some/dir/>: Better already. But relative links of "type 4" are still broken (except for "case B"). <BASE HREF='http://www.example.com/some/dir/file.php>: Exactly. Everything should be working with this one.

最后一点

请记住,这适用于文档中的所有url:

< A HREF = < IMG SRC = < SCRIPT SRC = ...

有一件事要记住:

如果你要开发一个在iOS上的UIWebView中显示的网页,那么你必须使用BASE标签。否则它根本不会起作用。无论是JavaScript, CSS,图像-没有一个将工作在UIWebView下的相对链接,除非标签BASE被指定。

我以前也遇到过这种情况,直到我发现。

我将在为什么不应该设置<base href>标记的长长的原因列表中再添加一个参数。正如许多人在这里注意到的,设置<base href>会改变#anchor和?query URL的行为——它们附加到基本href,而不是文档自己的URL的回退基础。

您可能认为设置<base href="https://example.com/the/documents/own/url">可以解决这个问题,并且一切都将正常运行。你错了。

在现实世界的web中,?query=参数一直用于会话属性(如谷歌Analytics)和许多其他事情。这些参数中有许多是专门供脚本在客户端使用的;服务器不会关心它们,也不会对它们做任何事情。

假设您正在为example.com/landing-page提供服务,其中包含<base href="example.com/landing-page">,并且页面上有一个到#菜单的链接。然后有人通过URL example.com/landing-page?source=my-marketing-campaign到达那里。

如果没有<base href>,当他们单击#菜单时,浏览器将识别页面内导航并立即跳转到该部分。

但是,由于定义的base href example.com/landing-page缺少查询参数source=my-marketing-campaign,浏览器不能确定它是一个页面内链接。因此,单击#menu将触发一个新的HTTP请求,页面(及其所有非缓存资产)将重新加载。最好的情况是,这是对各方时间和带宽的毫无意义的浪费。在最坏的情况下,状态和数据可能会丢失。

对于静态站点来说,这是没有办法的。如果您正在使用CMS,您可能会想一下,您可以动态地将<base href>设置为请求URL,包括所有参数。虽然这可以解决刷新问题,但最终会遇到缓存问题和噩梦般的安全漏洞。

底线:<base href>会给你带来麻烦,不管你把它设置成什么。不要这样做。

如果你担心恶意脚本可能会注入自己的<base href="evil.com">标记(例如在nonce重定向攻击中),2022年的最佳解决方案似乎是将base-uri指令添加到你的内容安全策略中。

我已经找到了一种方法来使用<基础>和基于锚的链接。您可以使用JavaScript来保持像#contact这样的链接正常工作。我在一些视差页面中使用了它,它很适合我。

<base href="http://www.mywebsite.com/templates/"><!--[if lte IE 6]></base><![endif]-->

...content...

<script>
var link='',pathname = window.location.href;
$('a').each(function(){
    link = $(this).attr('href');
    if(link[0]=="#"){
        $(this).attr('href', pathname + link);
    }
});
</script>

你应该用在这一页的末尾

它可能不是很流行,因为它不是很出名。我不会害怕使用它,因为所有主流浏览器都支持它。

如果您的站点使用AJAX,您将希望确保所有页面都正确设置了AJAX,否则可能会出现无法解析的链接。

只是不要在HTML 4.01 Strict页面中使用target属性。