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

永久链接,用于娱乐和利润

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (9投票s)

2008年9月5日

CPOL

4分钟阅读

viewsIcon

27721

downloadIcon

162

永久链接提供了一种简单的方式来重定向传入流量到特定页面,跟踪点击和目标,以及防止外部链接过期。

引言

在为 CALM 构建 ASP.NET 网站时 [你注意到永久链接了吗?],我希望有一种简单的方法来了解哪些推荐链接正在为网站带来流量,哪些没有。我还希望有一种简单的方式根据来源的上下文来重定向传入流量,并跟踪不同的营销活动(来自文章、电子邮件、博客、Google AdWords 等)。永久链接解决了这三个问题。

目录

背景

永久链接的正式概念大约在 2000 年左右就已出现(参见 Wikipedia)。然而,任何曾经重新组织过网站、重命名页面、更改落地页或点击过已失效链接的人,可能都想象过这样的东西。

“Permalink”是“permanent link”(永久链接)的缩写。这个术语最初是用来引用已存档或已移动的网页或博客帖子的方式。永久链接通常与 URL 重写结合使用,这样浏览器就可以显示人类可读的(并且对搜索引擎友好的)URL,而后端仍然使用数据库跟踪链接。

实现

永久链接最简单的实现方式就是将一个 ID 号通过 URL 的查询字符串传递。主页面使用这个 ID 来决定显示哪个内部页面。

永久链接,带来乐趣

永久链接允许您在不更改网站的情况下更改落地页,只需更改链接 ID 在数据库中的目标条目即可。这使您可以在不冒着破坏外部链接的风险的情况下,根据需要重组您的网站。

永久链接,带来收益

永久链接允许您跟踪哪些推荐链接能够到达您的“目标页面”,无论是演示下载、订单,还是彩蛋。例如,主页面可以记住传入的链接 ID(例如,存储在 session 中),然后目标页面可以检索它并更新计数器来跟踪点击次数。

永久链接演示代码

演示应用程序包含一个 SQL 脚本,用于创建和填充一个小数据库,以及一个 ASP.NET 网站来演示永久链接的使用和跟踪。SQL 脚本创建了 CampaignCampaignLink 表,并用一些示例数据填充它们。该网站包含几个内容页面和“目标”页面,以及一个“外部推荐”页面,用于模拟外部链接并演示如何非常具体地使用永久链接来跟踪推荐。还包含一个统计页面,用于显示每个 Campaign 和 CampaignLink 的点击和目标统计信息。

Using the Code

要运行演示,请使用具有创建数据库、表和存储过程权限的登录名打开 Microsoft SQL Server Management Studio。然后,打开脚本 create-permalinks-database.sql 并执行它。刷新“数据库”列表,您应该会看到 PermaLinks 数据库。

然后,在 Visual Studio 中打开 PermaLinkDemo.sln 文件(VS2005,一个主页),如果需要,请在 web.config 文件中更改连接字符串,然后构建并运行网站。默认页面是 external.aspx,它使用数据库中的 CampaignLinks 表来模拟外部链接。点击外部链接,查看它将您带到哪个页面。点击“目标”按钮来增加计数器。点击“返回”链接返回到外部链接页面。重复操作一段时间以提高计数。然后,点击“显示永久链接统计信息”链接查看结果。

关注点

