代码之家  ›  专栏  ›  技术社区  ›  Rick Strahl

如何实现可靠的网页计数器?

  •  7
  • Rick Strahl  · 技术社区  · 16 年前

    实现网页计数器的好方法是什么?

    从表面上看,这是一个简单的问题,但在处理搜索引擎爬虫和机器人、同一用户多次单击、刷新单击等问题时,它会出现问题。

    具体来说,什么是一个好方法,以确保链接不只是“点击”由用户反复点击?IP地址?饼干?这两者都有一些缺点(IP地址不一定是唯一的,可以关闭cookie)。

    存储数据的最佳方法是什么?单独增加一个计数器,或者将每次单击都存储在日志表中,然后偶尔进行汇总。

    任何现场体验都会有所帮助,

    +++瑞克

    4 回复  |  直到 11 年前
        1
  •  4
  •   Mike Trpcic    16 年前

    将IP地址与会话一起使用。将IP地址的每个新会话计数为一次命中计数器。如果您认为需要查看日志数据库,可以将这些数据存储在日志数据库中。这对于计算站点获得最多流量的时间、每天的流量、每个IP的流量等很有用。

        2
  •  2
  •   Rick Strahl    11 年前

    因此,我根据这里的评论,对此进行了一些讨论。我想到的是在一个简单的领域里计算一个计数器。在我的应用程序中,我有代码段实体和视图属性。

    当查看一个片段时,一个方法过滤掉了(白名单),这就是浏览器应该做的:

    public bool LogSnippetView(string snippetId, string ipAddress, string userAgent)
    {
        if (string.IsNullOrEmpty(userAgent))
           return false;
    
        userAgent = userAgent.ToLower();
    
        if (!(userAgent.Contains("mozilla") || !userAgent.StartsWith("safari") ||
            !userAgent.StartsWith("blackberry") || !userAgent.StartsWith("t-mobile") ||
            !userAgent.StartsWith("htc") || !userAgent.StartsWith("opera")))
            return false;
    
        this.Context.LogSnippetClick(snippetId, IpAddress);
    }
    

    然后,存储过程使用单独的表临时保存存储代码段ID、输入的日期和IP地址的最新视图。每个视图都会被记录下来,当一个新的视图出现时,它会被检查看看在过去的2分钟内,同一个IP地址是否访问了这个片段。如果是这样,则不记录任何内容。

    如果是新视图,则会记录该视图(再次记录snippet id、ip和entered),并在snippets表中更新实际视图字段。

    如果不是新视图,则清除表中记录的所有超过4分钟的视图。这将在任何时候导致视图日志表中的条目数最少。

    存储过程如下:

    ALTER PROCEDURE [dbo].[LogSnippetClick]
        -- Add the parameters for the stored procedure here 
        @SnippetId AS VARCHAR(MAX),
        @IpAddress AS VARCHAR(MAX)          
       AS
       BEGIN
    
        SET NOCOUNT ON;
    
        -- check if don't allow updating if this ip address has already 
        -- clicked on this snippet in the last 2 minutes
        select Id from SnippetClicks 
            WHERE snippetId = @SnippetId AND ipaddress = @IpAddress AND 
                  DATEDIFF(minute,  Entered, GETDATE() ) < 2      
    
         IF @@ROWCOUNT = 0  
         BEGIN              
            INSERT INTO SnippetClicks 
                (SnippetId,IpAddress,Entered) VALUES 
                (@SnippetId,@IpAddress,GETDATE())         
            UPDATE CodeSnippets SET VIEWS = VIEWS + 1 
                WHERE id = @SnippetId
         END
         ELSE
         BEGIN
            -- clean up
            DELETE FROM SnippetClicks WHERE DATEDIFF(minute,Entered,GETDATE()) > 4
         END
    END
    

    这似乎很管用。正如其他人提到的,这并不完美,但看起来在初始测试中已经足够好了。

        3
  •  0
  •   Zachery Delafosse    16 年前

    如果要使用PHP,可以使用会话跟踪来自特定用户的活动。结合数据库,您可以从特定的IP地址跟踪活动,您可以假定这些地址是同一个用户。

    使用时间戳来限制点击(例如,假设每5秒不超过1次点击),并告诉用户何时对网站进行新的“访问”(例如,如果最后一次点击超过10分钟)。

    您可能会发现有助于检测机器人程序或访问者趋势(如浏览器使用情况)的$_server[]属性。

    编辑: 我以前跟踪过点击量和访问量,将页面视图计数为点击量,并在创建新会话时将+1计数为访问量。它相当可靠(对于我使用它的目的来说,它足够可靠)。现在,不支持cookie(因此也不支持会话)的浏览器和禁用会话的用户非常少见,所以我不会担心,除非有理由过分精确。

        4
  •  0
  •   Cameron    16 年前

    如果我是你,我会放弃在我的柜台上准确的第一位。正如您所说,每个解决方案(如cookie、IP地址等)都往往不可靠。因此,我认为您最好的选择是在系统中使用冗余:使用cookies、“flash cookies”(共享对象)、IP地址(可能与用户代理结合使用)以及登录人员的用户ID。

    您可以实现某种方案,在这种方案中,任何未知的客户机都被赋予一个唯一的ID,该ID被存储(希望)在客户机上,并随每个请求一起重新传输。然后,您可以将IP地址、用户代理和/或用户ID(加上您能想到的任何其他内容)绑定到每个唯一的ID,反之亦然。每次点击的时间戳和唯一ID都可以记录在某个数据库表中的某个地方,并且每次点击(至少每次点击到你的网站)都可以通过或拒绝,这取决于最后一次点击对同一个唯一ID的时间有多近。这对于短期点击来说可能足够可靠,而长期点击也不重要。(对于点击率问题,而不是页面计数器)。

    友好的机器人应该适当地设置其用户代理,并且可以根据已知的机器人用户代理列表进行检查(我找到了一个 here 在一次简单的谷歌搜索之后),为了正确的识别和处理,与真实的人分开。

    推荐文章