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

使用 Redis 构建简单的 URL 缩短服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (4投票s)

2014年9月16日

CC (BY-ND 3.0)

3分钟阅读

viewsIcon

18460

downloadIcon

292

在本文中,我将向您展示如何使用 Redis 和 ASP.NET MVC 构建一个简单的 URL 缩短服务。

 

在阅读本文之前,我建议您先下载源代码。

什么是 Redis

与 memcached 类似,Redis 是一种内存数据库。除此之外,Redis 还允许您将数据保存到硬盘上,这使得 Redis 不仅仅是一个缓存,还是一个 NoSQL 数据库。

构建 Web 应用程序

首先,在 Visual Studio 中创建一个 ASP.NET MVC 项目,不使用身份验证。

然后,在 Models 文件夹中添加一个类来存储 URL 数据

public class MicroUrlItem
{
    [Display(Name = "Shorten URL")]
    public string ShortenUrl { get; set; }

    [Required]
    [Display(Name = "Origin URL")]
    [Url]
    public string OrignUrl { get; set; }

    [Range(1, double.MaxValue)]
    [Display(Name = "Expire in Days")]
    public int ExpireInDays { get; set; }

    [Display(Name = "Expire Mode")]
    public ExpireMode ExpireMode { get; set; }
}

ExpireMode 是一个自定义枚举,因此我们需要声明它。

public enum ExpireMode
{
    [Display(Name = "By Created")]
    ByCreated = 0,
    [Display(Name = "By Last Accessed")]
    ByLastAccessed = 1,
    [Display(Name = "Never")]
    Never = 2
}

之后,添加一个主页

@model MicroUrl.Models.MicroUrlItem

@{
    ViewBag.Title = "Home Page";
}
<h3>Get you micro URL here</h3>
<div class="row">
    @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { role = "form", @class = "col-lg-6" }))
    {
        <div class="form-group">
            @Html.LabelFor(m => m.OrignUrl)
            @Html.TextBoxFor(m => m.OrignUrl, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.OrignUrl, "", new { @class = "text-danger" })
        </div>
        <div class="form-group">
            @Html.LabelFor(m => m.ShortenUrl)
            @Html.TextBoxFor(m => m.ShortenUrl, new { @class = "form-control", placeHolder = "Keep it empty to generate automatically" })
            @Html.ValidationMessageFor(m => m.ShortenUrl, "", new { @class = "text-danger" })
        </div>
        <div class="form-group">
            @Html.LabelFor(m => m.ExpireMode)
            @Html.EnumDropDownListFor(m => m.ExpireMode, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.ExpireMode, "", new { @class = "text-danger" })
        </div>
        <div class="form-group">
            @Html.LabelFor(m => m.ExpireInDays)
            @Html.TextBoxFor(m => m.ExpireInDays, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.ExpireInDays, "", new { @class = "text-danger" })
        </div>
        <button type="submit" class="btn btn-default">Create</button>
    }
</div>

它看起来像这样

此代码段中一个有趣的事情是 HtmlHelper 中的 EnumDropDownListFor 方法,该方法直到 ASP.NET MVC 5.2 才可用。

在早期版本的 ASP.NET MVC 中,如果没有此方法,我们必须手动创建下拉列表项,这是一项脏活。

但现在我们可以使用此方法从枚举生成项目,并使用 Display 属性设置其显示名称。

然后我们需要一个页面来告诉用户操作已在 Success.cshtml 中成功,这很简单。

@model MicroUrl.Models.MicroUrlItem

@{
    ViewBag.Title = "Success";
}

<h2>Success</h2>
<h3>
    @{
        var url = string.Format("http://{0}:{1}/{2}", Request.Url.Host, Request.Url.Port, Model.ShortenUrl);
    }
    Your Micro URL is <a href="@url">@url</a>
</h3>

将对象保存到 Redis

在完成上述准备工作后,我们现在可以开始编写代码将数据存储在 Redis 中。