网站和存储过程中使用的技术都很简单,但其中一些可能对某些人有益。

  • 外部链接页面(external.aspx)是使用 SqlDataReaderStringBuilder 来填充 Literal 控件的链接表生成的。
  • protected void Page_Load(object sender, EventArgs e)
    {
        //we want to generate a full URL, 
        //e.g. https:///PermaLinks/?linkid=###
        //this is probably not the best way to do this,
        //but it works ;-)
        string baseUrl = this.Request.Url.AbsoluteUri;
        baseUrl = baseUrl.Replace("/external.aspx",
            "/?linkid=");
        //generate a table of links using a data reader;
        //we could have used a repeater control instead
        SqlConnection conn = null;
        SqlCommand cmd = null;
        SqlDataReader rdr = null;
        StringBuilder sb = new StringBuilder();
        try
        {
            conn = new SqlConnection(
                ConfigurationManager.ConnectionStrings["db"].ConnectionString);
            cmd = new SqlCommand("select CampaignLinkId, 
                CampaignLinkDescription from dbo.CampaignLink", conn);
            conn.Open();
            rdr = cmd.ExecuteReader(CommandBehavior.Default);
            sb.Append("<table border='0' align='center' width='90%'>");
            while (rdr.Read())
            {
                //generate a row in the table for each external link
                sb.Append("<tr><td>>a href='");
                sb.Append(baseUrl);
                sb.Append(rdr.GetInt32(0));     //link id
                sb.Append("'>");
                sb.Append(rdr.GetString(1));    //campaign link description
                sb.Append("</a></td></tr>");
            }
            sb.Append("</table>");
            this.Literal1.Text = sb.ToString();
        }
        catch(Exception ex)
        {
            this.Literal1.Text = "ERROR: " + ex.Message;
        }
        finally
        {
            if (rdr != null && !rdr.IsClosed)
            {
                rdr.Close();
                rdr.Dispose();
                rdr = null;
            }
            if (conn != null && conn.State != ConnectionState.Closed)
            {
                conn.Close();
                conn.Dispose();
                conn = null;
            }
        }
    }
  • Default.aspx 页面捕获链接 ID,将其存储在 Session 中,并使用存储过程检索目标 URL 进行重定向。
  • protected void Page_Load(object sender, EventArgs e)
    {
        int linkId = 0; //default to first permalink if no linkid found
        if (!int.TryParse(this.Request.Params["linkid"], out linkId))
        {
            linkId = 1; //default to first link
        }
        //find page to redirect to
        string url = getUrl(linkId);
        this.Session["linkid"] = linkId;
        this.Response.Redirect(url);
    }
    protected string getUrl(int id)
    {
        SqlConnection conn;
        SqlCommand cmd;
        string url = "hireme.aspx";
        try
        {
            conn = new SqlConnection(
             ConfigurationManager.ConnectionStrings["db"].ConnectionString);
            cmd = new SqlCommand("dbo.uspGetLinkUrl " 
                + id.ToString(), conn);
            conn.Open();
            object result = cmd.ExecuteScalar();
            if (result != null && result != DBNull.Value)
            {
                url = Convert.ToString(result);
            }
        }
        catch
        {
            //just send to default page
        }
        return url;
    }
  • 目标按钮处理程序从 Session 中检索传入的链接 ID,以使用存储过程更新计数器。
  • protected void Button1_Click(object sender, EventArgs e)
    {
        //update buy counter
        updateBuyCounter();
    }
    private void updateBuyCounter()
    {
        SqlConnection conn = null;
        SqlCommand cmd = null;
        string linkid = Convert.ToString(this.Session["linkid"]);
        if (linkid == null || linkid.Length <= 0) { return; }
        try
        {
            conn = new SqlConnection(
                ConfigurationManager.ConnectionStrings["db"].ConnectionString);
            cmd = new SqlCommand("exec dbo.uspUpdateBuyCount " 
                + linkid, conn);
            conn.Open();
            cmd.ExecuteNonQuery();
        }
        catch
        {
            //in a real system, only catch SQL errors
        }
        finally
        {
            if (conn != null && conn.State != ConnectionState.Closed)
            {
                conn.Close();
                conn.Dispose();
                conn = null;
            }
        }
    }
  • 统计页面是使用三个 DataGridView 控件、一个 SqlDataReader 和一个返回三个结果集的存储过程生成的。
  • protected void Page_Load(object sender, EventArgs e)
    {
        SqlConnection conn = null;
        SqlCommand cmd = null;
        SqlDataReader rdr = null;
        try
        {
            conn = new SqlConnection(
                ConfigurationManager.ConnectionStrings["db"].ConnectionString);
            cmd = new SqlCommand("dbo.uspCampaignStats", conn);
            cmd.CommandType = CommandType.StoredProcedure;
            conn.Open();
            rdr = cmd.ExecuteReader(CommandBehavior.Default);
            GridViewCampaign.DataSource = rdr;
            GridViewCampaign.DataBind();
            rdr.NextResult();
            GridViewCampaignLink.DataSource = rdr;
            GridViewCampaignLink.DataBind();
            rdr.NextResult();
            GridViewTotals.DataSource = rdr;
            GridViewTotals.DataBind();
        }
        catch
        {
            //in a real system, only catch SQL errors
        }
        finally
        {
            if (rdr != null && !rdr.IsClosed)
            {
                rdr.Close();
                rdr.Dispose();
                rdr = null;
            }
            if (conn != null && conn.State != ConnectionState.Closed)
            {
                conn.Close();
                conn.Dispose();
                conn = null;
            }
        }
    }

结论

永久链接是一种简单的方法,可以防止“链接腐烂”,跟踪推荐,并监控流量。在网站的日志中可以找到更多详细信息,并且有几种产品可以解析这些日志并生成包含图表、路径等的详细报告。这些工具并非总是可用或方便;但是,简单的统计页面可以格式化成可以在智能手机上阅读,从而随时随地访问。

未来的增强

基本的永久链接实现可以通过会话 ID 来扩展,以跟踪访问者路径。永久链接也可以使用 HttpModule 来实现,但基本功能保持不变。永久链接还可以与 URL 重写结合使用,以创建更用户友好的链接,从而有效地隐藏浏览器或搜索引擎的链接 ID。最后,一个成熟的永久链接解决方案显然会包含管理页面来维护 Campaigns 和 CampaignLinks。

历史

  • 2008-09-04
    • 首次发布文章。
© . All rights reserved.