将 URL 转换为一种标准格式
Posted
技术标签:
【中文标题】将 URL 转换为一种标准格式【英文标题】:Convert URL into one standard format 【发布时间】:2019-01-12 03:04:03 【问题描述】:这里有几个网址:
http://sub.example.com/?feed=atom&hello=world
http://www.sub.example.com/?feed=atom&hello=world
http://sub.example.com/?hello=world&feed=atom
http://www.sub.example.com/?hello=world&feed=atom
http://www.sub.example.com/?hello=world&feed=atom
http://www.sub.example.com/?hello=world&feed=atom#123
如您所见,它们都指向完全相同的页面,但 URL 格式不同。这是另外两个基本示例:
http://example.com/hello/
http://example.com/hello
两者都是一样的。
我想将 URL 转换成one 标准格式,这样当我将URL 存储在数据库中时,我可以很容易地检查URL 字符串是否已经存在于数据库。
由于 URL 的格式设置方式多种多样,这可能会令人费解。
的权威方法是什么?也许parse_url()
路线...?
编辑
正如 cmets 中所述,没有明确的解决方案,但我们的目标是尽可能接近我们所拥有的页。在发布此赏金的答案之前,请阅读 cmets。
【问题讨论】:
这其实是一个超级有趣的问题。 +1 不确定是否有明确的方法,除非您拥有提供这些 URL 的网站。如果不检索每个 URL、创建校验和并比较校验和值,就无法确定或证明所有这些 URL 都是相同的。 目的是,例如,它将始终为http://sub.example.com/?feed=atom&hello=world
这些是不同的网址。 www.sub.*
和 sub.*
理论上可以指向不同的页面。你能做的最好的就是对查询字符串进行排序。同样,尾部斜杠也表示不同的 url。
正确的解决方法是打开网址,看看是否返回301重定向;然后存储重定向的 url。或扫描页面寻找<link rel=canonical>
标签。网站使用这两种技术来指示相同 URL 的“首选”变体。
【参考方案1】:
避免在url中传递参数。使用 JSON 将参数传递到网页。
【讨论】:
认真的吗?你有具体的原因吗?【参考方案2】:所有答案都包含大量信息。假设您使用的是类似 Apache 的服务器,对于 URL 位,我将使用 .htaccess(或者,如果您可以更改它 - 等效的服务器 Apache 配置文件)来进行重写。举个简单的例子:
RewriteEngine on
RewriteBase /
RewriteCond %HTTP_HOST ^www\.example\.com$
RewriteRule (.*) http://example.com/$1 [R=Permanent]
在本例中,“R=Permanent
”确实进行了重定向。这通常不是一个大问题,因为,a)它告诉浏览器记住重定向,b)您的内部链接可能是相对的,因此协议(http 或 https)和服务器(example.com 或其他)被保留。因此,通常重定向将是每个会话一次或更少 - 花费时间,IMO,以避免在 php 中执行所有这些操作。
我猜你也可以用它来重写查询位的顺序,尽管当查询位很重要时,我倾向于(不建议你这样做,只是说)将它们添加到我的路径中(例如 rewrite " .../blah/atom
" 到 ".../blah.php?feed=atom
")。无论如何,有很多可用的重写技巧,我建议你阅读它们
Apache mod_rewrite.
如果您确实走这条路,请务必仔细考虑您想要发生的事情 - 一旦您开始使用 URL,您通常会在很长一段时间内无法做出决定。
【讨论】:
除非我弄错了这不是 OP 的网站。这是一个可以使用不同 URL 访问的站点,他只想存储其中一个。如果这实际上是他的网站,那么您的答案就是正确的,但我认为情况并非如此。 好吧,如果他在做日志处理或类似的事情,那么你的观点是正确的,并且同意这会偏离目标。如果是这样的话,我稍后会给出答案。【参考方案3】:我的原始答案假设这些页面都归 OP 所有,根据“如您所见,它们都指向完全相同的页面,但 URL 格式不同......”这一行。我正在调整答案以处理多个选项,并添加您可以和不能对 URL 做出的假设列表。
正如其他人指出的那样,如果您不知道页面是否相同,则没有明确的简单答案。但是,如果您遵循这些假设,您应该可以安全地标准化一些事情:
可以假设
具有相同值的查询字符串无论顺序如何都指向相同的位置。示例:https://example.com/?fruit=apple&color=red 与 https://example.com/?color=red&fruit=apple 相同
可以遵循 301 重定向到特定来源。如果您收到 301 重定向响应,请按照重定向并使用该 URL。您可以放心地假设,如果某个 URL 确实指向同一个页面,并且页面排名得到了优化,那么您就可以关注它。
如果 html 中只有一个 <link rel="canonical">
标签,它也可以用来覆盖规范链接(原因见下文)。
不能假设
如果它们不同,则任何 URL 都保证与任何其他 URL 相同(在这种情况下,通过 URL,我指的是查询字符串之前的任何内容)。
http://example.com 可以不同于https://example.com 可以不同于http://www.example.com 或https://www.example.com。在输入“www”或将其排除在外时,显示不同的网站没有任何限制。这就是为什么在搜索引擎上的页面排名在这里真的被破坏了。任何两个 URL,即使它们当前具有完全相同的内容,也会保持完全相同的内容。一个例子是https://example.com/test 和https://sub.example.com/test。两者都可以设置为相同的通用测试页面内容。将来,https://sub.example.com/test 可能会更改。你不能假设它不会。
如果您拥有该网站
以您想要的 URL 格式的第一部分重定向所有流量:您想要www.example.com
或example.com
还是sub.example.com
?你想要一个斜线还是不?首先使用服务器规则或 PHP 重定向它。这对搜索页面排名也非常有益(如果这对您很重要)。
这方面的一个例子是这样的:
if (!$_SERVER['HTTPS'] || 'example.com' !== $_SERVER['HTTP_HOST'] || rtrim($_SERVER['PHP_SELF'], '/') !== $_SERVER['PHP_SELF'])
header('HTTP/1.1 301 Moved Permanently');
header('Location: '. 'https://example.com/'.rtrim($_SERVER['PHP_SELF']), '/'));
exit;
最后,要管理任何剩余的 SEO 问题,您可以添加此 HTML 标记:
`<link rel="canonical" href="<?php echo $url; ?>">`
无论您是否拥有网站,您都可以标准化查询顺序
即使您不控制网站,也可以假设查询顺序无关紧要。要标准化这一点,请获取您的查询并重建参数,将其附加到您的规范化 URL。
function getSortedQuery()
$url = [];
parse_str($_SERVER['QUERY_STRING'], $url);
ksort($url);
return http_build_query($url);
$url = $_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.getSortedQuery();
另一种选择是抓取页面内容并查看是否有<link rel="canonical">
字符串,并使用该字符串记录您的数据。这有点贵,因为它需要加载整个页面。
重复一遍,请确保您获取 301 重定向,因为它们不是建议,而是关于最终结果 URL 的指令。
最后一个建议
我可能建议使用两列,一列是“canonical_url”,另一列是“effective_url”。有时一个 URL 可以工作,然后变成 301 重定向。这只是我的看法,但我想知道这些事情。
【讨论】:
除非我弄错了这不是 OP 的网站。这是一个可以使用不同 URL 访问的站点,他只想存储其中一个。如果这实际上是他的网站,那么您的答案就是正确的,但我认为情况并非如此。 然后引用“如您所见,它们都指向完全相同的页面,但 URL 格式不同......”是不正确且具有误导性的。【参考方案4】:重复 URL 就是这种情况,您可以使用 URL 工厂将所有不正确的 URL 重定向到正确的 URL,从而避免此类重复的 URL。
这篇文章也解释了同样的事情:
https://www.tinywebhut.com/remove-duplicate-urls-from-your-website-38
任何其他指向同一页面的 URL 都会被 301 重定向到正确版本的 URL。
这是搜索引擎优化 (SEO) 的最佳实践。下面我给大家举几个例子。
你可以考虑一下这个网站的网址,比如这个页面的错误链接是
https://***.com/questions/51685850
https://***.com/questions/51685850/convert-url-into-one-s
https://***.com/questions/51685850/
如果您转到此页面的上述错误 URL,您将被重定向到正确的 URL,即
https://***.com/questions/51685850/convert-url-into-one-standard-format
如果您更改此问题的标题,所有其他 URL 都会 301 重定向到正确的 URL。这里的想法是 301 重定向,它告诉搜索引擎用新 URL 替换旧 URL,否则搜索引擎会找到提供相同内容的不同 URL。
这里真正的问题是问题的 ID,51685850
。此 id 用于使用数据库中的信息创建正确的 URL。使用在文章中提供的链接中创建的 URL 工厂,您甚至不需要将 URL 存储在数据库中。
您可以在此处阅读有关重复内容的更多信息:
https://moz.com/learn/seo/duplicate-content
同样的规则也适用于 tinywebhut.com,错误的 URL 是
https://www.tinywebhut.com/remove-duplicate-38
https://www.tinywebhut.com/some-text-38
https://www.tinywebhut.com/remove-duplicate-urls-from-your-website-38/
在上述 URL 中,ID 附加到 URL 的末尾,即38
,如果您访问这些 URL 中的任何一个,您将被 301 重定向到正确版本的 URL,即
https://www.tinywebhut.com/remove-duplicate-urls-from-your-website-38
这里我没有做任何函数来解释,因为这篇文章已经做了:
https://www.tinywebhut.com/remove-duplicate-urls-from-your-website-38
您可以通过几个非常简单的功能来实现该目标,并且您可以应用相同的想法来删除其他重复的 URL,例如 /about.php
、/about
、/about.php/
、/about/
等。要实现这一点,您只需要为现有函数添加更多代码。
另一种方法是添加规范标签,例如,即使您有多个 URL 可以访问同一页面,您只需应用规范标签并将链接添加到正确的 URL。
<link rel="canonical" href="https://***.com/questions/51685850/convert-url-into-one-standard-format" />
通过这种方式,您告诉搜索引擎多个 URL 应被视为一个,并且搜索引擎将在其搜索结果中添加规范标签中使用的链接。您可以在此处阅读有关规范化的更多信息:
https://moz.com/learn/seo/canonicalization
但摆脱重复内容的最佳方法仍然是 301 重定向。如果您像我一开始所说的那样进行 301 重定向,那么所有问题都会毫无意外地解决。
【讨论】:
【参考方案5】:由于问题被标记为“PHP”,我假设您在后端。
有足够的答案可以比较 URLs(协议、主机、端口、路径、请求参数列表),其中路径区分大小写,协议和主机不区分。更改请求参数的顺序严格来说也是更改 URL。
我的印象是,您希望通过服务器所服务的 RESOURCE 来区分(http://www.sub.example.com/ 提供与 http://sub.example.com/ 相同的资源或 .../hello 提供与 . ../你好/)
服务于哪个资源,您应该完全了解后端级别,因为您(后端)知道您在服务什么。找到资源的完美 ID 并使用它。
PS:URL 不是一个好的标识符。但是,如果您必须使用它,只需使用经过清理的版本(出于您的目的进行清理 => 清理到您的首选主机,在路径末尾去除或添加斜杠,从路径中删除 /../ 之类的内容(无论如何都是安全问题),带来请求参数按特定顺序排列,无论您的目的是否正确。
最好的问候,iPirat
【讨论】:
【参考方案6】:正如一些人指出的那样,虽然您显示的 URL 当前可能指向相同的内容,但无法判断它们将来是否会指向相同的内容。协议或主机名的更改可以为您提供不同的内容集,即使是 example.com
与 www.example.com
,即使由同一台机器在同一 IP 提供服务。不常见,但可能会发生......
因此,如果我想维护一个 URL 列表,我将存储协议、主机名、目录路径、文件名(如果存在)(也称为“问号前最后一个斜杠之后的任何内容”),以及按密钥集排序的GET 参数的键/值对
然后别忘了你可以去https://www.google.com
,除了协议和主机名之外什么都没有......
【讨论】:
【参考方案7】:将首选的<link rel="canonical" ... >
标记添加到HTML 标头中是唯一可靠的解决方案,以便将唯一内容引用到单个SEF URL
。请参阅 Google 的有关 Consolidate duplicate URLs 的文档,它可能比我以往任何时候都更权威、更可靠地回答了整个问题。
无需解析那些服务器的.htaccess
rewrite-rules 或 HTML 标头就能够知道规范 URL 或解析一堆外部 URL 的想法似乎不适用(仅仅是因为可以维护一个带有 URL 别名的表,随后不允许猜测 HTTP 请求可能是如何被重写的)。
这个问题可能属于https://webmasters.stackexchange.com/search?q=cannonical。
【讨论】:
【参考方案8】:我在报告配置保存功能方面遇到了同样的问题。在我们的系统中,用户可以设计自己的销售报表(如 Jira 的 JQL);为此,我们使用 get params 作为条件,使用片段标识符(# 之后)作为布局设置,如下所示:
http://example.com/report.php?since=20180101&until=20180806#sort=amount&color=blue
对于我们的系统,GET 的顺序或 # 参数之后的顺序也无关紧要,如果将参数设置为“until”而不是“since”,那么您会达到相同的报告配置,所以对我们来说是相同的请求。
考虑到这一点,子域不在讨论范围之内,因为您必须使用重写技术(如 Apache 中的 mod_rewrite 和 301)来解决这个问题,或者在软件级别创建域异常池来执行此操作。此外,不同的域可以指向不同的网站,因此您必须决定是否是一个好主意;在 subdos 中“www”很容易弄清楚,但在其他情况下会花费你时间。
服务器端可以帮助在查询部分获取变量。例如,在 PHP 中,您可以使用函数 parse_str 和 $_SERVER['QUERY_STRING'] 来获取数组,然后,您需要使用 asort() 来命令它最终比较是否是相同的请求(array_diff 函数)。
不幸的是,服务器端不是一个选项,因为无法获取哈希 (#) 内容,我们仍然没有考虑其他问题,例如包含脚本名、协议或端口:
http://www.sub.example.com/index.php?hello=world&feed=atom
https://www.sub.example.com/?hello=world&feed=atom
http://www.sub.example.com:8081/?hello=world&feed=atom
以我个人的经验,最接近的解决方案是 javascript,用于处理 url,将查询部分解析为数组,比较它们并对片段标识符执行相同的操作。如果您需要在服务器端使用它,则每个加载页面都必须跟随一个 ajax 请求,将这些数据发送到服务器。
提前为我的回答长度道歉,但这是我为了解决您遇到的相同问题而必须经历的。问候!
从 URL 获取协议、域和端口 Get protocol, domain, and port from URL
如何在 JavaScript 中获取查询字符串值? How can I get query string values in JavaScript?
如何从 URL 中获取片段标识符(哈希 # 后的值)? How do I get the fragment identifier (value after hash #) from a URL?
【讨论】:
【参考方案9】:在你之后parse_url
:
-
从域名中删除
www
前缀
如果 路径 不为空 - 删除尾部的斜杠
按名称的字母顺序对查询参数进行排序 - 如果有的话
组合这些部分以获得规范的 URL。
【讨论】:
1) 如果 www.example.com 和 example.com 不同怎么办 (ii) 如果需要尾部斜杠怎么办,例如当 url 是目录时? OP 暗示,对于他的 URL,www
和非www
的含义相同,并且服务器会忽略/删除尾部斜杠。
你必须强调你不能暗示任何事情。即使是谷歌也有重复网址的问题。
因此没有解决此问题的definite
方法。问题已结束。以上是关于将 URL 转换为一种标准格式的主要内容,如果未能解决你的问题,请参考以下文章
如何将任何日期格式转换为一种日期格式,即 ddMMMMYYYY(10Apr2018)