【问题标题】:How to implement a short URL like the URLs in Twitter?如何实现类似于 Twitter 中的 URL 的短 URL?
【发布时间】:2011-09-14 09:30:45
【问题描述】:

如果有一个长 URL,我想生成一个短 URL,就像 Twitter 中的那样。有没有办法在 Ruby 中实现这一点?

【问题讨论】:

    标签: ruby short-url


    【解决方案1】:

    最简单的方法是:

    1. 保留所有 URL 的数据库
    2. 在向数据库中插入新 URL 时,找出自增整数主键的 id。
    3. 将该整数编码为基数 36 或 62(数字 + 小写字母或数字 + 混合大小写字母)。瞧!你有一个短网址!

    在 Ruby 中编码到 base 36/从 base 36 解码很简单:

    12341235.to_s(36)
    #=> "7cik3"
    
    "7cik3".to_i(36)
    #=> 12341235
    

    编码为 base 62 有点复杂。这是一种方法:

    module AnyBase
      ENCODER = Hash.new do |h,k|
        h[k] = Hash[ k.chars.map.with_index.to_a.map(&:reverse) ]
      end
      DECODER = Hash.new do |h,k|
        h[k] = Hash[ k.chars.map.with_index.to_a ]
      end
      def self.encode( value, keys )
        ring = ENCODER[keys]
        base = keys.length
        result = []
        until value == 0
          result << ring[ value % base ]
          value /= base
        end
        result.reverse.join
      end
      def self.decode( string, keys )
        ring = DECODER[keys]
        base = keys.length
        string.reverse.chars.with_index.inject(0) do |sum,(char,i)|
          sum + ring[char] * base**i
        end
      end
    end
    

    ...它正在发挥作用:

    base36 = "0123456789abcdefghijklmnopqrstuvwxyz"
    db_id = 12341235
    p AnyBase.encode( db_id, base36 )
    #=> "7cik3"
    p AnyBase.decode( "7cik3", base36 )
    #=> 12341235
    
    base62 = [ *0..9, *'a'..'z', *'A'..'Z' ].join
    p AnyBase.encode( db_id, base62 )
    #=> "PMwb"
    p AnyBase.decode( "PMwb", base62 )
    #=> 12341235
    

    编辑

    如果您想避免恰好是英文单词的 URL(例如,四个字母的脏话),您可以使用一组不包含元音的字符:

    base31 = ([*0..9,*'a'..'z'] - %w[a e i o u]).join
    base52 = ([*0..9,*'a'..'z',*'A'..'Z'] - %w[a e i o u A E I O U]).join
    

    但是,您仍然会遇到AnyBase.encode(328059,base31)AnyBase.encode(345055,base31)AnyBase.encode(450324,base31) 之类的问题。因此,您可能还想避免类似元音的数字:

    base28 = ([*'0'..'9',*'a'..'z'] - %w[a e i o u 0 1 3]).join
    base49 = ([*'0'..'9',*'a'..'z',*'A'..'Z'] - %w[a e i o u A E I O U 0 1 3]).join
    

    这也将避免“是 0 还是 O?”的问题。和“那是 1 还是 I?”。

    【讨论】:

    • 您帮助了我很多次,非常感谢您的帮助,每次提供的答案都很棒,非常感谢。
    • 小心这个实现,因为它会生成你可能想要避免的人类可读的单词。例如。 645860.to_s(36) = '鸭'。 739172 可能会被认为更糟。我建议使用 base20 (0-9a-j) 或类似的。为了帮助做出决定,您甚至可以使用类似“wordplay”之类的字谜查找器,如下所示:wordplay 'aaabbbcccdddeeefffggghhhiiijjj' - 它会告诉您可以生成哪些单词。
    • Upvoted :) 关于这种情况,人们可能想要考虑这个 Google 建议 (code.google.com/p/shortlink/wiki/Specification),它指出 URI 应该不区分大小写。这也是一个很好的基本“反混淆”策略。
    • 对于 Ruby 2.0,将 decode 方法的第 3 行替换为:string.reverse.chars.map.with_index.inject(0) do |sum,(char,i)|
    • base28 和 base49 集仍然包括 0、1 和 3,因为 *0..9 产生整数数组,而 %w[0 1 3] 产生字符串数组(使用 ruby​​ 2.1.5 测试)。正确的集合应该是:base28 = ([*'0'..'9',*'a'..'z'] - %w[a e i o u 0 1 3]).joinbase49 = ([*'0'..'9',*'a'..'z',*'A'..'Z'] - %w[a e i o u A E I O U 0 1 3]).join(注意数字周围的引号)。
    【解决方案2】:

    您可以使用众多网址缩短服务的 API 来生成短网址。几乎所有现有的服务都为您提供了一个 API,以便您能够调用和缩短 url,这正是 twitter 客户端所做的。您应该查看特定的 url 缩短服务的网站以获取更多详细信息。

    如果你想自己创建这样的服务,那也很简单,你需要做的就是在原始长 url 和特殊短 url 之间维护一个内部映射(在数据库中)(生成由你)。当您收到对特定短 url 的请求时,您应该能够从数据库中获取原始长 url 并将用户重定向到相同的位置。

    【讨论】:

      【解决方案3】:

      我使用bitly gem。这真的很简单。

      gem install bitly
      
      # Use api version 3 or get a deprecation warning
      Bitly.use_api_version_3
      
      # Create a client
      bitly = Bitly.new(username, api_key)
      
      # Call method shorten
      bitly.shorten('http://www.google.com').short_url
      

      【讨论】:

        【解决方案4】:

        对于 Ruby 2.0,将 decode 方法替换为:

        def self.decode( string, keys )
          ring = DECODER[keys]
          base = keys.length
          string.reverse.chars.map.with_index.inject(0) do |sum,(char,i)|
            sum + ring[char] * base**i
          end
        end
        

        【讨论】:

          猜你喜欢
          • 2015-08-01
          • 2023-03-18
          • 2011-03-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多