使用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

url-shortner

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

posted @ 2017-01-04 22:25  princessd8251  阅读(1158)  评论(0)    收藏  举报