首先需要一个名为 ServiceStack.Redis 的 Nuget 包。我们可以在 Package Manager 中搜索 redis,或者使用以下命令在控制台中安装

PM> Install-Package ServiceStack.Redis

顺便说一句,如果您需要引用一个具有强名称的已签名程序集,则可以安装 ServiceStack.Redis.Signed

然后我们可以使用 using 语句创建一个 redis 客户端,并获取一个类型化的客户端来处理 MicroUrlItem

using (IRedisClient client = new RedisClient())
{
    var typedClient = client.As<MicroUrlItem>();
    //...
}

在将对象保存在 Redis 中之前,我们需要使用 ServiceStack.DataAnnotations.PrimaryKey 属性将 ShortenUrl 属性标记为主键,因此最终 MicroUrlItem 中的 ShortenUrl 属性应为

public class MicroUrlItem
{
    [ServiceStack.DataAnnotations.PrimaryKey]
    [Display(Name = "Shorten URL")]
    public string ShortenUrl { get; set; }
    
    //other properties
    //...
}

我们需要做的另一件事是在未指定 ShortenUrl 时生成一个随机 URL。

if (string.IsNullOrWhiteSpace(model.ShortenUrl))
{
    string url;
    do
    {
        url = GetRandomUrl(6);
    } while (typedClient.GetById(url) != null);
    model.ShortenUrl = url;
}

这是我生成随机 URL 的方法

private static string randomList = "0123456789abcdefghijklmnopqrstuwxyz";

private static string GetRandomUrl(int length)
{
    var sb = new StringBuilder(length);
    var random = new Random();
    for (int i = 0; i < length; i++)
    {
        var index = random.Next(0, randomList.Length);
        sb.Append(randomList[index]);
    }
    return sb.ToString();
}

现在模型已准备好保存到 Redis

typedClient.Store(model);

最后,我们需要告诉 Redis,如果指定了过期时间,则对象何时过期。

if (model.ExpireMode != ExpireMode.Never)
    typedClient.ExpireIn(model.ShortenUrl, TimeSpan.FromDays(model.ExpireInDays));

从 Redis 获取对象

[Route("{shortenUrl}")]
public ActionResult Index(string shortenUrl)
{
    using (IRedisClient client = new RedisClient())
    {
        var typedClient = client.As<MicroUrlItem>();
        var microUrlItem = typedClient.GetById(shortenUrl);
        if (microUrlItem != null)
        {
            //renew the record
            if (microUrlItem.ExpireMode == ExpireMode.ByLastAccessed)
                typedClient.ExpireIn(microUrlItem.ShortenUrl, TimeSpan.FromDays(microUrlItem.ExpireInDays));
            return Redirect(microUrlItem.OrignUrl);
        }
    }
    return HttpNotFound();
}

现在我们可以用同样的方式创建一个类型化的客户端,如果找到匹配的记录,则返回带有 HTTP 302 的响应。当访问缩短的 URL 时,如果其 ExpireMode 属性设置为 ByLastAccessed,我们应该 renew 它。

另一件重要的事情是使 Route 属性起作用,只需在应用程序启动时将 AttributeRoutes 映射到 ASP.NET MVC 路由系统。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    //map the AttributeRoutes
    routes.MapMvcAttributeRoutes();

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

运行应用程序

在运行此应用程序之前,我们需要启动 Redis,要获取 Redis,您可以转到 https://redis.ac.cn/download 下载它。

对于 Windows,启动命令提示符并转到 Redis 文件夹,然后运行

redis-server.exe --maxheap 1gb

我们还可以启动一个命令行客户端来启动一个监视器

然后我们可以在 Visual Studio 中启动网站,并创建一个缩短的 URL。

这是自定义 URL

这是由服务生成的 URL

在我们得到微型 URL 后,我们可以在监视器中看到 Redis 中发生的情况。

感谢阅读!

© . All rights reserved.