【问题标题】:Designing a URL Shortening service like TinyURL设计像 TinyURL 这样的 URL 缩短服务
【发布时间】:2020-01-11 06:48:49
【问题描述】:

我正在阅读一份在线文档,其中介绍了如何设计网址缩短服务。该网站是https://www.educative.io/courses/grokking-the-system-design-interview

在编码实际 URL 部分中,他们说 -> “我们可以计算给定 URL 的唯一哈希(例如,MD5 或 SHA256 等)。然后可以对哈希进行编码以进行显示。这种编码可以是 base36 ([a-z ,0-9]) 或 base62 ([A-Z , a-z, 0-9]),如果我们添加 '+' 和 '/' 我们可以使用 Base64 编码。一个合理的问题是,短键的长度应该是多少?6、8 或 10 个字符。

"如果我们使用 MD5 算法作为我们的哈希函数,它会产生一个 128 位的哈希值。经过 base64 编码后,我们会得到一个超过 21 个字符的字符串(因为每个 base64 字符编码 6 位哈希值)。由于每个短键只有 8 个字符的空间,那么我们将如何选择我们的键呢?我们可以将前 6(或 8)个字母作为键。这可能导致键重复,以解决该问题,我们可以从编码字符串中选择一些其他字符或者交换一些字符。”

我使用在线 MD5 哈希生成器(http://onlinemd5.com/)和 Base64 编码器(https://www.base64encode.org/)来验证上述内容。我使用“www.yahoo.com”作为 MD5 哈希的输入字符串,输出为 1B03577ED104F16AADC00A639D33CB44 。然后我对它进行 Base64 编码并得到 MUIwMzU3N0VEMTA0RjE2QUFEQzAwQTYzOUQzM0NCNDQ= 与 UTF-8 目标字符集和 Unix 换行符分隔符。

谁能解释我是否正确执行?我看到字符数超过 21 个。

【问题讨论】:

  • MD5 哈希中的 32 个字符中的每个字符代表 4 位。因此,您需要将它们组合起来以创建 8 位值。例如第一个字节是十六进制 1B,即十进制 27。得到一个 16 字节的数组后,就可以对其进行 Base64 编码。
  • 看完本教程-lifewire.com/base64-encoding-overview-1166412和下面的评论,我明白了。谢谢大家。

标签: algorithm hash system


【解决方案1】:

问题是您使用 MD5 的输出作为十六进制数字字符串,然后对该字符串进行 base64 编码。没有理由对该字符串进行 base64 编码 - base64 编码适用于二进制数据。您可能想要做的是 base64 MD5 哈希的实际 128 位二进制值。这是一些 Python 代码,可以完成我认为您正在尝试做的事情:

import hashlib, base64

text = "www.yahoo.com"
text_utf8 = text.encode('utf8')
md5 = hashlib.md5(text_utf8).digest()
b64 = base64.b64encode(md5)
print(b64)

这会得到结果GwNXftEE8WqtwApjnTPLRA,它的长度是您所期望的。

【讨论】:

    【解决方案2】:

    这篇文章帮助我真正理解了TinyUrl design背后的算法 这是示例 java 程序,如果有人正在寻找它。

    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Base64;
    import java.util.Random;
    import java.util.concurrent.ThreadLocalRandom;
    
    
    public class TinyUrlAlgorithm {
        public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            byte[] input = "https://www.educative.io/courses/grokking-the-system-design-interview".getBytes("UTF-8");//args[0].getBytes("UTF-16");//"https://www.educative.io/courses/grokking-the-system-design-interview".getBytes("UTF-8");
            byte[] md5hash = messageDigest.digest(input);
            Base64.Encoder encoder = Base64.getEncoder();
            String encodeToString = encoder.encodeToString(md5hash);
            int shortKeyType =  3;//Integer.parseInt(args[1]);
            String tinyUrlKey = shortKeyType ==1 ? encodeToString.substring(0,6) : shortKeyType == 2 ? encodeToString.substring(0,8) : randomlySelect8Chars(encodeToString);
            System.out.println("ShortKey --> " + tinyUrlKey);
    
        }
    
        //Fisher yates algorithm
        private static String randomlySelect8Chars(String encodeToString) {
            Random random = ThreadLocalRandom.current();
            char[] encodedChars =  encodeToString.toCharArray();
            assert encodedChars.length == 21;
            for(int i=20; i >=0; i--) {
                int randomIndex =  random.nextInt(i+1);
                swap(encodedChars,randomIndex,i);
            }
    
            return new String(encodedChars,0,8);
        }
    
        private static void swap(char[] chars, int i, int j) {
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-14
      • 2012-09-15
      • 1970-01-01
      相关资源
      最近更新 更多