【问题标题】:How to check if two URL's lead to the same path?如何检查两个 URL 是否指向同一路径?
【发布时间】:2021-08-06 08:58:03
【问题描述】:

我正在构建一个 URL Shortener,我决定尽可能回收短 ID 以节省数据库空间。如何检查 2 个 URL 是否指向同一路径?

例如,假设用户为https://google.com/ 生成了一个短网址。

我的应用生成以下短 id:jkU3

因此,如果此用户访问https://tiny.url/jkU3,我的快速服务器会将访问者重定向到https://google.com/

这就像一个魅力,但知道让我们假设另一个人访问 https://tiny.url/ 并为 https://google.com 生成一个短 URL。另一个来为https://www.google.com/ 生成一个短URL,另一个来为https://www.google.com 生成一个短URL。你明白了..

到目前为止,我的应用会浪费 4 个短 ID。

如何防止这种情况发生?这个有正则表达式吗?

这是我用于生成短 URL 的当前代码:

app.post("/", (req: Request, res: Response) => {
  const shortUrl: string = nanoid(4);
  const destination: string = req.body.destination;

  UrlSchema.create({
    _id: mongoose.Types.ObjectId(),
    origin: shortUrl,
    destination: destination,
  }).then(() => {
    // Unique Id
    res.json(shortUrl);
  });
});

【问题讨论】:

  • 虽然在 google 的情况下这似乎是对短 ID 的浪费,但请注意有些网站可以使用 www,而有些网站可以不使用。有些网站使用最后一个/,但有些网站没有,并且如果系统管理员不能很好地完成这项工作,他们可能会忘记对有和没有/ 的页面进行正确的重定向。在某些情况下,网页可能与 http/https 一起使用,而您不能只使用一种协议。所以总而言之,除了将所有 url 设置为相同的大写或小写之外,我不建议您对它们进行任何更改。因为没有保证
  • 而且通常情况下,用户会将长网址复制/粘贴到您的小网址,而不是手动输入它们。因此,相同 url 出现不同变化的可能性非常小,除非您创建脚本来获取这些 url,并检查 302 重定向并获取最终 url。

标签: node.js regex mongodb express mongoose


【解决方案1】:

在创建新条目之前,您可以检查工作目的地

const existing = await UrlSchema.findOne({destination:req.body.destination});
if(!existing){
    // create new
} else{
    // return same
}

如果目的地尚不存在,您将通过这种方式创建目的地。如果存在 tariling 斜杠 (/) 以更好地匹配 URL,您可以删除它,

【讨论】:

    【解决方案2】:

    您列出了四个略有不同的网址:

    https://www.google.com
    https://google.com
    https://www.google.com/
    https://google.com/
    

    这些在技术上都不是相同的 https 请求,尽管听起来您想假设末尾的 / 是可选的,因此不会使其成为不同的目标 URL。

    后两个不保证与前两个是同一主机。对于google.comwww.google.com,它们是同一个主机,但不能保证所有可能的主机都是这种情况。

    如果您想假设这四个都属于同一个主机,无论域是什么,那么您只需在将 URL 放入数据库之前对其进行规范化,然后在分配新的缩短 ID 之前,您搜索URL 规范化版本的数据库。

    在这种情况下,您将删除 www. 并删除任何尾部斜杠以创建 URL 的规范化版本。

    function normalizeUrl(url) {
        // remove "www." if at first part of hostname
        // remove trailing slash
        return url.replace(/\/\/www\./, "//").replace(/\/$/, "");
    }
    

    规范化 URL 后,您可以在数据库中搜索规范化的 URL。如果找到它,则使用现有的缩短器。如果找不到,则使用新生成的 shortId 将规范化版本添加到数据库中。

    这是一个演示:

    function normalizeUrl(url) {
        // remove "www." if at first part of hostname
        // remove trailing slash
        return url.replace(/\/\/www\./i, "//").replace(/\/$/, "");
    }
    
    const testUrls = [
        "https://www.google.com",
        "https://www.google.com/",
        "https://google.com",
        "https://google.com/",
    ];
    
    for (const url of testUrls) {
        console.log(normalizeUrl(url));
    }

    仅供参考,由于 DNS 中的主机名不区分大小写,您可能还需要强制主机名小写以使其正常化。路径名称或查询参数可能区分大小写(有时是,有时不是)。

    要包括主机区分大小写规范化,您可以使用:

    function normalizeUrl(url) {
        // remove "www." if at first part of hostname
        // remove trailing slash
        // lowercase host name
        return newUrl = url.replace(/\/\/www\./i, "//").replace(/\/$/, "").replace(/\/\/([^/]+)/, function(match, p1) {
            // console.log(match, p1);
            return "//" + p1.toLowerCase();
        });
    }
    
    const testUrls = [
        "https://www.google.com",
        "https://www.google.com/",
        "https://google.com",
        "https://google.com/",
        "https://WWW.google.com",
        "https://www.Google.com/",
        "https://GOOGLE.com",
        "https://google.COM/",
        "https://www.Google.com/xxx",     // this should be unique
        "https://google.COM/XXX",         // this should be unique
    ];
    
    for (const url of testUrls) {
        console.log(normalizeUrl(url));
    }

    【讨论】:

    • 在 normalize 函数中删除 www 是您假设 www.example.com 和 example.com 将导致相同的 url,但实际上,并不能保证带和不带 www 的域会导致相同的页面,并且有些网站甚至无法解析 www
    • @SomeoneSpecial - 这个警告在答案中得到了充分解释。他们是否要做出这个假设取决于 OP。我个人不会。他们的问题表明他们想要。
    猜你喜欢
    • 2011-03-09
    • 2011-07-16
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 2012-07-12
    • 2021-12-02
    相关资源
    最近更新 更多