随着页面地址越来越长,在进行分享的时候,一长串的地址不友好,所以一个短的链接服务产生。那今天就跟大家介绍一下实现短链的几种方案。
1.数据库自增(使用数据库自带的自增id)
2.redis自增(incr实现)
3.hash算法
4.摘要算法
本文通过介绍redis自增与hash算法来实现
redis自增
思路:
1.判断传递的参数url是否存在
2.存在直接返回
3.不存在=》(1.进行incr 2.存储关系(url=>id,id=>url)3.返回id)
4.转64进制(讲解hash算法的时候会接触到)
想用redis来实现,lua脚本肯定是一个好选择(因为是原子性操作),以下是redis生成id的lua脚本例子
async def get_unionid(key):
script = '''
local key = 's:tag:%s'
local id = redis.call('get',key)
if(id)
then
return id
else
local new_id= redis.call('incr','s:unionid')
redis.call('set',key,new_id)
redis.call('set',new_id,key)
return new_id
end''' % key
redis = await AioRedisService.get()
s = await redis.eval(script)
return int(s)
hash算法
思路:
1.使用murmurhash3来加密url(速度快,效果好)
2.转64进制(讲解hash算法的时候会接触到)得到 key
3.获取key对应的内容(极小概率会一致,为了防止冲突多一个判断)
4.不存在,直接赋值,并且返回key,存在则进行下一步
5.判断key对应的url与当前url是否一致,一致:直接返回,不一致:加个混淆参数,重新从第二个步骤开始
核心代码:
import mmh3
import time
from common.service.aioredis_service import AioRedisService
class ShortCore:
table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
short_key = 's:short:%s'
salt_key = 'dd&&dd'
def b64(self, n):
'''转64进制
'''
n = abs(n)
if n == 0:
return '0'
r = []
while n > 0:
r.append(self.table[n % 64])
n //= 64
return ''.join(r[::-1])
def create(self, url):
'''获取数据
'''
return self.b64(mmh3.hash(url))
async def get_db(self, key):
'''获取对应的url
'''
redis = await AioRedisService.get()
s = await redis.get(self.short_key % key)
if s:
return s.decode().split(self.salt_key)[0]
return ''
async def set_db(self, key, url):
'''设置短链关系
'''
redis = await AioRedisService.get()
return await redis.set(self.short_key % key, url)
async def setnx_db(self, key, url):
'''设置短链关系
'''
redis = await AioRedisService.get()
return await redis.setnx(self.short_key % key, url)
def recreate(self, url):
'''重新创建
'''
url = '%s%s%s' % (url, self.salt_key, int(time.time()*1000))
return url, self.b64(mmh3.hash(url))
sanic-resuful 部分代码
1.创建短链
from apps.code import Code
from common.core.short_core import ShortCore
from sanic_restful_api import reqparse, Resource
parse = reqparse.RequestParser()
parse.add_argument('url', location='json',
type=str, required=True, nullable=True)
class ShortUrl(Resource):
async def post(self, request):
'''生成短链
'''
args = parse.parse_args(request)
core = ShortCore()
key = core.create(args.url)
url = await core.get_db(key)
print('1', url)
if not url:
await core.set_db(key, args.url)
else:
if url != args.url:
new_url, key = core.recreate(args.url)
print('2', 'new_url')
await core.set_db(key, new_url)
return {'code': Code.SUCCESS, 'data': {'key': key}}
2.获取短链
from sanic.response import redirect
from common.core.short_core import ShortCore
from sanic_restful_api import reqparse, Resource
parse = reqparse.RequestParser()
parse.add_argument('url', location='json',
type=str, required=True, nullable=True)
class Url(Resource):
async def get(self, request, key):
'''获取短链
'''
core = ShortCore()
url = await core.get_db(key)
if url:
return redirect(url, status=302)
else:
return 'welcome to short service'
THE END
短链的核心就是用短的字符来表示一段长的链接,通过短的标识,获取到原始的长链接进行一个302跳转,提交了分享时的点击的成功效果,也美化文案长度。 用id或者用hash加密,都可以得到一个唯一字符,比如自增id不可以直接给id,容易被刷,所以会再经历一次十进制转64进制的过程,当处于大id时也会有一定的压缩效果。
最后还是那句话,如果有问题,欢迎随时留言讨论。