65.9K
CodeProject 正在变化。 阅读更多。
Home

理解随机 URL 并在 ASP.NET 中创建它们

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (25投票s)

2014 年 11 月 27 日

CPOL

16分钟阅读

viewsIcon

86325

downloadIcon

496

本文介绍随机 URL 的概念以及如何在 ASP.NET 中生成它们,用于为您的应用程序创建随机 URL。

引言

本文介绍随机 URL,它有助于应用程序所有者创建可以保存在数据库或作为短文本传递给下一个应用程序的小型 URL,而不是冗长乏味的 URL。

大多数公司都使用这种技术为他们自己或用户希望添加的任何其他资源文件(如 Twitter、Facebook 和 Tumblr 等)提供短链接。它们允许用户发送指向可能存在的文档的链接

http://www.example.com/post/category/postId/some-other-text-from-post

...到如下链接:

http://www.examp.le/pSij284Fj

现在让我们来理解这个概念,以及如何在我们的 ASP.NET 网站中实现这个功能。但请记住,这是纯 C# 代码,未使用 ASP.NET 命名空间或框架中的任何代码,这意味着您也可以在 WPF、Win Forms 等 .NET 应用程序中使用它。

更长的 URL - 问题

URL 是互联网上特定文档的链接,用户可以随时使用任何可以访问互联网服务的软件访问。有时,这些 URL 长得足以让用户感到烦恼,例如那些 URL 本身包含所有附加信息。以以下 URL 为例:

http://www.example.com/page/category/sub-category/month-date/some-general-fancy-text

这确实是一个很长的文本,大多数 URL 比这个还要长,跨越 500 多个字符。哦,浏览器不太喜欢这些过长的 URL,有时 Internet Explorer 会在处理包含 500 多个字符的 mailto: URL 时出现问题。

不仅浏览器讨厌这些长 URL,搜索引擎也讨厌这些长 URL,而且注意到 Google 甚至不关心索引 1855 个字符左右的 URL。 - 参考

所以,不仅我们用户讨厌这些长 URL(因为关闭标签后我们根本不记得它们,或者需要去历史记录中查找),软件也讨厌这些长 URL,它们有时会阻止使用这些字符的 URL。

为什么不推荐使用

通常有不止一个原因不希望使用这些长 URL。但每个人都有自己的偏好,我也有。我不喜欢在 URL 栏中填入大量数据,我更喜欢只获取网站的域名以及我在站点地图中的位置 - 仅页面。

总之,发送更短的 URL 比发送更大的 URL 更好。URL 中的每个字符都占用一个字节的数据(`char` 的大小为 1 字节),如果使用 Unicode,则可能是 2 字节(请注意,在 Windows 中,字符始终是 Unicode;在 .NET 框架中,将始终使用 2 字节的数据来表示 Unicode 字符)。可以在此处阅读 .NET 中 `char` 的概述。

为了良好的网络连接,以及设备之间数据的平滑传输,最好发送较少的数据开销,以便实际消息能够更快地到达。2048 个字符,每个字符 2 字节,几乎相当于 4kb 的数据,仅用于标识资源。4kb 数据将被添加到创建以传输到网络流中的数据包的开销部分,并且除了用于标识用户将使用的 Web 资源的地址外,别无他用,或者数据必须发送到 - 对于高速互联网用户来说,这不会是麻烦,但对于移动用户或慢速互联网数据包用户来说,这将是一个大问题,因为他们首先必须只发送资源数据,然后才能执行其他任何操作,等等。

总数据量计算,作者 SoMad 2048 * 2 字节 = 4096 字节 = 32768 位 = 4kb - 谢谢!

可以做什么

通常,不会进行 URL 缩短,而是发送长 URL,但必须将其最小化。为此,大多数公司,特别是那个 140 个字符的博客网站“Twitter”需要此功能,他们会在系统中存储长 URL,并仅在他们的 Tweet 中显示简短的 URL。这样,无论 URL 多长,都只有几个字符长 - Twitter 上是 15 个字符,对于其他人来说可能更短,例如 Goo.gl(Google URL 缩短器)和 fb.me(Facebook 的短 URL)等公司。

这使得人们可以编写短 URL,例如,http://exm.pl/AfzaalBlog ,用户可以记住,这会重定向到我的博客。此 URL 更好,因为:

  1. 它很短。
  2. 传输数据时将使用更少的数据。
  3. 它易于记忆。
  4. 它更具语义,并且可以理解用户将要去哪里 - 更像是一个 2-4 个词的句子。

