我想创建一个URL缩短服务,你可以写一个长URL到输入字段和服务缩短URL为“http://www.example.org/abcdef”。
可以用包含a-z, a-z和0-9的6个字符的字符串代替"abcdef"。这样就有560 ~ 570亿个可能的字符串。
我的方法:
我有一个有三列的数据库表:
Id,整数,自动递增
long, string,用户输入的长URL
短,字符串,缩短的URL(或只有六个字符)
然后将长URL插入到表中。然后,我将为“id”选择自动递增的值,并构建它的散列。这个散列应该作为“short”插入。但是我应该构建什么样的哈希呢?像MD5这样的哈希算法会创建太长的字符串。我认为我不用这些算法。一个自建的算法也可以。
我的想法:
对于“http://www.google.de/”,我得到了自动增量id 239472。然后我执行以下步骤:
short = '';
if divisible by 2, add "a"+the result to short
if divisible by 3, add "b"+the result to short
... until I have divisors for a-z and A-Z.
可以不断重复,直到这个数不能被整除为止。你认为这是一个好方法吗?你有更好的主意吗?
由于对这个主题的持续兴趣,我已经发布了一个高效的GitHub解决方案,包括JavaScript、PHP、Python和Java的实现。如果你喜欢,添加你的解决方案:)
Node.js和MongoDB的解决方案
因为我们知道MongoDB用来创建一个12字节的新ObjectId的格式。
一个4字节的值,表示从Unix纪元开始的秒数,
3字节的机器标识符,
2字节的进程id
一个3字节的计数器(在您的机器中),从一个随机值开始。
示例(我选择一个随机序列)
a1b2c3d4e5f6g7h8i9j1k2l3
a1b2c3d4表示自Unix纪元以来的秒数,
4e5f6g7表示机器标识符,
H8i9表示进程号
J1k2l3表示计数器,从一个随机值开始。
由于计数器是唯一的,如果我们将数据存储在同一台机器上,我们可以毫无疑问地获得它,它将是重复的。
因此,短URL将是计数器,这里是一个代码片段,假设您的服务器运行正常。
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create a schema
const shortUrl = new Schema({
long_url: { type: String, required: true },
short_url: { type: String, required: true, unique: true },
});
const ShortUrl = mongoose.model('ShortUrl', shortUrl);
// The user can request to get a short URL by providing a long URL using a form
app.post('/shorten', function(req ,res){
// Create a new shortUrl */
// The submit form has an input with longURL as its name attribute.
const longUrl = req.body["longURL"];
const newUrl = ShortUrl({
long_url : longUrl,
short_url : "",
});
const shortUrl = newUrl._id.toString().slice(-6);
newUrl.short_url = shortUrl;
console.log(newUrl);
newUrl.save(function(err){
console.log("the new URL is added");
})
});
我不断增加数据库中每个域的整数序列,并使用Hashids将整数编码为URL路径。
static hashids = Hashids(salt = "my app rocks", minSize = 6)
我运行了一个脚本,看看它需要多长时间才能耗尽字符长度。对于6个字符,它可以做164,916,224个链接,然后增加到7个字符。Bitly使用7个字符。在我看来,不到五个字很奇怪。
哈希id可以将URL路径解码为整数,但更简单的解决方案是使用整个短链接sho。Rt /ka8ds3作为主键。
以下是完整的概念:
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)
}