├── .gitignore
├── nginx
├── html
│ └── ourl
│ │ ├── favicon.ico
│ │ ├── css
│ │ └── app.css
│ │ ├── js
│ │ └── index.js
│ │ └── index.html
└── conf
│ ├── nginx.conf
│ ├── vhosts
│ └── ourl.conf
│ └── mime.types
├── dist.ini
├── lualib
└── ourl
│ ├── urls.sql
│ ├── config.sample.lua
│ ├── idna.lua
│ └── init.lua
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.so
2 | *.o
3 | lualib/ourl/config.lua
4 |
--------------------------------------------------------------------------------
/nginx/html/ourl/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaooloong/ourls-resty/HEAD/nginx/html/ourl/favicon.ico
--------------------------------------------------------------------------------
/nginx/html/ourl/css/app.css:
--------------------------------------------------------------------------------
1 | .header {
2 | text-align: center;
3 | }
4 |
5 | .header h1 {
6 | font-size: 200%;
7 | color: #333;
8 | margin-top: 30px;
9 | }
--------------------------------------------------------------------------------
/nginx/conf/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes auto;
2 | user apache;
3 | events {
4 | worker_connections 1024;
5 | }
6 | http {
7 | include mime.types;
8 | default_type application/octet-stream;
9 | sendfile on;
10 | keepalive_timeout 65;
11 |
12 | include vhosts/*.conf;
13 | }
14 |
--------------------------------------------------------------------------------
/dist.ini:
--------------------------------------------------------------------------------
1 | name = ourls-resty
2 | abstract = 一个网址短链接应用,Ourls(PHP) 的 OpenResty 移植
3 | author = xiaooloong
4 | is_original = no
5 | license = mit
6 | lib_dir = lualib
7 | doc_dir = lualib
8 | repo_link = https://github.com/xiaooloong/ourls-resty
9 | main_module = lualib/ourl/init.lua
10 | requires = nginx, hamishforbes/lua-resty-iputils, openresty/lua-resty-string, openresty/lua-resty-mysql
--------------------------------------------------------------------------------
/nginx/conf/vhosts/ourl.conf:
--------------------------------------------------------------------------------
1 | lua_shared_dict ourls 10m;
2 | server {
3 | listen 80;
4 | server_name t.sicaudm.com;
5 | root html/ourl;
6 | index index.html;
7 |
8 | location / {
9 | try_files $uri $uri/ @app;
10 | }
11 | location @app {
12 | internal;
13 | default_type text/html;
14 | content_by_lua_block {
15 | local t = require 'ourl'
16 | t.run()
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lualib/ourl/urls.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE `urls` (
2 | `id` INT (11) NOT NULL AUTO_INCREMENT,
3 | `sha1` CHAR (40) NOT NULL,
4 | `url` VARCHAR (255) NOT NULL,
5 | `create_at` INT (11) NOT NULL,
6 | `creator` INT (11) unsigned NOT NULL DEFAULT '0',
7 | `count` INT (11) NOT NULL DEFAULT '0',
8 | `status` TINYINT(1) NOT NULL DEFAULT '1',
9 | PRIMARY KEY (`id`),
10 | INDEX (`sha1`),
11 | INDEX (`create_at`),
12 | INDEX (`creator`),
13 | INDEX (`count`),
14 | INDEX (`status`)
15 | ) ENGINE = INNODB CHARACTER
16 | SET utf8 COLLATE utf8_unicode_ci;
--------------------------------------------------------------------------------
/lualib/ourl/config.sample.lua:
--------------------------------------------------------------------------------
1 | local ok, new_tab = pcall(require, "table.new")
2 | if not ok or type(new_tab) ~= "function" then
3 | new_tab = function (narr, nrec) return {} end
4 | end
5 | local _M = new_tab(0, 8)
6 | _M.db = new_tab(0, 4)
7 | _M.db_rw = new_tab(0, 8)
8 | _M.db_ro = new_tab(0, 8)
9 | _M.hash = new_tab(0, 4)
10 |
11 | _M.db_rw.host = '127.0.0.1'
12 | _M.db_rw.port = 3306
13 | --_M.db_rw.path = '/var/lib/mysql/mysql.sock'
14 | _M.db_rw.database = 'ourl'
15 | _M.db_rw.user = 'ourl'
16 | _M.db_rw.password = ''
17 |
18 | _M.db_ro.host = '127.0.0.1'
19 | _M.db_ro.port = 3306
20 | --_M.db_ro.path = '/var/lib/mysql/mysql.sock'
21 | _M.db_ro.database = 'ourl'
22 | _M.db_ro.user = 'ourl'
23 | _M.db_ro.password = ''
24 |
25 | _M.hash.salt = 'ourl'
26 | _M.hash.length = 5
27 | _M.hash.alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
28 |
29 | _M.proxies = {
30 | '127.0.0.0/8',
31 | '10.0.0.0/8',
32 | '172.16.0.0/12',
33 | '192.168.0.0/16',
34 | }
35 |
36 | _M.db.timeout = 1000
37 | _M.db.keepalive = 10000
38 | _M.db.poolsize = 10
39 |
40 | _M.log_level = ngx.ALERT
41 | _M.debug = false
42 | return _M
--------------------------------------------------------------------------------
/nginx/html/ourl/js/index.js:
--------------------------------------------------------------------------------
1 | $('#shorten').click(function() {
2 | var raw_url = $('#url').val();
3 | if (validator.isURL(raw_url)) {
4 | var url = encodeURIComponent(raw_url);
5 | $.getJSON(
6 | 'shorten?url=' + url,
7 | function (data) {
8 | if (data.status == 1) {
9 | $('#url').val(data.s_url);
10 | var qrcode = $('#qrcode');
11 | qrcode.qrcode({
12 | width: 200,
13 | height: 200,
14 | text: data.s_url
15 | });
16 | qrcode.removeClass('am-hide')
17 | } else {
18 | alert(data.msg);
19 | }
20 | }
21 | )
22 | } else {
23 | alert('请输入正确的url');
24 | }
25 | });
26 |
27 | $('#expand').click(function() {
28 | var s_url = $('#url').val();
29 | $.getJSON(
30 | 'expand?s_url=' + encodeURIComponent(s_url),
31 | function(data) {
32 | if (data.status == 1) {
33 | $('#url').val(data.url);
34 | var qrcode = $('#qrcode');
35 | qrcode.addClass('am-hide');
36 | qrcode.html('');
37 | } else {
38 | alert(data.msg);
39 | }
40 | }
41 | )
42 | });
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ourls-Resty
2 |
3 | [Ourls][1] 是由 [takashiki][2] 实现的一个基于发号和 hashid 的短网址服务。
4 | 受这个项目的启发,将此项目移植到 [OpenResty][3] 。
5 |
6 | 移植了原项目的功能和特性,并加入了内存缓存支持。
7 |
8 | ### 使用方法
9 |
10 | #### 环境
11 | - 安装 openresty [预编译包][9] (或 [手动编译教程][10])
12 | - 安装 libidn : `yum install libidn`
13 |
14 | #### 安装
15 | - 使用 opm 包管理安装本库: `opm install xiaooloong/ourls-resty`
16 | - 安装 lua 库依赖: `luarocks install net-url && luarocks install router`
17 | - 参考 [hashids.lua][4] 的说明安装 hashids
18 |
19 | #### 配置
20 | - 进入工程目录 `/usr/local/openresty/site/lualib/ourl`
21 | - 复制 `config.sample.lua` 为 `config.lua`
22 | - 修改 `config.lua` 中的数据库配置、hashids 参数、可信代理服务器的 cidr
23 | - 恢复 `urls.sql` 至 `mysql` 或 `mariadb` 数据库
24 | - 进入 `/usr/local/openresty/nginx/conf` 目录
25 | - 根据自己的实际情况,配置静态文件,合并配置
26 |
27 | #### 完成
28 | - 启动 openresty (service openresty start)
29 |
30 | ### 使用到的其他项目
31 |
32 | - [leihog/hashids.lua][4]
33 | - [APItools/router.lua][5]
34 | - [golgote/neturl][6]
35 | - [hamishforbes/lua-resty-iputils][8]
36 |
37 | [1]: https://github.com/takashiki/Ourls
38 | [2]: https://github.com/takashiki
39 | [3]: http://openresty.org/
40 | [4]: https://github.com/leihog/hashids.lua
41 | [5]: https://github.com/APItools/router.lua
42 | [6]: https://github.com/golgote/neturl
43 | [8]: https://github.com/hamishforbes/lua-resty-iputils
44 | [9]: http://openresty.org/cn/rpm-packages.html
45 | [10]: https://moonbingbing.gitbooks.io/openresty-best-practices/content/openresty/install_on_centos.html
--------------------------------------------------------------------------------
/lualib/ourl/idna.lua:
--------------------------------------------------------------------------------
1 | local ffi = require 'ffi'
2 | local ffi_new = ffi.new
3 | local ffi_string = ffi.string
4 | local ffi_typeof = ffi.typeof
5 | local ffi_c = ffi.C
6 | local type = type
7 | local char = string.char
8 | ffi.cdef[[
9 | void free (void *__ptr);
10 | int idna_to_ascii_8z (const char *input, char **output, int flags);
11 | int idna_to_unicode_8z8z (const char *input, char **output, int flags);
12 | ]]
13 | local idna = ffi.load('idn')
14 | local buff_ptr_type = ffi_typeof('char *[1]')
15 |
16 | local ok, new_tab = pcall(require, "table.new")
17 | if not ok or type(new_tab) ~= "function" then
18 | new_tab = function (narr, nrec) return {} end
19 | end
20 |
21 | local _M = new_tab(0, 4)
22 |
23 | _M._VERSION = '0.0.1'
24 |
25 | function _M.encode(text)
26 | if not text or 'string' ~= type(text) or 1 > #text then
27 | return nil, 'empty string'
28 | end
29 | text = text .. char(0)
30 | local buff_out = ffi_new(buff_ptr_type)
31 | local ok = idna.idna_to_ascii_8z(text, buff_out, 0)
32 | if 0 == ok then
33 | local str = ffi_string(buff_out[0])
34 | ffi_c.free(buff_out[0])
35 | return str
36 | else
37 | ffi_c.free(buff_out[0])
38 | return nil, 'failed to encode'
39 | end
40 | end
41 |
42 | function _M.decode(text)
43 | if not text or 'string' ~= type(text) or 1 > #text then
44 | return nil, 'empty string'
45 | end
46 | text = text .. char(0)
47 | local buff_out = ffi_new(buff_ptr_type)
48 | local ok = idna.idna_to_unicode_8z8z(text, buff_out, 0)
49 | if 0 == ok then
50 | local str = ffi_string(buff_out[0])
51 | ffi_c.free(buff_out[0])
52 | return str
53 | else
54 | ffi_c.free(buff_out[0])
55 | return nil, 'failed to encode'
56 | end
57 | end
58 |
59 | return _M
--------------------------------------------------------------------------------
/nginx/html/ourl/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 | Ourls
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
43 |
44 |
45 |
46 |
54 |
55 |
56 |
© 2016 Ourls . Licensed under MIT license.
57 |
58 |
59 |
60 |
61 |
62 |
63 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/nginx/conf/mime.types:
--------------------------------------------------------------------------------
1 |
2 | types {
3 | text/html html htm shtml;
4 | text/css css;
5 | text/xml xml;
6 | image/gif gif;
7 | image/jpeg jpeg jpg;
8 | application/javascript js;
9 | application/atom+xml atom;
10 | application/rss+xml rss;
11 |
12 | text/mathml mml;
13 | text/plain txt;
14 | text/vnd.sun.j2me.app-descriptor jad;
15 | text/vnd.wap.wml wml;
16 | text/x-component htc;
17 |
18 | image/png png;
19 | image/tiff tif tiff;
20 | image/vnd.wap.wbmp wbmp;
21 | image/x-icon ico;
22 | image/x-jng jng;
23 | image/x-ms-bmp bmp;
24 | image/svg+xml svg svgz;
25 | image/webp webp;
26 |
27 | application/font-woff woff;
28 | application/java-archive jar war ear;
29 | application/json json;
30 | application/mac-binhex40 hqx;
31 | application/msword doc;
32 | application/pdf pdf;
33 | application/postscript ps eps ai;
34 | application/rtf rtf;
35 | application/vnd.apple.mpegurl m3u8;
36 | application/vnd.ms-excel xls;
37 | application/vnd.ms-fontobject eot;
38 | application/vnd.ms-powerpoint ppt;
39 | application/vnd.wap.wmlc wmlc;
40 | application/vnd.google-earth.kml+xml kml;
41 | application/vnd.google-earth.kmz kmz;
42 | application/x-7z-compressed 7z;
43 | application/x-cocoa cco;
44 | application/x-java-archive-diff jardiff;
45 | application/x-java-jnlp-file jnlp;
46 | application/x-makeself run;
47 | application/x-perl pl pm;
48 | application/x-pilot prc pdb;
49 | application/x-rar-compressed rar;
50 | application/x-redhat-package-manager rpm;
51 | application/x-sea sea;
52 | application/x-shockwave-flash swf;
53 | application/x-stuffit sit;
54 | application/x-tcl tcl tk;
55 | application/x-x509-ca-cert der pem crt;
56 | application/x-xpinstall xpi;
57 | application/xhtml+xml xhtml;
58 | application/xspf+xml xspf;
59 | application/zip zip;
60 |
61 | application/octet-stream bin exe dll;
62 | application/octet-stream deb;
63 | application/octet-stream dmg;
64 | application/octet-stream iso img;
65 | application/octet-stream msi msp msm;
66 |
67 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
68 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
69 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
70 |
71 | audio/midi mid midi kar;
72 | audio/mpeg mp3;
73 | audio/ogg ogg;
74 | audio/x-m4a m4a;
75 | audio/x-realaudio ra;
76 |
77 | video/3gpp 3gpp 3gp;
78 | video/mp2t ts;
79 | video/mp4 mp4;
80 | video/mpeg mpeg mpg;
81 | video/quicktime mov;
82 | video/webm webm;
83 | video/x-flv flv;
84 | video/x-m4v m4v;
85 | video/x-mng mng;
86 | video/x-ms-asf asx asf;
87 | video/x-ms-wmv wmv;
88 | video/x-msvideo avi;
89 | }
90 |
--------------------------------------------------------------------------------
/lualib/ourl/init.lua:
--------------------------------------------------------------------------------
1 | local config = require 'ourl.config'
2 | local router = require 'router'
3 | local hashid = require 'hashids'
4 | local neturl = require 'net.url'
5 | local idna = require 'ourl.idna'
6 | local iputil = require 'resty.iputils'
7 | local json = require 'cjson'
8 | local mysql = require 'resty.mysql'
9 | local r_sha1 = require 'resty.sha1'
10 | local r_str = require 'resty.string'
11 | local cache = ngx.shared.ourls
12 |
13 | local ok, new_tab = pcall(require, "table.new")
14 | if not ok or type(new_tab) ~= "function" then
15 | new_tab = function (narr, nrec) return {} end
16 | end
17 |
18 | local STATUS_ERR = 0
19 | local STATUS_OK = 1
20 | local r, h, db_rw, db_ro, base, proxy_whitelist
21 |
22 | local function log(...)
23 | ngx.log(config.log_level, json.encode({...}))
24 | end
25 |
26 | local function finish()
27 | for _, db in ipairs({db_rw, db_ro}) do
28 | db:set_keepalive(config.db.keepalive, config.db.poolsize)
29 | end
30 | end
31 |
32 | local function json_api(t)
33 | finish()
34 | if 'table' ~= type(t) then
35 | t = {t}
36 | end
37 | ngx.status = ngx.HTTP_OK
38 | ngx.header['Content-Type'] = 'application/json'
39 | ngx.print(json.encode(t))
40 | return ngx.exit(ngx.status)
41 | end
42 |
43 | local function die(msg, code)
44 | code = code or STATUS_ERR
45 | msg = msg or ''
46 | json_api({
47 | status = code,
48 | msg = msg
49 | })
50 | end
51 |
52 | local function db_query(db, query)
53 | local ok, err = db:send_query(query)
54 | if not ok then
55 | log('failed to send query', query, err)
56 | die('数据库错误')
57 | end
58 |
59 | local res, err, errcode, sqlstate = db:read_result()
60 | if not res then
61 | log('failed to read result of query', query, errcode, err, sqlstate)
62 | die('数据库错误')
63 | elseif config.debug then
64 | log('[DEBUG]', query, res, errcode, err, sqlstate)
65 | end
66 |
67 | return res, err, errcode, sqlstate
68 | end
69 |
70 | local function ip2long(ip)
71 | local l = 0
72 | for v in ngx.re.gmatch(ip, [=[[^\.]+]=], 'o') do
73 | l = l * 256 + tonumber(v[0])
74 | end
75 | return l
76 | end
77 |
78 | local function real_remote_addr()
79 | local ip = ngx.var.remote_addr
80 | local proxy = ngx.req.get_headers()['X-Forwarded-For']
81 | if proxy then
82 | if 'table' == type(proxy) then
83 | proxy = proxy[1]
84 | end
85 | local pattern = [=[([0-9]{1,3}\.){3}[0-9]{1,3}]=]
86 | local m = ngx.re.match(proxy, pattern, 'o')
87 | if m then
88 | proxy = m[0]
89 | if iputil.ip_in_cidrs(ip, proxy_whitelist) then
90 | ip = proxy
91 | end
92 | end
93 | end
94 | return ip2long(ip)
95 | end
96 |
97 | local function url_modify(url, scheme)
98 | scheme = scheme or 'http'
99 | if not ngx.re.match(url, [[^https?://]], 'io') then
100 | url = scheme .. '://' .. url
101 | end
102 | url = neturl.parse(url)
103 | if not url.host then
104 | return nil
105 | end
106 | local ok, err = idna.encode(url.host)
107 | if ok then
108 | url.host = ok
109 | else
110 | if config.debug then
111 | log('[DEBUG]', url.host, err)
112 | end
113 | die('非法域名')
114 | end
115 | return tostring(url:normalize())
116 | end
117 |
118 | local function shorten(params)
119 | local url = params.url
120 | if not url then
121 | die('请输入正确的 url')
122 | end
123 | if 'table' == type(url) then
124 | url = url[1]
125 | end
126 | url = url_modify(url)
127 | if not url then
128 | die('请输入正确的 url')
129 | end
130 | local pattern = ("^https?://%s/"):format(ngx.var.host)
131 | if ngx.re.match(url, pattern, 'o') then
132 | die('该地址不能被缩短')
133 | end
134 | local sha1 = r_sha1:new()
135 | sha1:update(url)
136 | local digest = r_str.to_hex(sha1:final())
137 | local id = cache:get(digest)
138 | if not id then
139 | local query = "SELECT `id` FROM `urls` WHERE `sha1`=" .. ngx.quote_sql_str(digest)
140 | local res = db_query(db_ro, query)
141 | id = 0
142 | if #res > 0 then
143 | id = res[1]['id']
144 | cache:set(digest, id)
145 | else
146 | local ip = real_remote_addr()
147 | local query = ("INSERT INTO `urls` (`sha1`, `url`, `create_at`, `creator`) VALUES (%s, %s, %s, %s)"):format(
148 | ngx.quote_sql_str(digest),
149 | ngx.quote_sql_str(url),
150 | ngx.quote_sql_str(ngx.time()),
151 | ngx.quote_sql_str(ip)
152 | )
153 | local res = db_query(db_rw, query)
154 | id = res['insert_id']
155 | cache:set(digest, id)
156 | end
157 | end
158 | id = tonumber(id)
159 | if not id then
160 | die('服务器错误')
161 | end
162 | local s = h:encode(id)
163 | json_api({
164 | status = STATUS_OK,
165 | s_url = base .. s
166 | })
167 | end
168 |
169 | local function expand(params)
170 | local s = params.s_url
171 | if not s then
172 | die('请传入短链接')
173 | end
174 | if 'table' == type(s) then
175 | s = s[1]
176 | end
177 | local pattern = ("^https?://%s/([%s]+)$"):format(
178 | ngx.var.host,
179 | config.hash.alphabet
180 | )
181 | local m = ngx.re.match(s, pattern, 'o')
182 | if m then
183 | s = m[1]
184 | local id = h:decode(s)
185 | if not id or not id[1] then
186 | die('短地址无法解析')
187 | end
188 | local url = cache:get(id[1])
189 | if not url then
190 | local query = "SELECT `url` FROM `urls` WHERE `id`=" .. ngx.quote_sql_str(id[1])
191 | local res = db_query(db_ro, query)
192 | if #res > 0 then
193 | url = res[1]['url']
194 | cache:set(id[1], url)
195 | else
196 | die('地址不存在')
197 | end
198 | end
199 | json_api({
200 | status = STATUS_OK,
201 | url = url
202 | })
203 | else
204 | die('请传入正确的短链接')
205 | end
206 | end
207 |
208 | local function redirect(params)
209 | local hash = params.hash
210 | if not hash then
211 | die('请传入短地址')
212 | end
213 | if 'table' == type(hash) then
214 | hash = hash[1]
215 | end
216 | local id = h:decode(hash)
217 | if not id or not id[1] then
218 | die('请传入正确的短地址')
219 | end
220 | local url = cache:get(id[1])
221 | if not url then
222 | local query = "SELECT `url` FROM `urls` WHERE `id`=" .. ngx.quote_sql_str(id[1])
223 | local res = db_query(db_ro, query)
224 | if #res > 0 then
225 | url = res[1]['url']
226 | cache:set(id[1], url)
227 | else
228 | die('地址不存在')
229 | end
230 | end
231 | local query = "UPDATE `urls` SET `count`=`count`+1 WHERE `id`=" .. ngx.quote_sql_str(id[1])
232 | db_query(db_rw, query)
233 | finish()
234 | ngx.redirect(url, ngx.HTTP_MOVED_TEMPORARILY)
235 | end
236 | local _M = new_tab(0, 8)
237 |
238 | _M._VERSION = '0.3.2'
239 |
240 | local function prepare()
241 | local err
242 | db_rw, err = mysql:new()
243 | if not db_rw then
244 | log('failed to init mysql master', err)
245 | die('数据库错误')
246 | end
247 | db_ro, err = mysql:new()
248 | if not db_ro then
249 | log('failed to init mysql slave', err)
250 | die('数据库错误')
251 | end
252 | for name, db in pairs({db_rw = db_rw, db_ro = db_ro}) do
253 | db:set_timeout(config.db.timeout)
254 | local ok, err, errcode, sqlstate = db:connect(config[name])
255 | if not ok then
256 | log('failed to connect to mysql', name, errcode, err, sqlstate)
257 | die('数据库错误')
258 | end
259 | local count
260 | count, err = db:get_reused_times()
261 | if 0 == count then
262 | db_query(db, [[SET NAMES 'utf8';]])
263 | elseif err then
264 | log('failed to get reused times', name, err)
265 | die('数据库错误')
266 | end
267 | end
268 |
269 | if not r then
270 | r = router.new()
271 | r:get('/shorten', shorten)
272 | r:get('/expand', expand)
273 | r:get('/:hash', redirect)
274 | end
275 | if not h then
276 | h = hashid.new(config.hash.salt, config.hash.length, config.hash.alphabet)
277 | end
278 | if not base then
279 | base = ("%s://%s/"):format(ngx.var.scheme, ngx.var.host)
280 | end
281 | if not proxy_whitelist then
282 | proxy_whitelist = iputil.parse_cidrs(config.proxies)
283 | end
284 | ngx.req.read_body()
285 | end
286 |
287 | function _M.run()
288 | prepare()
289 | local ok, err = r:execute(
290 | ngx.var.request_method,
291 | ngx.var.uri,
292 | ngx.req.get_uri_args(),
293 | ngx.req.get_post_args()
294 | )
295 | if not ok then
296 | if config.debug then
297 | die('服务器错误: ' .. err)
298 | else
299 | finish()
300 | ngx.status = ngx.HTTP_NOT_FOUND
301 | return ngx.exit(ngx.status)
302 | end
303 | end
304 | end
305 |
306 | return _M
--------------------------------------------------------------------------------