这些是人们应该使用短 URL 的一些原因,不仅仅是为了快速发送数据(通常在快速互联网连接上,短 URL 和长 URL 看起来没有区别,但在慢速连接上会有很大差异)。

随机 URL

如果上面说的“短 URL 更好”是正确的,那么为什么人们还想使用随机 URL 呢?这让他们为每个访问者创建随机 URL 等等,导致一片混乱。

为什么使用随机 URL

短 URL 是一个更好的 URL,上面提到的统计数据解释了这一点。但通常,有一群用户可能希望您为他们所有的资源文件创建一个 URL,这需要用户花费时间填写表单才能在您的服务器上获取一个 `ShortURL`,然后签署一份请愿书同意条款并拿到该 URL 作为短 URL。嗯,这是一个漫长的过程 - 并且包含一点夸张。

为此,网站可能希望创建一组函数,该函数会生成一个随机的字母数字 `string` - 意味着它为每个用户、每次尝试获取新 URL 的操作而生成。它通过检查任何其他先前创建的可能相似的 `string` 来保持随机性。

这些字母数字文本表示创建的 URL 的数量取决于 URL 中允许的总字符数。您可能知道组合和排列的概念,其中字符及其所有匹配字符在 `string` 中排列,以便它们始终代表新的内容。例如,一个简单的 10 个字符的 `string`,可以容纳 9 个数字,可以增长到,哦,我数学不是很好,但我可以告诉你,这足以捕获一个大公司的文档资源而不会重复任何链接。

您可以通过在 URL `string` 中使用小写和大写字母来使其更强大。这样,您的 URL 将会强大 3 倍,并且这种混合足够强大,可以包含足够的 URL,以至于您的任何用户都不会抱怨收到类似“抱歉,URL 已满”的错误。

创建更强大的混合 - 真正的随机 URL

本节在评论中开始 - 由于随机 URL 需要是随机的,并且概念是要生成不超过 7-10 个字符的短 URL。真正要做的是让这些短 URL 在现实生活中也随机,而不仅仅是一个用于 URL 的字符串。

在此示例中,我添加了两个特殊字符以使随机性更强大,同样,URL 必须足够随机,以便在不久的将来或遥远的将来,URL 生成都能足够随机,以最大程度地减少任何重复错误。URL 生成中的重复将导致应用程序中的“停止!”发生,因为将不再生成短 URL,因为应用程序生成 URL 的主要逻辑将失效。

在上面的逻辑中,如果您注意选择字符或数字值的条件,您可以看到数字的选择比例为 1:3,25% 是数字,75% 是字符。我为什么这样做,这对 URL 在现实中有什么影响?

实际上,我们要创建的字符串是 26 个字母的排列组合,它们用作字符,而不仅限于这 26 个,还有两个特殊字符(-,_),它们会稍微增加非重复的几率。现在还有另一个包含数字的列表。将它们混合在一起将创建一个随机 URL。但能持续多久?这取决于混合物,你见过化学家工作吗?他选择特定数量的混合物来创建一个非常稳定的化合物。

同样,向字母集中添加一些数字将产生良好的结果和大量可生成的随机 URL - 统计学或数学学生将帮助我们找到这些列表的良好排列,帮助我们最大程度地减少应用程序中重复的几率。如果数字增加到 50%,则数字和字符的几率为 50/50,使其更容易很快重复。同样,0% 的数字(或很少的几率)也会导致字符在(大量)URL 添加到数据库后开始重复,并且您需要更改或更新应用程序以使用更强大的。

使重复几率消失的最后一种方法是检查字符串的区分大小写。例如,B 不等于 b。您将检查字符串的每个字符,以匹配另一个字符串中的字符。或者,您可以使用所有对象中都可用的 `.Equal()` 方法(因为它继承自 `System.Object`)来检查两个字符串在字符和大小写方面是否相等。例如,下面的代码,

// creating the variables
string a = "Love for all Hatred for none!";
string b = "LOVE FOR ALL HATRED FOR NONE!";
string c = "love for all hatred for none!";
string d = "Love for all Hatred for none!";
        
// testing the objects, whether they're equal or not.
if(a.Equals(b)) {
   Console.WriteLine("a matches b.");
} else {
   Console.WriteLine("a doesn't match b");
}
if(a.Equals(c)) {
   Console.WriteLine("a matches c");
} else {
   Console.WriteLine("a doesn't match c");
}
if(a.Equals(d)) {
   Console.WriteLine("a matches d");
} else {
   Console.WriteLine("a doesn't match d");
}

