Skip to content

Commit 0c84abb

Browse files
committed
test
1 parent ab48c04 commit 0c84abb

File tree

10 files changed

+298
-42
lines changed

10 files changed

+298
-42
lines changed

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# lua-resty-router
22

3-
High performance and productive router for Openresty.
3+
Elegant, performant and productive router for Openresty.
44

55
# Router
66

@@ -98,3 +98,7 @@ assert(tree:match('/v1','GET') == 'v1')
9898
assert(tree:match('/v2','POST') == 'v2')
9999
assert(tree:match('/v2','GET') == nil)
100100
```
101+
102+
## reference
103+
104+
- [nginx api for lua](https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#nginx-api-for-lua)

app.lua

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
local Router = require('resty.router')
2+
3+
local router = Router:new()
4+
5+
-- 测试插件
6+
router:use(function(ctx)
7+
ctx.plugin_executed = true
8+
ctx:yield()
9+
end)
10+
11+
-- 测试事件
12+
router:on('success', function(ctx)
13+
ngx.log(ngx.INFO, "请求成功")
14+
end)
15+
16+
router:on('error', function(ctx)
17+
ngx.log(ngx.INFO, "请求失败")
18+
end)
19+
20+
-- 1. 测试静态路径
21+
router:get("/hello", function()
22+
return "Hello World"
23+
end)
24+
25+
-- 2. 测试JSON响应
26+
router:get("/json", function()
27+
return { message = "success", code = 0 }
28+
end)
29+
30+
-- 3. 测试动态路径参数
31+
router:get("/users/#id", function(ctx)
32+
return {
33+
id = ctx.params.id,
34+
type = "number"
35+
}
36+
end)
37+
38+
router:get("/users/:name", function(ctx)
39+
return {
40+
name = ctx.params.name,
41+
type = "string"
42+
}
43+
end)
44+
45+
-- 4. 测试正则路径
46+
router:get("/version/<ver>\\d+\\.\\d+", function(ctx)
47+
return {
48+
version = ctx.params.ver
49+
}
50+
end)
51+
52+
-- 5. 测试通配符
53+
router:get("/files/*path", function(ctx)
54+
return {
55+
path = ctx.params.path
56+
}
57+
end)
58+
59+
-- 6. 测试多个HTTP方法
60+
router:post("/users", function(ctx)
61+
return { method = "POST" }
62+
end)
63+
64+
router:put("/users/#id", function(ctx)
65+
return { method = "PUT", id = ctx.params.id }
66+
end)
67+
68+
-- 7. 测试错误处理
69+
router:get("/error", function()
70+
error("测试错误")
71+
end)
72+
73+
-- 8. 测试状态码
74+
router:get("/404", function()
75+
return nil, "Not Found", 404
76+
end)
77+
78+
-- 9. 测试HTML响应
79+
router:get("/html", function()
80+
return "<h1>Hello HTML</h1>"
81+
end)
82+
83+
-- 10. 测试函数返回
84+
router:get("/func", function()
85+
return function()
86+
ngx.say("function called")
87+
return true
88+
end
89+
end)
90+
91+
return router

conf/nginx.conf

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
worker_processes auto;
2+
pid logs/nginx.pid;
3+
4+
error_log logs/error.log;
5+
events {
6+
worker_connections 1024;
7+
}
8+
9+
http {
10+
default_type application/json;
11+
access_log logs/access.log;
12+
13+
lua_package_path './lib/?.lua;;';
14+
lua_code_cache on;
15+
uwsgi_temp_path /tmp;
16+
fastcgi_temp_path /tmp;
17+
client_body_temp_path /tmp;
18+
proxy_temp_path /tmp;
19+
scgi_temp_path /tmp;
20+
server {
21+
listen 8080;
22+
server_name localhost;
23+
charset utf-8;
24+
25+
location / {
26+
content_by_lua_block {
27+
require("app"):run()
28+
}
29+
}
30+
}
31+
}

dist.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name = lua-resty-router
2-
abstract = High performance and productive router for Openresty
2+
abstract = Elegant, performant and productive router for Openresty
33
author = Nan Xiang(@xiangnanscu)
44
is_original = yes
55
license = mit

lib/resty/router.lua

+79-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local encode = require "cjson.safe".encode
1+
local json = require "cjson.safe"
22
local bit = bit
33
local gmatch = string.gmatch
44
local ipairs = ipairs
@@ -15,6 +15,15 @@ local ngx_var = ngx.var
1515
local string_format = string.format
1616
local xpcall = xpcall
1717
local spawn = ngx.thread.spawn
18+
local ngx_req = ngx.req
19+
local decode = json.decode
20+
local encode = json.encode
21+
local get_post_args = ngx.req.get_post_args
22+
local read_body = ngx.req.read_body
23+
local get_body_data = ngx.req.get_body_data
24+
local assert = assert
25+
local rawget = rawget
26+
local setmetatable = setmetatable
1827

1928
local method_bitmask = {
2029
GET = 1, -- 2^0
@@ -351,100 +360,131 @@ function Router:emit(event_key, ...)
351360
end
352361
end
353362

363+
local Response = {
364+
header = ngx_header,
365+
get_headers = ngx_req.get_headers,
366+
}
367+
Response.__index = Response
368+
369+
local Context = {
370+
yield = coroutine.yield
371+
}
372+
---@private
373+
function Context.__index(self, key)
374+
if Context[key] ~= nil then
375+
return Context[key]
376+
elseif ngx_req[key] ~= nil then
377+
return ngx_req[key]
378+
elseif key == 'response' then
379+
return setmetatable({}, Response)
380+
elseif key == 'query' then
381+
self.query = ngx_req.get_uri_args()
382+
return rawget(self, 'query')
383+
else
384+
return nil
385+
end
386+
end
387+
354388
---@return table
355389
function Router:create_context()
356-
return setmetatable({ yield = coroutine.yield }, ngx.req)
390+
return setmetatable({}, Context)
357391
end
358392

359393
---@param path string
360394
---@param method string
361395
---@return boolean
362396
---@overload fun(string, string): boolean
363397
function Router:dispatch(path, method)
364-
local handler, params_or_code = self:match(path, method)
365-
if handler == nil then
366-
return self:fail('match route failed', {}, params_or_code)
367-
end
368-
398+
-- before plugins
369399
local ctx = self:create_context()
370-
if params_or_code then
371-
ctx.params = params_or_code
372-
end
373-
374400
for _, plugin in ipairs(self.plugins) do
375401
local co = coroutine.create(function()
376402
plugin(ctx)
377403
end)
378404
local ok, err = resume(co)
379405
if not ok then
380-
return self:fail(err, ctx, 500)
406+
return self:fail(ctx, err)
381407
end
382408
if coroutine.status(co) == "suspended" then
383409
ctx[#ctx + 1] = co
384410
end
385411
end
386-
412+
-- match route
413+
local handler, params_or_code = self:match(path, method)
414+
if handler == nil then
415+
return self:fail(ctx, 'match route failed', params_or_code)
416+
end
417+
if params_or_code then
418+
ctx.params = params_or_code
419+
end
387420
if type(handler) == 'string' then
388-
return self:ok(handler, ctx)
421+
return self:ok(ctx, handler)
389422
else
390423
---@diagnostic disable-next-line: param-type-mismatch
391-
local ok, result, err = xpcall(handler, trace_back, ctx)
424+
local ok, result, err_or_okcode, errcode = xpcall(handler, trace_back, ctx)
392425
if not ok then
393-
return self:fail(result, ctx, 500)
426+
return self:fail(ctx, result)
394427
elseif result == nil then
395-
return self:fail(err, ctx, 500)
428+
if err_or_okcode ~= nil then
429+
return self:fail(ctx, err_or_okcode, errcode)
430+
elseif rawget(ctx, 'response') then
431+
local code = ctx.response.status or 200
432+
return self:finish(ctx, code, ngx.exit, code)
433+
else
434+
return self:fail(ctx, 'no response')
435+
end
396436
else
397437
local resp_type = type(result)
398438
if resp_type == 'table' or resp_type == 'boolean' or resp_type == 'number' then
399-
local json, encode_err = encode(result)
400-
if not json then
401-
return self:fail(encode_err, ctx)
439+
local response_json, encode_err = encode(result)
440+
if not response_json then
441+
return self:fail(ctx, encode_err)
402442
else
403443
ngx_header.content_type = 'application/json; charset=utf-8'
404-
return self:ok(json, ctx)
444+
return self:ok(ctx, response_json, err_or_okcode)
405445
end
406446
elseif resp_type == 'string' then
407447
if byte(result) == 60 then -- 60 is ASCII value of '<'
408448
ngx_header.content_type = 'text/html; charset=utf-8'
409449
else
410450
ngx_header.content_type = 'text/plain; charset=utf-8'
411451
end
412-
return self:ok(result, ctx)
452+
return self:ok(ctx, result, err_or_okcode)
413453
elseif type(result) == 'function' then
414-
ok, result, err = xpcall(result, trace_back)
454+
ok, result, err_or_okcode, errcode = xpcall(result, trace_back, ctx)
415455
if not ok then
416-
return self:fail(result, ctx, 500)
456+
return self:fail(ctx, result)
417457
elseif result == nil then
418-
return self:fail(err, ctx, 500)
458+
return self:finish(ctx, 500, ngx.exit, 500)
419459
else
420-
return self:finish(200, ctx)
460+
return self:finish(ctx, 200, ngx.exit, 200)
421461
end
422462
else
423-
return self:fail('invalid response type: ' .. resp_type)
463+
return self:fail(ctx, 'invalid response type: ' .. resp_type)
424464
end
425465
end
426466
end
427467
end
428468

429-
function Router:ok(body, ctx, code)
469+
function Router:ok(ctx, body, code)
430470
ngx_print(body)
431471
code = code or 200
432-
return self:finish(code, ctx, ngx.exit, code)
472+
return self:finish(ctx, code, ngx.exit, code)
433473
end
434474

435-
function Router:fail(err, ctx, code)
475+
function Router:fail(ctx, err, code)
436476
ngx_print(err)
437477
code = code or 500
438-
return self:finish(code, ctx, ngx.exit, code)
478+
return self:finish(ctx, code, ngx.exit, code)
439479
end
440480

441481
function Router:redirect(ctx, uri, code)
442482
code = code or 302
443-
return self:finish(code, ctx, ngx.redirect, uri, code)
483+
return self:finish(ctx, code, ngx.redirect, uri, code)
444484
end
445485

446-
function Router:exec(uri, args, ctx)
447-
return self:finish(200, ctx, ngx.exec, uri, args)
486+
function Router:exec(ctx, uri, args)
487+
return self:finish(ctx, ngx.OK, ngx.exec, uri, args)
448488
end
449489

450490
local function get_event_key(events, code)
@@ -467,7 +507,7 @@ local function get_event_key(events, code)
467507
end
468508
end
469509

470-
function Router:finish(code, ctx, ngx_func, ...)
510+
function Router:finish(ctx, code, ngx_func, ...)
471511
local events = self.events
472512
if events[code] then
473513
self:emit(code, ctx)
@@ -485,4 +525,8 @@ function Router:finish(code, ctx, ngx_func, ...)
485525
return ngx_func(...)
486526
end
487527

528+
function Router:run()
529+
return self:dispatch(ngx_var.document_uri, ngx_var.request_method)
530+
end
531+
488532
return Router

package.json

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
"pull": "uname -s | grep -q Darwin && yarn _pull || while true; do timeout 10 yarn _pull && break; done",
1818
"resty": "/usr/local/openresty/bin/resty -I template -I resty_modules/lualib -I resty_modules/site/lualib --main-conf 'env NODE_ENV;' --http-conf 'lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;'",
1919
"busted": "yarn resty -I spec template/bin/busted.lua -o TAP",
20-
"lab": "pnpm build && ./outfile.cjs",
20+
"sync": "cp lib/resty/router.lua template/lib/resty/router.lua",
21+
"lab": "yarn sync && pnpm build && ./outfile.cjs",
2122
"format": "prettier --write .",
2223
"build": "zx ./scripts/build.mjs",
2324
"snapshot": "zx ./scripts/snapshot.mjs",
24-
"pretest": "run-s build snapshot",
25+
"pretest2": "run-s build snapshot",
2526
"prepublishOnly": "pnpm build",
2627
"prepublishOnly2": "zx ./scripts/prepublish.mjs",
27-
"test": "resty test_spec.lua"
28+
"nginx": "nginx -p . -c conf/nginx.conf",
29+
"test": "yarn nginx; ./test.sh ; yarn nginx -s stop"
2830
},
2931
"author": "",
3032
"license": "ISC",

template/app.lua

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
local Router = require('resty.router')
2+
3+
local router = Router:new()
4+
5+
router:get('/', function(ctx)
6+
ctx.response.status = 200
7+
ctx.response.body = 'Hello, World!'
8+
end)
9+
10+
return router

template/conf/nginx.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ http {
1010
include mime.types;
1111
default_type application/json;
1212

13-
access_log logs/access.log main;
13+
access_log logs/access.log;
1414

1515
sendfile on;
1616
tcp_nopush on;

0 commit comments

Comments
 (0)