How do I create a URL shortener?

后端 未结 30 2042
我寻月下人不归
我寻月下人不归 2020-11-22 05:11

I want to create a URL shortener service where you can write a long URL into an input field and the service shortens the URL to \"http://www.example.org/abcdef\

相关标签:
30条回答
  • 2020-11-22 05:25

    For a similar project, to get a new key, I make a wrapper function around a random string generator that calls the generator until I get a string that hasn't already been used in my hashtable. This method will slow down once your name space starts to get full, but as you have said, even with only 6 characters, you have plenty of namespace to work with.

    0 讨论(0)
  • I keep incrementing an integer sequence per domain in the database and use Hashids to encode the integer into a URL path.

    static hashids = Hashids(salt = "my app rocks", minSize = 6)
    

    I ran a script to see how long it takes until it exhausts the character length. For six characters it can do 164,916,224 links and then goes up to seven characters. Bitly uses seven characters. Under five characters looks weird to me.

    Hashids can decode the URL path back to a integer but a simpler solution is to use the entire short link sho.rt/ka8ds3 as a primary key.

    Here is the full concept:

    function addDomain(domain) {
        table("domains").insert("domain", domain, "seq", 0)
    }
    
    function addURL(domain, longURL) {
        seq = table("domains").where("domain = ?", domain).increment("seq")
        shortURL = domain + "/" + hashids.encode(seq)
        table("links").insert("short", shortURL, "long", longURL)
        return shortURL
    }
    
    // GET /:hashcode
    function handleRequest(req, res) {
        shortURL = req.host + "/" + req.param("hashcode")
        longURL = table("links").where("short = ?", shortURL).get("long")
        res.redirect(301, longURL)
    }
    
    0 讨论(0)
  • 2020-11-22 05:27

    This is what I use:

    # Generate a [0-9a-zA-Z] string
    ALPHABET = map(str,range(0, 10)) + map(chr, range(97, 123) + range(65, 91))
    
    def encode_id(id_number, alphabet=ALPHABET):
        """Convert an integer to a string."""
        if id_number == 0:
            return alphabet[0]
    
        alphabet_len = len(alphabet) # Cache
    
        result = ''
        while id_number > 0:
            id_number, mod = divmod(id_number, alphabet_len)
            result = alphabet[mod] + result
    
        return result
    
    def decode_id(id_string, alphabet=ALPHABET):
        """Convert a string to an integer."""
        alphabet_len = len(alphabet) # Cache
        return sum([alphabet.index(char) * pow(alphabet_len, power) for power, char in enumerate(reversed(id_string))])
    

    It's very fast and can take long integers.

    0 讨论(0)
  • 2020-11-22 05:28

    If you don't want re-invent the wheel ... http://lilurl.sourceforge.net/

    0 讨论(0)
  • 2020-11-22 05:28
    alphabet = map(chr, range(97,123)+range(65,91)) + map(str,range(0,10))
    
    def lookup(k, a=alphabet):
        if type(k) == int:
            return a[k]
        elif type(k) == str:
            return a.index(k)
    
    
    def encode(i, a=alphabet):
        '''Takes an integer and returns it in the given base with mappings for upper/lower case letters and numbers 0-9.'''
        try:
            i = int(i)
        except Exception:
            raise TypeError("Input must be an integer.")
    
        def incode(i=i, p=1, a=a):
            # Here to protect p.                                                                                                                                                                                                                
            if i <= 61:
                return lookup(i)
    
            else:
                pval = pow(62,p)
                nval = i/pval
                remainder = i % pval
                if nval <= 61:
                    return lookup(nval) + incode(i % pval)
                else:
                    return incode(i, p+1)
    
        return incode()
    
    
    
    def decode(s, a=alphabet):
        '''Takes a base 62 string in our alphabet and returns it in base10.'''
        try:
            s = str(s)
        except Exception:
            raise TypeError("Input must be a string.")
    
        return sum([lookup(i) * pow(62,p) for p,i in enumerate(list(reversed(s)))])a
    

    Here's my version for whomever needs it.

    0 讨论(0)
  • 2020-11-22 05:31

    My approach: Take the Database ID, then Base36 Encode it. I would NOT use both Upper AND Lowercase letters, because that makes transmitting those URLs over the telephone a nightmare, but you could of course easily extend the function to be a base 62 en/decoder.

    0 讨论(0)
提交回复
热议问题