// Output of the program
// a doesn't match b
// a doesn't match c
// a matches d

...显示了如何检查区分大小写的字符串以创建另一层防重复安全。可以在此处测试 Fiddle。

在 ASP.NET 中生成随机 URL

ASP.NET 允许您使用 GUID 生成一个随机 `string`,您可以使用它来创建“永不重复”的长唯一 `string`。但是,您也可以创建一个简短的代码片段,它将不断为您提供具有随机字符集和序列的 `string`。

函数代码

第一步,我们将生成一个依赖于字母(字符)和数字数据(数字)的随机 URL。所以我们将要做的是创建两个列表,一个包含我们 URL 的所有字符数据,另一个包含 0-9 的所有数字。

在字符中,我添加了“-”和“_”,以增加非重复的可能性,您可以添加任何其他在 URL 中有效的字符,它将为您的应用程序添加一层额外的非重复 URL。

第二件事是您需要生成随机数,您只能生成整数值,`Random` 类无法创建字符。所以我们将使用索引器,它允许我们从集合中选择任何一个元素;`List` 是 `T` 类型元素的集合,然后我们将它连接到我们将要写入 `stream`;或任何其他地方的实际 URL 的 `string` 中。

// List of characters and numbers to be used...
string URL = "";
List<int> numbers = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
List<char> characters = new List<char>() 
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '_'};

// Create one instance of the Random
Random rand = new Random();
// run the loop till I get a string of 10 characters
for (int i = 0; i < 11; i++) {
    // Get random numbers, to get either a character or a number...
    int random = rand.Next(0, 3);
    if(random == 1) {
        // use a number
        random = rand.Next(0, numbers.Count);
        URL += numbers[random].ToString();
    } else {
        // Use a character
        random = rand.Next(0, characters.Count);
        URL += characters[random].ToString();
    }
}

使用单独的类

正如在评论中所述,每个应用程序中的数据访问层都必须对用户界面隐藏,所以请记住将此函数写在一个单独的类中,您可以从那里调用它,您甚至可以指定它只有一个成员,即 `GetURL()` 方法并将其设为 `static`。

这将最大程度地减少代码重复的可能性 - 这在本篇文章中跑题了,您的代码违反了编程规则。如果您创建一个类,该类将如下所示:

using System;
using System.Collections.Generic;
using System.Web;
using WebMatrix.WebData;

/// <summary>
/// RandomURL class generates Random URLs for applications.
/// </summary>
public class RandomURL
{
    var db = Database.Open("StarterSite");
    // List of characters and numbers to be used...
    private static List<int> numbers = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    private static List<char> characters = new List<char>() {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
                                                        'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 
                                                        'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 
                                                        'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '_'};

    public static string GetURL () {    
        string URL = "";
        Random rand = new Random();
        // run the loop till I get a string of 10 characters
        for (int i = 0; i < 11; i++) {
            // Get random numbers, to get either a character or a number...
            int random = rand.Next(0, 3);
            if(random == 1) {
                // use a number
                random = rand.Next(0, numbers.Count);
                URL += numbers[random].ToString();
            } else {
                random = rand.Next(0, characters.Count);
                URL += characters[random].ToString();
            }
        }

        return URL;
    }

    public static bool Exists(string URL) {
        if(db.Query("SELECT * FROM RandomUrls WHERE ShortUrl = @0", URL).Count() > 0) {
            // Generate a new URL because the previous one had a match.
            return true;
        } else {
            return false;
        }
    }

    // Saves the URL in the database
    public static bool Save(string longUrl, string URL) {
        if(db.Execute("INSERT INTO RandomUrls (UrlString, ShortUrl) VALUES (@0, @1)", longUrl, URL) > 0)        {
            // A row was added
            return true;
        } else {
            return false;
        }
    }
}

...您会注意到,现在成员(方法和两个 `List`)都是 `static` 的了。由于我们永远不会更改值,除非我们重新运行相同的代码;或者简单地说 - 同一时间不会有该类的多个实例,所以我们将它们设置为静态并使用它们,而无需在每次使用时创建它的实例。

此代码的结果

我在函数阶段和类阶段都运行了相同的代码,它奏效了!我的 ASP.NET 网站网页的运行结果,显示了生成的 URL,如下所示:

Result

每次运行代码都会为您提供一个随机 URL,您可以在短消息中发送它或在应用程序中执行其他任务。

保存和重用原始 URL

这个主题在评论中开始 - “如何取回原始 URL 以便重用”。嗯,这是一个很好的问题。它迫使我更改了整个项目并添加了一些代码块,以及从数据库中获取原始 URL 并使用重定向功能来实际演示本文的功能。

保存 URL

第一阶段是将 URL 存储在数据库中,您可以设计数据库来存储 URL 和您将使用的短 URL。在此过程中,可以使用以下模式,请注意 ID 在此方法中不是必需的。

Database Schema

这里要注意的重要事项如下:

