A Rate-Limiting HTTP Proxy(4)HTTP MVC
HTTP
There are several HTTP handling method
Proxy - nginx work as an Proxy
location ~ ^/user {
proxy_pass http://127.0.0.1:8080;
}
I try to make NGINX running on 80 port, but I get this error message:
[emerg] 73020#2236172: bind() to 0.0.0.0:80 failed (13: Permission denied)
Add this to the nginx.conf, restart it with sudoer
user root;
Exception:
nginx: [emerg] getgrnam("root") failed in /opt/luaweb/conf/nginx.conf:1
Solution:
http://blog.csdn.net/u013091013/article/details/51860303
I should as this line to the top.
user root owner;
Add HTML Editor to my Eclipse, add this URL to the plugin list http://download.eclipse.org/releases/mars/ - only select the HTML editor and JS editor
Here is the whole script - nginx.conf
user root owner;
worker_processes 1;
error_log logs/error.log notice;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
root html;
index index.html;
}
location ~ ^/user {
proxy_pass http://localhost:8080;
}
}
lua_package_path "/opt/luaweb/lua/?.lua;;";
server {
listen 8080;
lua_code_cache off;
location ~ /user/(.+) {
default_type text/html;
content_by_lua_file lua/$1.lua;
}
}
}
index.html page to Show the Look and Feel
<html>
<head>
<meta charset="UTF-8">
<title>Login Page</title>
</head>
<body>
UserName: <input type="text" id="username" value="admin">
Password: <input type="password" id="password" value="admin">
<a href="javascript:void(0)" οnclick="login()">Login</a>
<script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script>
function login() {
var username = $('#username').val();
var password = $('#password').val();
$.post('/user/login', {username: username, password: password}, function(res){
console.log(res)
var msg = res.ret ? "登录成功" : "登录失败"
alert(msg)
}, 'json')
}
</script>
</body>
</html>
Here the LUA Script to handle the Login, that can be JAVA,PYTHON or any Other Backend.
lua/login.lua mock the Backend Logic
local req = require "req"
local cjson = require "cjson"
local args = req.getArgs()
local username = args['username']
local password = args['password']
local res = {}
if username == "admin" and password == "admin" then
res['ret'] = true
res['token'] = ngx.md5('admin/' .. tostring(ngx.time()))
else
res['ret'] = false
end
Module ngx.location.capture
We can do something on the params level.
local req = require “req”
local args = req.getArgs()
GET
local res = ngx.location.capture(‘/user/login’, { method = ngx.HTTP_GET, args = args, });
POST
local res = ngx.location.capture(‘/user/login’, { method = ngx.HTTP_POST, body = ngx.encode_args(args), });
Exception if we do GET without Post Body
no request body found; maybe you should turn on lua_need_request_body?
Solution:
That is because the HTTP method is not match in the jQuery. If it is using GET, then lua should be GET, or POST together.
Here is the final local-login.lua
local req = require "req"
local cjson = require "cjson"
local args = req.getArgs()
-- GET
local res = ngx.location.capture('http://localhost/user/login', {method = ngx.HTTP_GET, args = args})
-- POST
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_POST, body = ngx.encode_args(args)})
-- print(res.status) -- status code
if res.status == 200 then
local ret = cjson.decode(res.body)
ret['from'] = 'local'
ngx.say(cjson.encode(ret))
else
print(res.body)
ngx.say('{"ret": false, "from": "local"}')
end
HTML button and command in index.html
<a href="javascript:void(0)" οnclick="local_login()">Local Login</a>
function local_login() {
var username = $('#username').val();
var password = $('#password').val();
$.get('/user/local-login', {username: username, password: password}, function(res){
console.log(res)
var msg = res.ret ? "本地登录成功" : "本地登录失败"
alert(msg)
}, 'json')
}
Third Party Module lua-resty-http
https://github.com/pintsized/lua-resty-http
Exception:
2017/05/18 13:48:18 [error] 19934#2742039: *53 lua entry thread aborted: runtime error: /opt/luaweb/lua/local-login.lua:3: module 'resty.http' not found:
Solution:
https://moonbingbing.gitbooks.io/openresty-best-practices/ngx_lua/how_use_third_lib.html
Copy the lua module script in openresty
>cp ~/Downloads/lua-resty-http-master/lib/resty/*.lua ./
Updated local-login.lua to support Third Party
local req = require "req"
local cjson = require "cjson"
local http = require "resty.http"
local args = req.getArgs()
-- GET
-- local res = ngx.location.capture('http://localhost/user/login', {method = ngx.HTTP_GET, args = args})
-- POST
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_POST, body = ngx.encode_args(args)})
-- http
local httpc = http.new()
local res = httpc:request_uri("http://127.0.0.1:8080/user/login", {
method = "POST",
body = ngx.encode_args(args),
headers = {
["Accept"] = "application/json",
["Accept-Encoding"] = "utf-8",
["Cookie"] = ngx.req.get_headers()['Cookie'],
["Content-Type"] = "application/x-www-form-urlencoded",
}
})
httpc:set_keepalive(60)
-- print(res.status) -- status code
DispatherServlet — MVC
https://github.com/362228416/openresty-web-dev/tree/master/demo8
nginx.conf
http {
lua_package_path "$prefix/lua/?.lua;$prefix/lualib/?.lua;;";
server {
listen 80;
server_name localhost;
lua_code_cache off;
location / {
default_type "text/html; charset=utf-8";
content_by_lua_file lualib/lite/mvc.lua;
}
location ~ ^/js/|^/css/|\.html {
root html;
}
}
}
lualib/lite/mvc.lua is handle the moduleName/methodName
local uri = ngx.var.uri
-- home page
if uri == "" or uri == "/" then
local res = ngx.location.capture("/index.html", {})
ngx.say(res.body)
return
end
local m, err = ngx.re.match(uri, "([a-zA-Z0-9-]+)/*([a-zA-Z0-9-]+)*")
local is_debug = true
local moduleName = m[1] -- module
local method = m[2] -- method
if not method then
method = "index" -- default method index
else
method = ngx.re.gsub(method, "-", "_")
end
-- controller is under web
local prefix = "web."
local path = prefix .. moduleName
-- input the module web.user
local ret, ctrl, err = pcall(require, path)
if ret == false then
if is_debug then
ngx.status = 404
ngx.say("<p style='font-size: 50px'>Error: <span style='color:red'>" .. ctrl .. "</span> module not found !</p>")
end
ngx.exit(404)
end
-- method of the module, get, index
local req_method = ctrl[method]
if req_method == nil then
if is_debug then
ngx.status = 404
ngx.say("<p style='font-size: 50px'>Error: <span style='color:red'>" .. method .. "()</span> method not found in <span style='color:red'>" .. moduleName .. "</span> lua module !</p>")
end
ngx.exit(404)
end
-- call lua method
ret, err = pcall(req_method)
if ret == false then
if is_debug then
ngx.status = 404
ngx.say("<p style='font-size: 50px'>Error: <span style='color:red'>" .. err .. "</span></p>")
else
ngx.exit(500)
end
end
2 Methods in lua/web/user.lua
local cjson = require "cjson"
local req = require "lite.req"
local _M = {}
local users = {"Mr Li", "Mr Luo", "Mr Kang"}
function _M.index()
ngx.say(cjson.encode(users))
end
function _M.get()
local args = req.getArgs()
local index = tonumber(args['index'])
if not index then
index = 1
end
ngx.say(users[index])
end
return _M
We can visit page URL like this
http://localhost/user — lua/web/user.lua method index
http://localhost/user/get?index=1 — lua/web/user.lua method get
Home Page index.html and index.js index.css are as follow:
<html>
<head>
<meta charset="UTF-8">
<title>Home Page</title>
<link rel="stylesheet" href="/css/index.css">
</head>
<body>
<div class="container">
<h1>UserLists</h1>
<ul id="users"></ul>
<p>Second<span id="user"></span></p>
</div>
<script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="/js/index.js"></script>
</body>
</html>
.container {
width: 1000px;
margin: 0 auto;
text-align: center;
}
(function(){
$.getJSON('/user/', function(data){
$('#users').html(data.join(','))
console.log(data)
})
$.get('/user/get', {index: 2}, function(data){
$('#user').html(data)
console.log(data)
})
})()
References:
https://github.com/362228416/openresty-web-dev/tree/master/demo7
https://moonbingbing.gitbooks.io/openresty-best-practices/
HTTP
There are several HTTP handling method
Proxy - nginx work as an Proxy
location ~ ^/user {
proxy_pass http://127.0.0.1:8080;
}
I try to make NGINX running on 80 port, but I get this error message:
[emerg] 73020#2236172: bind() to 0.0.0.0:80 failed (13: Permission denied)
Add this to the nginx.conf, restart it with sudoer
user root;
Exception:
nginx: [emerg] getgrnam("root") failed in /opt/luaweb/conf/nginx.conf:1
Solution:
http://blog.csdn.net/u013091013/article/details/51860303
I should as this line to the top.
user root owner;
Add HTML Editor to my Eclipse, add this URL to the plugin list http://download.eclipse.org/releases/mars/ - only select the HTML editor and JS editor
Here is the whole script - nginx.conf
user root owner;
worker_processes 1;
error_log logs/error.log notice;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
root html;
index index.html;
}
location ~ ^/user {
proxy_pass http://localhost:8080;
}
}
lua_package_path "/opt/luaweb/lua/?.lua;;";
server {
listen 8080;
lua_code_cache off;
location ~ /user/(.+) {
default_type text/html;
content_by_lua_file lua/$1.lua;
}
}
}
index.html page to Show the Look and Feel
<html>
<head>
<meta charset="UTF-8">
<title>Login Page</title>
</head>
<body>
UserName: <input type="text" id="username" value="admin">
Password: <input type="password" id="password" value="admin">
<a href="javascript:void(0)" οnclick="login()">Login</a>
<script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script>
function login() {
var username = $('#username').val();
var password = $('#password').val();
$.post('/user/login', {username: username, password: password}, function(res){
console.log(res)
var msg = res.ret ? "登录成功" : "登录失败"
alert(msg)
}, 'json')
}
</script>
</body>
</html>
Here the LUA Script to handle the Login, that can be JAVA,PYTHON or any Other Backend.
lua/login.lua mock the Backend Logic
local req = require "req"
local cjson = require "cjson"
local args = req.getArgs()
local username = args['username']
local password = args['password']
local res = {}
if username == "admin" and password == "admin" then
res['ret'] = true
res['token'] = ngx.md5('admin/' .. tostring(ngx.time()))
else
res['ret'] = false
end
Module ngx.location.capture
We can do something on the params level.
local req = require “req”
local args = req.getArgs()
GET
local res = ngx.location.capture(‘/user/login’, { method = ngx.HTTP_GET, args = args, });
POST
local res = ngx.location.capture(‘/user/login’, { method = ngx.HTTP_POST, body = ngx.encode_args(args), });
Exception if we do GET without Post Body
no request body found; maybe you should turn on lua_need_request_body?
Solution:
That is because the HTTP method is not match in the jQuery. If it is using GET, then lua should be GET, or POST together.
Here is the final local-login.lua
local req = require "req"
local cjson = require "cjson"
local args = req.getArgs()
-- GET
local res = ngx.location.capture('http://localhost/user/login', {method = ngx.HTTP_GET, args = args})
-- POST
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_POST, body = ngx.encode_args(args)})
-- print(res.status) -- status code
if res.status == 200 then
local ret = cjson.decode(res.body)
ret['from'] = 'local'
ngx.say(cjson.encode(ret))
else
print(res.body)
ngx.say('{"ret": false, "from": "local"}')
end
HTML button and command in index.html
<a href="javascript:void(0)" οnclick="local_login()">Local Login</a>
function local_login() {
var username = $('#username').val();
var password = $('#password').val();
$.get('/user/local-login', {username: username, password: password}, function(res){
console.log(res)
var msg = res.ret ? "本地登录成功" : "本地登录失败"
alert(msg)
}, 'json')
}
Third Party Module lua-resty-http
https://github.com/pintsized/lua-resty-http
Exception:
2017/05/18 13:48:18 [error] 19934#2742039: *53 lua entry thread aborted: runtime error: /opt/luaweb/lua/local-login.lua:3: module 'resty.http' not found:
Solution:
https://moonbingbing.gitbooks.io/openresty-best-practices/ngx_lua/how_use_third_lib.html
Copy the lua module script in openresty
>cp ~/Downloads/lua-resty-http-master/lib/resty/*.lua ./
Updated local-login.lua to support Third Party
local req = require "req"
local cjson = require "cjson"
local http = require "resty.http"
local args = req.getArgs()
-- GET
-- local res = ngx.location.capture('http://localhost/user/login', {method = ngx.HTTP_GET, args = args})
-- POST
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_POST, body = ngx.encode_args(args)})
-- http
local httpc = http.new()
local res = httpc:request_uri("http://127.0.0.1:8080/user/login", {
method = "POST",
body = ngx.encode_args(args),
headers = {
["Accept"] = "application/json",
["Accept-Encoding"] = "utf-8",
["Cookie"] = ngx.req.get_headers()['Cookie'],
["Content-Type"] = "application/x-www-form-urlencoded",
}
})
httpc:set_keepalive(60)
-- print(res.status) -- status code
DispatherServlet — MVC
https://github.com/362228416/openresty-web-dev/tree/master/demo8
nginx.conf
http {
lua_package_path "$prefix/lua/?.lua;$prefix/lualib/?.lua;;";
server {
listen 80;
server_name localhost;
lua_code_cache off;
location / {
default_type "text/html; charset=utf-8";
content_by_lua_file lualib/lite/mvc.lua;
}
location ~ ^/js/|^/css/|\.html {
root html;
}
}
}
lualib/lite/mvc.lua is handle the moduleName/methodName
local uri = ngx.var.uri
-- home page
if uri == "" or uri == "/" then
local res = ngx.location.capture("/index.html", {})
ngx.say(res.body)
return
end
local m, err = ngx.re.match(uri, "([a-zA-Z0-9-]+)/*([a-zA-Z0-9-]+)*")
local is_debug = true
local moduleName = m[1] -- module
local method = m[2] -- method
if not method then
method = "index" -- default method index
else
method = ngx.re.gsub(method, "-", "_")
end
-- controller is under web
local prefix = "web."
local path = prefix .. moduleName
-- input the module web.user
local ret, ctrl, err = pcall(require, path)
if ret == false then
if is_debug then
ngx.status = 404
ngx.say("<p style='font-size: 50px'>Error: <span style='color:red'>" .. ctrl .. "</span> module not found !</p>")
end
ngx.exit(404)
end
-- method of the module, get, index
local req_method = ctrl[method]
if req_method == nil then
if is_debug then
ngx.status = 404
ngx.say("<p style='font-size: 50px'>Error: <span style='color:red'>" .. method .. "()</span> method not found in <span style='color:red'>" .. moduleName .. "</span> lua module !</p>")
end
ngx.exit(404)
end
-- call lua method
ret, err = pcall(req_method)
if ret == false then
if is_debug then
ngx.status = 404
ngx.say("<p style='font-size: 50px'>Error: <span style='color:red'>" .. err .. "</span></p>")
else
ngx.exit(500)
end
end
2 Methods in lua/web/user.lua
local cjson = require "cjson"
local req = require "lite.req"
local _M = {}
local users = {"Mr Li", "Mr Luo", "Mr Kang"}
function _M.index()
ngx.say(cjson.encode(users))
end
function _M.get()
local args = req.getArgs()
local index = tonumber(args['index'])
if not index then
index = 1
end
ngx.say(users[index])
end
return _M
We can visit page URL like this
http://localhost/user — lua/web/user.lua method index
http://localhost/user/get?index=1 — lua/web/user.lua method get
Home Page index.html and index.js index.css are as follow:
<html>
<head>
<meta charset="UTF-8">
<title>Home Page</title>
<link rel="stylesheet" href="/css/index.css">
</head>
<body>
<div class="container">
<h1>UserLists</h1>
<ul id="users"></ul>
<p>Second<span id="user"></span></p>
</div>
<script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="/js/index.js"></script>
</body>
</html>
.container {
width: 1000px;
margin: 0 auto;
text-align: center;
}
(function(){
$.getJSON('/user/', function(data){
$('#users').html(data.join(','))
console.log(data)
})
$.get('/user/get', {index: 2}, function(data){
$('#user').html(data)
console.log(data)
})
})()
References:
https://github.com/362228416/openresty-web-dev/tree/master/demo7
https://moonbingbing.gitbooks.io/openresty-best-practices/