使用Openresty的Lua扩展开发URL网址缩短接口simple-url-shorten
网址缩短接口一般位于网络服务的底层,为上层应用提供网址缩短化服务。大型网络架构过程中,如微博、社交平台、app等,都会考虑采用网址缩短服务。采用网址缩短服务有如下优点:
1、节约带宽
2、减少子符长度,节约页面空间
3、防止HTTP请求中的referer记录及信息泄露
4、美化URL,增强用户体验,便于传播
5、可以简单统计功能(按业务需求而定)
闲来无事的时候,自己用Openresty的ngx_lua扩展结合Redis数据库,写了一个简单的网址缩短接口,具有执行效率高、搭建简单、扩展性强等优势,支持Json格式的Restfull数据,代码部署于Github,有兴趣的同学可以去尝试一下。网址:https://github.com/peanode/simple-url-shorten
1、为什么用Openresty的ngx_lua来写?
Openresty是一个Nginx的Fork,具有高效、可扩展性,特别是结合了ngx_lua扩展,能够通过Lua脚本扩展Nginx的功能。Nginx是一款性能优异的Web服务应用,Lua具有高效执行的特性,两者结合能够更好地为Web应用,特别是接口类应用提高高性能和高扩展性,比如其他的PHP、Java等写的接口要快好多。
2、为什么使用Redis?
应用都会涉及到存储,存储数据有数据库和文件存储,文件存储直接不考虑,考虑的问题就是使用关系型数据库还是NoSQL数据库,使用何种数据库。
接口类的首要问题就是执行效率,效率高,才能为上层应用提供更便捷的服务。而且网址缩短服务是一个简单的服务,不会有太复杂的数据字段,所以NoSQL能够更好地支撑整个接口。所以摆在面前的就是Memcached、Redis、MongoDB。Memecached是不持久性存储,只能存储于内存,也就是说系统故障或者重启后,数据就没了,这当然不是我们想要的,所以Pass;MongoDB是一种最像关系型数据库的Nosql数据库,具有非常多的数据类型,数据一般存储于磁盘上,相比Redis的持久性存储和内存中读取,所以取Redis而舍MongoDB。
3、网址缩短后字符长度
Simple Url Shorten网址缩短是可以配置缩短后的字符长度的,也就是说,可以根据业务需求,自己设置缩短后的字符长度,字符个数和生成的个数如下所示:
1 -> 62
2 -> 3844
3 -> 238328
4 -> 14776336
5 -> 916132832
6 -> 56800235584
7 -> 3521614606208
8 -> 218340105584896
9 -> 13537086546263552
10 -> 839299365868340224
11 -> 52036560683837093888
12 -> 3226266762397899821056
13 -> 200028539268669788905472
14 -> 12401769434657526912139264
15 -> 768909704948766668552634368
16 -> 47672401706823533450263330816
4、网址缩短算法
网址缩短算法是这里最复杂的一个算法。总体要满足如下的需求:
1、能够生成唯一的字符串
2、最好不要有规律,比如 UYT1,下一个是UYT2
3、使用大写字母、小写字符、数字,共62个组成
综合了以上的需求,我采用如下的算法实现:先预存一个起始的字符串(缩短后的,一般不会在缩短服务中用到这个字符串),进行缩短后,会根据上次的字符串进行逐位递加,简单来说就是一个62进制的数做+1操作(字符来自配置文件中),但是显示的字符不是有规律的,因为我们事先在配置文件中给出的字符串就不是按照顺序来写的,比如,{‘e‘,‘Q‘,‘W‘,‘3‘,‘s‘,‘5‘,‘R‘,‘J‘,‘a‘,‘g‘,‘M‘,‘T‘,‘7‘,‘n‘,‘O‘,‘X‘,‘8‘,‘f‘,‘2‘,‘o‘,‘z‘,‘w‘,‘G‘,‘K‘,‘x‘,‘D‘,‘Z‘,‘F‘,‘b‘,‘u‘,‘N‘,‘L‘,‘S‘,‘l‘,‘Y‘,‘V‘,‘I‘,‘t‘,‘4‘,‘q‘,‘6‘,‘A‘,‘y‘,‘1‘,‘i‘,‘B‘,‘C‘,‘c‘,‘P‘,‘0‘,‘U‘,‘r‘,‘k‘,‘j‘,‘m‘,‘p‘,‘9‘,‘h‘,‘v‘,‘d‘,‘E‘,‘H‘},这可以增强缩短后的字符串的随机性。
function M.get_short_string(last)
local result = {}
local str = ''
if last ~= ngx.null then
str = string.sub(last, #config['prefix']+1, #last-#config['suffix'])
for k in string.gmatch(str, "([0-9a-zA-Z])") do
table.insert(result, k)
end
else
str = table.concat(config['start_url'],'')
result = config['start_url']
end
for i=#str, 1, -1 do
local char = string.sub(str, i, i)
local pos = string.find(config['base_str'], char)
local pos_start = string.find(config['base_str'], config['start_url'][i])
if pos == #config['base_str'] then
pos =0
end
result[i] = config['base_table'][pos+1]
if pos_start ~= pos+1 then
break
elseif i == 1 then
return nil, 53
end
end
return config['prefix'].. table.concat(result,'') .. config['suffix']
end
5、系统需求及安装方法
系统需求:linux、Redis、Openresty
安装方法:
1. 编译安装openresty,要启用lua模块。[http://openresty.org/](http://openresty.org/ “Openresty”)
2. 安装并配置redis软件
3. 下载simple-url-shorten文件,lualib(默认/usr/local/openresty/lualib)目录中新建short目录,将lua代码文件放置于目录中
[root@localhost ~]# ll /usr/local/openresty/lualib/short
-rw-r--r--. 1 root root 2434 Dec 22 16:44 config.lua
-rw-r--r--. 1 root root 3491 Dec 22 16:44 functions.lua
-rw-r--r--. 1 root root 313 Dec 22 16:13 index.lua
-rw-r--r--. 1 root root 369 Dec 22 16:35 shorten.lua
4. 配置nginx.conf(文件默认位置/usr/local/openresty/nginx/conf/nginx.conf)
server {
....
location / {
lua_socket_keepalive_timeout 30s;
content_by_lua_file /usr/local/openresty/lualib/short/index.lua;
}
location /short {
lua_socket_keepalive_timeout 30s;
content_by_lua_file /usr/local/openresty/lualib/short/shorten.lua;
}
...
}
5. 配置simple-url-shorten
...
-- 配置Redis数据库信息
local redis = {}
redis['host'] = '127.0.0.1'
redis['port'] = 6379
redis['password'] = 'passwd'
-- 设置起始的短网址,根据长度可以选择需要多少数量的短网址
-- 1 -> 62
-- 2 -> 3844
-- 3 -> 238328
-- 4 -> 14776336
-- 5 -> 916132832
-- 6 -> 56800235584
-- 7 -> 3521614606208
-- 8 -> 218340105584896
-- 9 -> 13537086546263552
-- 10 -> 839299365868340224
-- 11 -> 52036560683837093888
-- 12 -> 3226266762397899821056
-- 13 -> 200028539268669788905472
-- 14 -> 12401769434657526912139264
-- 15 -> 768909704948766668552634368
-- 16 -> 47672401706823533450263330816
local start_url = {'0','0','0','0'}
-- 短网址前缀
local prefix = ''
-- 短网址后缀
local suffix = ''
-- 短网址的域名
local domain = 'http://192.168.56.201/'
-- 接受网址缩短的白名单和黑名单,白名单优先级高于黑名单;
-- 黑名单中默认包含短网址的域名
local white_host = {}
local black_host = {domain}
......
6、更多
Todo:如果适合业务需要,可以添加统计功能:域名统计、访问统计等
更多内容请参考: https://github.com/peanode/simple-url-shorten