  1. 长 URL 的大小设置为 4000 - 最大值,因为它可以很长。
  2. 短 URL 设置为 50,因为它将是一个短大小的 URL,其大小必须很短。
  3. ID 不是必需的 - 正如一直提到的。

现在您只需编写后端代码即可保存数据,并生成一个新的 URL 与您的应用程序中的长 URL 相关联。

注意:我没有更改类或 C# 代码,我只是更新了 UI 和应用程序的逻辑以保存 URL,并创建了一个新页面来重定向用户到由应用程序缩短的主 URL。所以不要纠结于是否使用上面发布的代码。这个是一个新功能。

在网页中创建一个 HTML 表单,以接受用户输入的 URL。

<form method="post">
    <input type="text" name="url" />
    <input type="submit" value="Submit" />
</form>

够了,现在进行服务器端编码,它会将 URL 保存到数据库。

string URL = "";
string longUrl = "";
if(IsPost) {
    longUrl = Request.Form["url"];
    // Change the UI of the web page.
    // Open the connection
    var db = Database.Open("StarterSite");

    // Get the URL
    URL = RandomURL.GetURL();
    
    while(RandomURL.Exists(URL)) {
        // Generate a new URL because currently generated URL has a match
        URL = RandomURL.GetURL();
    }

    // URL is unique, save it.
    RandomURL.Save(longUrl, URL);
}

以上代码的一点解释是,它将在请求为 `POST` 时运行。如果是,它将捕获用户在表单中发布的 URL,并查看数据库,如果生成的 `ShortURL` 匹配,它将创建一个新的 `RandomURL`(这通常不会发生 - 但经常发生),然后它会将这两个 URL 都保存在数据库中。

执行后,它将像这样保存 URL:

URLs in the Database.

您也可以附加自己的条件,以便长 URL 也被检查是否存在于数据库中,依此类推。

提取原始 URL 并重定向用户

此过程的主要部分是提取用户将被重定向到的实际 URL。它就像查询数据库一样简单,首先创建一个新的 ASP.NET 页面,您可以在其中编写查询数据库的代码。我查询了数据库,并像这样列出了 URL:

List of URLs

您已将创建的 `ShortURL string` 保存在数据库中,它与数据库中的长 URL 相关联。您可以将该 `ShortURL` 传递给页面,并对其执行其他不同的任务,在本篇文章中,将执行重定向任务。在新创建的 ASP.NET 页面中编写此代码:

// Get the short url
var shortUrl = UrlData[0];
RandomURL.Redirect(shortUrl);

上面的代码将使用 RandomURL 类的某个方法在数据库中查找,并找到被缩短的实际长 URL。我将文件名命名为 `redirect`,所以在我应用程序中 URL 传递为:

Redirect page URL

由于此页面连接到 Google,结果是此页面:

Google page redirect

这样,您就可以简单地将用户重定向到被缩短的长 URL 的实际网页。

提示:为什么只使用一个 Random 实例

我发现在文章和以下“兴趣点”部分分享我说的“只使用一个 Random 实例并使用 `.Next()` 方法创建新的随机数”是很有趣的。要注意的关键点是,这些随机数是使用种子生成的,如果您将该种子传递给对象的构造函数,它将使用它来创建随机数。否则,它将使用您系统的当前时间实例作为种子,并且由于代码在同一时间执行 - 不设置任何调试功能,或任何其他花哨的黑客,您使用的所有实例都将包含相同的随机数。

为了最小化此错误,您应该使用一个随机数,并使用 `.Next` 方法不断更改其值,并传递您想要获取随机数的范围。

关注点

创建一个简单的类来生成这些随机 URL 会很容易,它还将防止违反应用程序中“重复代码”的规则。

只创建一个 Random 实例会更好 - 一旦创建,请在每个函数中使用 `.Next()` 方法为该实例创建新的 Random。

历史

  • 此主题的第一篇文章
  • 本文的第二篇文章。
    我已更新应用程序的架构,将数据访问层隐藏在业务逻辑的后台。现在用户界面不直接与数据访问层通信。感谢 Sumuj John 就此主题发表的评论,并为我更新文章太晚表示歉意。
© . All rights reserved.