diff --git a/Lua-Script/lua-basic.md b/Lua-Script/lua-basic.md
new file mode 100644
index 0000000..7eafa66
--- /dev/null
+++ b/Lua-Script/lua-basic.md
@@ -0,0 +1,486 @@
+#### Lua 基础语法
++ 删除一个全局变量,只要将变量值赋值为nil:`a = nil`,当且仅当一个变量不为nil 时,这个变量存在
++ `Boolean`类型:在控制条件中除了`false`和`nil` 为假,其他值都为真,所以lua认为0和空字符串也是真
++ `String`类型:
+ + 字符串替换:`string.gsub()`
+ ```lua
+ a = 'one HELLO'
+ b = string.gsub(a,'one','two')
+ print(a) -- one HELLO
+ print(b) -- two HELLO
+ ```
+ + 字符串和数字
+ ```lua
+ print("10" + 1) -- 11
+ print("10" + "1") -- 11
+ print("10 + 1") -- 10 + 1
+ print("hello " .. " world") -- hello world
+ --print("hello" + 1) -- 错误写法
+ ```
+ + 字符串和数字转换
+ ```lua
+ a = 10
+ print(tostring(a)) -- 10
+ b = "20"
+ print(tonumber(b)) -- "20"
+
+ print(tostring(10) == "10") -- true
+ print(10 .. "" == "10") -- true
+ ```
++ 表达式
+ + 如果两个值类型不相等,Lua认为两者不同
+ + nil 只和自己相等
+ + 逻辑运算符
+ ```lua
+ -- a and b -- 如果a为false,则返回a ,否则返回b
+ -- a or b -- 如果a为true,则返回a ,否则返回b
+ print(4 and 5) -- 5
+ print(nil and 12 ) -- nill
+ print(false and 12) -- false
+ print(4 or 5) -- 4
+ print(false or 5) -- 5
+ ```
+ + 注意:`and`的优先级比`or`高
+ + Lua 三元运算符:`( a and b) or c`
++ 变量
+ + 赋值语句
+ ```lua
+ x = 20
+ y = 30
+ x,y = y,x
+ print(x,y) -- 30 20
+
+ a,b,c = 10,20
+ print(a,b,c) --10 20 nil
+
+ x,y,z = 10
+ print(x,y,z) -- 10 nil nil
+ ```
+ + 局部变量与代码块
+ + 代码块:指一个控制结构内,一个函数体,或者一个chunk(变量被声明的哪个文件或者文本串)
+ + ```lua
+ a = 12
+ if a>10 then
+ local i = 19
+ print(i) -- 19
+ end
+ print(i) -- nil
+ ```
++ 控制语句
+ ```lua
+ members = { Tom = 10, Jake = 11, Dodo = 12, Jhon = 16 }
+
+ for k, v in pairs(members) do
+ if v == 10 then
+ print(k, 'is 10 years old') -- Tom is 10 years old
+ elseif v == 11 then
+ print(k, 'is 11 years old') -- Jake is 11 years old
+ elseif v == 12 then
+ print(k, 'is 12 years old') -- Dodo is 12 years old
+ else
+ print(k, "is not 10,11,12 years old") -- Jhon is not 10,11,12 years old
+ end
+ end
+ ```
++ 函数
+ + 单个返回值
+ ```lua
+ function max(a,b)
+ if a > b then
+ return a
+ else
+ return b
+ end
+ end
+ print(max(10,20)) -- 20
+ ```
+ + 多个返回值
+ ```lua
+ function more()
+ return 10 , 20 ,30
+ end
+ a , b , c = more()
+ print(a,b,c) -- 10 20 30
+ ```
+ + 可变数目的参数
+ ```lua
+ function more()
+ return 10 , 20 ,30
+ end
+ -- 当函数位于最后一位的时候,返回全部值,否则值返回一个数值
+ a , b , c ,d = 100, more()
+ print(a,b,c,d) -- 100 10 20 30
+ ```
+ + 闭合函数
+ ```lua
+ function count()
+ -- i属于一个非局部变量,因为它既不是全局变量,也不是单纯的局部变量(因为另外一个函数可以访问到它)
+ local i = 0
+ return function()
+ i =i +1
+ return i
+ end
+ end
+ -- 以上 count()函数里的那个函数,加上一个非全局变量i,就构成一个闭合函数
+ -- 所以每次调用闭合函数,非局部变量的值都不会被重置
+ local func = count()
+ print(func()) -- 1
+ print(func()) -- 2
+ ```
+ + 非全局函数,在定义函数的使用要注意定义函数的顺序
+ ```lua
+ local eat
+ local drink
+ eat = function()
+ print("eat")
+ return drink() -- 这里的drink()属于尾调用
+ end
+ drink = function()
+ print("drink")
+ end
+ eat()
+ ```
++ table 使用
+ + Lua table 第一个索引为1
+ + 简单
+ ```lua
+ a = {}
+ a.x = 100
+ a.y = 200
+ a["z"] = 300 -- a.z = 300
+ print(a.x) -- 100
+ print(a.y) -- 200
+ print(a.z) -- 300
+ ```
++ 泛型迭代器
+ + 标准库迭代器包括:
+ + 迭代文件每行:`io.lines`
+ + 迭代table元素:`pairs`
+ - [x] 可以遍历表中的所有key
+ - [x] 并且除了迭代器本身以及遍历表本身,还可以返回nil
+ + 迭代数组元素:`ipairs`
+ - [x] ipairs不能返回nil,只能返回数字0,如果遇到nil则退出
+ - [x] 只能遍历表中出现的第一个不是整数的key
+ + 泛型迭代器
+ ```lua
+ config = {host = '127.0.0.1',port = '3306', dbname = 'LuaDB' }
+ config.redis_host = "192.168.1.1"
+ config.redis_port = "6379"
+ config.redis_db = "12"
+ print(config['redis_host']) -- 192.168.1.1
+ print(config.redis_port) -- 6379
+ print(config.dbname) -- LuaDB
+
+ for k, v in pairs(config) do
+ print(k,v)
+ end
+
+ --[[
+ host 127.0.0.1
+ dbname LuaDB
+ redis_host 192.168.1.1
+ redis_db 12
+ redis_port 6379
+ port 3306
+ -- ]]
+ ```
+ + 迭代table元素
+ ```lua
+ arr = {}
+ for var = 1,100 do -- for 循环
+ table.insert(arr,1,var)
+ end
+
+ for k, v in pairs(arr) do -- 遍历表
+ print(k,v)
+ end
+ --[[ 打印结果
+ 1 100
+ 2 99
+ ... ...
+ 99 2
+ 100 1
+
+ -- ]]
+ print(table.maxn(arr)) -- table长度 100
+ print(#arr) -- table长度(快捷方式) 100
+ ```
+ + 迭代数组元素:`ipairs`
+ ```lua
+ arr = {host = '127.0.0.1',port = '3306','Tinywan'}
+ -- 如果没有找到下标为整数的则直接退出,是整数的则直接输出,如上面的'Tinywan'
+ for k, v in ipairs(arr) do -- 只能遍历key 为整数的下标
+ print(k,v) -- 1 Tinywan
+ end
+ ```
+ + 循环迭代table元素(如:lua-resty-mysql 扩展查询的数据)
+ + 查询 :`res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)`
+ + 转换成JSON结果集输出2条记录:
+ ```lua
+ ngx.say("result: ", cjson.encode(res))
+ result: [{"age":"24123","name":"tinywan123","address":"China","id":"1"},{"age":"24","name":"tinywan","address":"China","id":"2"}]
+ ```
+ + 遍历该结果集:
+ ```lua
+ res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)
+ if not res then
+ ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
+ return
+ end
+
+ for k, v in pairs(res) do
+ if type(v) == "table" then
+ for new_table_index, new_table_value in pairs(v) do
+ ngx.say(new_table_index.." = "..new_table_value)
+ end
+ else
+ ngx.say(k,v)
+ end
+ end
+
+ --[[ 打印结果
+ age = 24123
+ name = tinywan123
+ address = China
+ id = 1
+ age = 24
+ name = tinywan
+ address = China
+ id = 2
+ ]]
+ ```
+ + json 和 lua table 转换
+ + [1] 将 json 转换成 lua table
+ ```lua
+ local json_str = '{"is_male":"nan","name":"zhangsan","id":1}'
+ local t = json.decode(json_str)
+ ngx.say(format_table(t))
+ ```
+ + [2] 将 lua table 转换成 json 字符串
+ ```lua
+ local t = [[{key="table key",value="table value"}]]
+ local json_str = json.encode(t)
+ ngx.say(json_str) -- "{key=\"table key\",value=\"table value\"}"
+ ```
+ + [3] 将lua table转换成 json 数组 (lua 两个大括号表示一个数组)
+ ```lua
+ local t = {keys={"list1","list2","list3"},num=1}
+ local str = json.encode(t)
+ ngx.say(str) -- {"keys":["list1","list2","list3"],"num":1}
+ ```
++ 编译执行与错误
+ + error 错误
+ ```lua
+ local name = "Lua1"
+ if name ~= "Lua"
+ then
+ error("this is not Lua ");
+ end
+ ```
+ + assert 错误:`assert(name~="Lua"," this is not Lua")`
+ + pcall 捕获错误代码
+ ```lua
+ function test()
+ print(a[1])
+ end
+ -- pcall 除了会返回true或者false外,还能返回函数的错误信息。
+ -- 如果没有错误信息,err 会返回一个nil
+ local status,err = pcall(test)
+ if status then
+ print('success')
+ else
+ print('函数执行出错了')
+ print('错误信息:',err)
+ end
+ ```
++ Lua面向对象(重点)
+ + [博客详细地址描述](http://www.cnblogs.com/tinywan/p/6940784.html)
+ + :white_check_mark: `__add` 元方法 #demo1
+ ```lua
+ local mt = {}
+ mt.__add = function(t1, t2)
+ print("两个Table 相加的时候会调用我")
+ end
+ local t1 = {}
+ local t2 = {}
+ -- 给两个table 设置新的元表,一个元表就是一个table的值
+ setmetatable(t1, mt) -- meta:元素
+ setmetatable(t2, mt)
+ -- 进行相加操作
+ local t = t1 + t2
+ print(t)
+
+ --[[输出结果
+ 两个Table 相加的时候会调用我
+ nil
+ --]]
+ ```
+ + :white_check_mark: `__add` 元方法 #demo2
+ ```lua
+ -- 创建一个元表 (是创建一个类吗?)
+ local mt = {}
+ mt.__add = function(s1, s2)
+ local result = ""
+ if s1.sex == "boy" and s2.sex == "girl" then
+ result = "一个男孩和一个女孩的家庭"
+ elseif s1.sex == "girl" and s2.sex == "girl" then
+ result = "两个女孩的家庭"
+ else
+ result = "未知孩子的家庭"
+ end
+ return result
+ end
+ -- 创建两个table,可以想象成是两个类的对象(实例化两个类)
+ local s1 = { name = "Per1", sex = "boy" }
+ local s2 = { name = "Per2", sex = "girl" }
+ -- 给两个table 设置新的元表,一个元表就是一个table的值
+ setmetatable(s1, mt)
+ setmetatable(s2, mt)
+ -- 进行加法操作
+ local result = s1 + s2
+ print(result)
+
+ -- 输出结果 一个男孩和一个女孩的家庭
+ ```
+ + :white_check_mark: `__index` 元方法 #demo1
+ ```lua
+ local t = {
+ name = "Tinywan"
+ }
+ local mt = {
+ __index = function(table, key)
+ print("虽然你调用了我不存在的字段和方法,不过没关系,我能检测出来" .. key)
+ end
+ }
+ setmetatable(t, mt)
+ print(t.name)
+ print(t.age)
+
+ --[[输出结果
+ -- Tinywan
+ -- 虽然你调用了我不存在的字段和方法,不过没关系,我能检测出来age
+ -- nil
+ ---- ]]
+ ```
+ + :white_check_mark: `__index` 元方法 #demo2
+ ```lua
+ local t = {
+ name = "Tinywan"
+ }
+ local mt = {
+ money = 808080
+ }
+
+ mt.__index = mt
+ setmetatable(t, mt)
+ print(t.money)
+ -- 输出结果 808080
+ ```
+ + :white_check_mark: `__index` 元方法 #demo3
+ ```lua
+ local t = {
+ name = "Tinywan"
+ }
+ local mt = {
+ __index = {
+ money = 909090
+ }
+ }
+ setmetatable(t, mt)
+ print(t.money)
+ -- 输出结果 909090
+ ```
+ + :white_check_mark: `__index` 元方法 #demo4
+ ```lua
+ local smartMan = {
+ name = "Tinywan",
+ age = 26,
+ money = 800000,
+ say_fun = function()
+ print("Tinywan say 大家好")
+ end
+ }
+
+ local t1 = {}
+ local t2 = {}
+ local mt = { __index = smartMan } -- __index 可以是一个表,也可以是一个函数
+ setmetatable(t1, mt)
+ setmetatable(t2, mt)
+ print(t1.money)
+ t2.say_fun()
+ --- 输出结果
+ -- 800000
+ -- Tinywan say 大家好
+ ```
+ + Lua面向对象1
+ + Lua面向对象1
+ + Lua面向对象3 更新中...
++ Lua 排序算法
+ + [Lua 排序算法 - 选择排序](https://www.openresty.com.cn/ms2008-select-sort.html#section-1)
+ + 选择排序
+ ```lua
+ local function selectionSort(arr)
+ for i = 1,#arr-1 do
+ local idx = i
+ -- 迭代剩下的元素,寻找最小的元素
+ for j = i+1,#arr do
+ if arr[j] < arr[idx] then
+ idx = j
+ end
+ end
+ --
+ arr[i],arr[idx]= arr[idx],arr[i]
+ end
+ end
+
+ local list = {
+ -81, -93, -36.85, -53, -31, 79, 45.94, 36, 94, -95.03, 11, 56, 23, -39,
+ 14, 1, -20.1, -21, 91, 31, 91, -23, 36.5, 44, 82, -30, 51, 96, 64, -41
+ }
+
+ selectionSort(list)
+ print(table.concat( list, ", "))
+ ```
+#### 控制结构
++ [if-elseif-end 语句](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/if-else-example.lua)
++ [for 语句](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/for-example.lua)
++ [Lua 只有一个容器,那就是table](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/container-table.lua)
+#### [Lua 实现简单封装](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/function1.lua)
+#### Table 操作常用的方法
++ table.concat (table [, sep [, start [, end]]])
+ + concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开
+ + demo
+ ```lua
+ fruits = {"banana","orange","apple"}
+ -- 返回 table 连接后的字符串 value = banana orange apple
+ print("连接后的字符串 ",table.concat(fruits))
+ -- 指定连接字符 value = banana, orange, apple
+ print("指定连接字符连接后的字符串 ",table.concat(fruits,", "))
+ ```
++ table.insert (table, [pos,] value):
+ + 在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾
+ + demo
+ ```lua
+ fruits = {"banana","orange","apple"}
+
+ -- 在末尾插入
+ table.insert(fruits,"Tinywan4")
+ print("索引为 4 的元素为 ",fruits[4]) -- 索引为 4 的元素为 Tinywan
+
+ -- 在索引为 2 的键处插入
+ table.insert(fruits,2,'Tinywan2')
+ print("索引为 2 的元素为 ",fruits[2]) -- 索引为 2 的元素为 Tinywan
+
+ print("最后一个元素为 ",fruits[5]) -- 最后一个元素为 Tinywan4
+ table.remove(fruits)
+ print("移除后最后一个元素为 ",fruits[5]) -- 移除后最后一个元素为 nil
+ ```
++ table.sort (table [, comp])
+ + 对给定的table进行升序排序
+#### Lua 模块与包
++ 定义:Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行.
++ Table 操作常用的方法
+ - [x] table.concat()
+ - [x] table.insert()
+ - [x] table.maxn()
+ - [x] table.concat()
\ No newline at end of file
diff --git a/Nginx/nginx-basic.md b/Nginx/nginx-basic.md
new file mode 100644
index 0000000..03e2433
--- /dev/null
+++ b/Nginx/nginx-basic.md
@@ -0,0 +1,35 @@
+
+## Nginx 基础知识
+---
++ [NGINX 所有 Modules](https://www.nginx.com/resources/wiki/modules/)
++ [Nginx 配置文件 nginx.conf 详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-base-config.md)
+#### agentzh的Nginx教程(版本2016.07.21)
++ [agentzh的Nginx教程地址](https://openresty.org/download/agentzh-nginx-tutorials-zhcn.html)
++ Nginx 变量漫谈(一)
+ + Nginx 变量的值只有一种类型,那就是字符串
+ + Nginx “变量插值”
+ ```bash
+ location /test {
+ set $first "hello ";
+ echo "${first}world";
+ }
+ ```
+ + set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时
+ + Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块
+ + Nginx 变量的生命期是不可能跨越请求边界的
++ Nginx 变量漫谈(二)
+ + 跳转
+ + 内部跳转:就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。
+ + 外部跳转: HTTP 状态码 301 和 302 所进行的“外部跳转”
+ + 标准 ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”
+ + Nginx 核心和各个 Nginx 模块提供的“预定义变量”
+ + Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式
+ + 如果你尝试改写另外一些只读的内建变量,比如 $arg_XXX 变量,在某些 Nginx 的版本中甚至可能导致进程崩溃。
++ Nginx 变量漫谈(四)
+ + map 指令:用于定义两个 Nginx 变量之间的映射关系,或者说是函数关系
+ + map 指令只能在 http 块中使用
+ + map 配置指令的工作原理是为用户变量注册 “取处理程序”,并且实际的映射计算是在“取处理程序”中完成的,而“取处理程序”只有在该用户变量被实际读取时才会执行(当然,因为缓存的存在,只在请求生命期中的第一次读取中才被执行),所以对于那些根本没有用到相关变量的请求来说,就根本不会执行任何的无用计算。
++ Nginx 变量漫谈(四)
++ [Nginx的11个Phases](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-phases.md)
++ [Nginx 陷阱和常见错误](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-1-config.md)
++ [Nginx 高并发系统内核优化](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-parameter-config.md)
\ No newline at end of file
diff --git a/Nginx/nginx-high-basic.md b/Nginx/nginx-high-basic.md
new file mode 100644
index 0000000..f5a65ca
--- /dev/null
+++ b/Nginx/nginx-high-basic.md
@@ -0,0 +1,277 @@
+## Nginx高性能WEB服务器详解
+#### 第一章 初探
++ [Nginx 编译安装以及参数详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-2-config.md)
++ NGINX变量详解
+ - [x] [nginx变量使用方法详解笔记(1)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/notes-1.md)
+ - [x] [nginx变量使用方法详解笔记(2)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/notes-2.md)
+ - [x] [nginx变量使用方法详解笔记(3)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-2-config.md)
++ Nginx指令执行顺序
+ - [x] [Nginx指令执行命令(01)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/command-order-01.md)
+#### 第二章 安装部署
++ 启动错误:`Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)`,执行:`sudo fuser -k 80/tcp`
++ [基于域名、IP的虚拟主机配置](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-all-config.md)
++ [完整、标准配置实际示列](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-basic-config.md)
++ [日志文件配置与切割](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-log-cut.md)
++ alias 和 root 在location 下的应用
+ - 通过alias 实现别名功能
+ ```
+ location /live {
+ alias /home/tinywan/HLS/;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS$ cat index.html
+ alias /home/tinywan/HLS/index.html
+ tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/index.html
+ alias /home/tinywan/HLS/index.html
+ ```
+ - 结论:
+ 1. cul 请求 `/live/index.html`,那么Nginx将会在服务器上查找`/home/tinywan/HLS/index.html` 文件
+ 1. 请求的`url` 中的`location`后面的部分会被追加到`alias `指定的目录后面,而`location`后面的`/live`路径将会别自动抛弃
+ - 类似案例[2]:
+ - config配置信息
+ ```
+ location ~ ^/live/(.*)$ {
+ alias /home/tinywan/HLS/$1;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS$ pwd
+ /home/tinywan/HLS
+ tinywan@tinywan:~/HLS$ cat txt.txt
+ txt file
+ tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
+ txt file
+ ```
+ - 如果url请求`/live/txt.txt`那么Nginx将会在服务器上查找`/home/tinywan/HLS/txt.txt` 文件
+ - **与root 功能的差别**:
+ - config配置信息,注意:一下的`alias` 换成 `root `
+ ```
+ location ~ ^/live/(.*)$ {
+ root /home/tinywan/HLS/$1;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
+
+
404 Not Found
+
+ 404 Not Found
+
openresty/1.11.2.1
+
+
+ ```
+ - 日志文件信息(打开Nginx的rewrite日志:rewrite_log on;):
+ ```
+ /home/tinywan/HLS/txt.txt/live/txt.txt
+ ```
+ - **二者的区别**
+ 1. `alias` 指定的目录是当前目录
+ 1. `root` 指定的是根目录
+ 1. 一般建议的`location /`中通过`root`命令配置目录,其他目录匹配的位置使用`alias`命令
+ - 案例[3]:
+ - config配置信息
+ ```
+ location ~ ^/live/(\w+)/(.*) {
+ alias /home/tinywan/HLS/live/$1/$2;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS/live/stream123$ pwd
+ /home/tinywan/HLS/live/stream123
+ tinywan@tinywan:~/HLS/live/stream123$ cat index.m3u8
+ 12312312312
+ tinywan@tinywan:~/HLS/live/stream123$ curl "http://127.0.0.1/live/stream123/index.m3u8?token=1234&api=009132"
+ 12312312312
+ ```
+#### 第三章 架构初探
+- [ ] 测试一
+#### 第四章 高级配置
++ 基本语法:location [=|~|~*|^~] /uri/ { … }
+ 1. `= `:严格匹配。如果这个查询匹配,那么将停止搜索并立即处理此请求。
+ 2. `~ `:为区分大小写匹配(可用正则表达式)
+ 3. `!~ `:为区分大小写不匹配
+ 4. `!~*`:为不区分大小写不匹配
+ 5. ` ^~ `:如果把这个前缀用于一个常规字符串,那么告诉nginx 如果路径匹配那么不测试正则表达式
++ [Perl 正则表达式参考](http://www.runoob.com/perl/perl-regular-expressions.html)
++ 正则中需要转义的特殊字符小结
+ - [1] ` $` 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n' 或 ‘\r'。要匹配 $ 字符本身,请使用 \$。
+ - [2] ` ( )` 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 和。
+ - [3] ` * ` 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+ - [4] ` +` 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
+ - [5] ` . ` 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
+ - [6] ` [ ]` 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
+ - [7] ` ? ` 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
+ - [8] ` \ ` 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n' 匹配字符 ‘n'。'\n' 匹配换行符。序列 ‘\\' 匹配 “\”,而 ‘\(' 则匹配 “(”。
+ - [9] ` ^ ` 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
+ - [10] ` { }` 标记限定符表达式的开始。要匹配 {,请使用 \{。
+ - [11] ` | ` 指明两项之间的一个选择。要匹配 |,请使用 \|。
+
++ 正则表达式 (Regular expression) 匹配location
+ - [1] `location ~* \.(gif|jpg|jpeg)$ { }`:匹配所有以 gif,jpg或jpeg 结尾的请求
+ - [2] `location ~ /documents/Abc { }`:匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
+ - [3] **目录匹配:**
+ 1. 可以匹配静态文件目录`(static/lib)`
+ 2. HLS直播目录`(/home/HLS/stream123/index.m3u8)`
+ 3. HLS/MP4/FLV点播视频目录`(/home/HLS/stream123.m3u8)`
+ 4. 匹配URL地址:`http://127.0.0.1/live/stream123/index.m3u8`
+ 5. nginx.conf 配置信息
+ ```
+ # 匹配任何以/live/ 开头的任何查询并且停止搜索。任何正则表达式将不会被测试
+ location ^~ /live/ {
+ root /home/tinywan/HLS/;
+ }
+ # 以上匹配成功后的组合:/home/tinywan/HLS/live/....
+ ```
++ 后缀匹配
+ 1. 匹配任何后缀文件名`gif|jpg|jpeg|png|css|js|ico|m3u8|ts` 结尾的请求
+ 2. TS 文件匹配`http://127.0.0.1/live/stream123/11.ts`
+ 3. M3U8 文件匹配`http://127.0.0.1/live/stream123/index.m3u8`
+ 4. 匹配URL地址:`http://127.0.0.1/hls/123.m3u8`
+ 5. nginx.conf 配置信息
+ ```
+ location ~* \.(gif|jpg|jpeg|png|css|js|ico|m3u8|ts)$ {
+ root /home/tinywan/HLS/;
+ }
+ ```
++ HSL直播目录匹配实际案例(请测试上线)
+ 1. 可以后缀文件名:`http://127.0.0.1/live/stream123/index.m3u8`
+ ```
+ location ^~ /live/ {
+ root /home/tinywan/HLS/;
+ }
+ ```
+
++ [nginx配置location总结及rewrite规则写法](http://seanlook.com/2015/05/17/nginx-location-rewrite/)
+#### 第五章 Gzip压缩
++ 测试一
+#### 第六章 Rewrite 功能
++ Rewrite 常用全局变量
+ + 请求案例: `curl -G -d "name=Tinywan&age=24" http://127.0.0.1/rewrite_var/1192/index.m3u8`
+ + 接受结果:
+
+ | 变量 | 值 |描述 |
+ | --------- | ----------- |----------- |
+ | $args | name=Tinywan&age=24 |存放URL 请求的指令 |
+ | $content_length | 0 | 请求头中的Content-length字段|
+ | $content_type | 0 |请求头中的Content-Type字段 |
+ | $document_root | /opt/openresty/nginx/html | 当前请求在root指令中指定的值 |
+ | $document_uri | /rewrite_var/1192/index.m3u8 | 与$uri相同 |
+ | $host | 127.0.0.1 |请求主机头字段,否则为服务器名称 |
+ | $http_user_agent | curl/7.47.0 | 客户端agent信息|
+ | $http_cookie | 0 | COOKIE变量的值|
+ | $limit_rate | 0 | 限制连接速率|
+ | $request_body_file | null | 客户端请求主体信息的临时文件名|
+ | $request_method | GET | 客户端请求的动作,通常为GET或POST |
+ | $remote_addr | 127.0.0.1 |客户端的IP地址 |
+ | $remote_port | 33516 |客户端端口|
+ | $remote_user | 0 | 已经经过Auth Basic Module验证的用户名|
+ | $request_filename | /opt/openresty/nginx/html/rewrite_var/1192/index.m3u8 |当前请求的文件路径 |
+ | $request_uri | /rewrite_var/1192/index.m3u8?name=Tinywan&age=24 |包含请求参数的原始URI,不包含主机名 |
+ | $query_string | name=Tinywan&age=24 | 与$args相同|
+ | $scheme | http |HTTP方法(如http,https |
+ | $server_protocol | HTTP/1.1 |请求使用的协议,通常是HTTP/1.0或HTTP/1.1 |
+ | $server_addr | 127.0.0.1 |服务器地址 |
+ | $server_name | localhost | 服务器名称|
+ | $server_port | 80 |请求到达服务器的端口号 |
+ | $uri | /rewrite_var/1192/index.m3u8 | 不带请求参数的当前URI|
+ | $binary_remote_addr | 乱码 | 二进制格式的客户端地址|
+
+ + uri 介绍 **(Nginx中的URI是相对的URI)**
+ + URL:`https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
+ + 绝对URI:`https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
+ + 相对URI:`/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
+ 
+
++ Rewrite 正则匹配` uri `参数接收
+ 1. 请求案例:`curl http://192.168.18.143/live/tinywan123/index.m3u8`
+ 2. Nginx.conf配置文件
+ ```Lua
+ location ~* ^/live/(\w+)/(\D+)\.(m3u8|ts)$ {
+ set $num $2;
+ set $arg1 $1;
+ echo "args === ${arg1}";
+ echo "1==$1 2==$2 3==$3";
+ echo "Total_numbser :: $num";
+ echo "URI $uri";
+ }
+
+ ```
+ 3. 输出结果
+ ```
+ args === tinywan123
+ $1==tinywan123 $2==index $3==m3u8
+ Total_numbser :: index
+ URI /live/tinywan123/index.m3u8
+ Total_numbser ::
+ ```
+ 4. $1为正则匹配多个英文字母或数字的字符串 `(\w+)`
+ $2 为正则匹配多个非数字 `(\D+)`
+ $3 为正则匹配的第一个值 `(m3u8|ts)`
+ `.` 需要用转义字符转义`\.`
+## 第七章 代理服务
++ [正向代理和反向代理的概念](#title)
++ [正向代理服务](#title)
++ [反向代理的服务](#title)
++ [Nginx日志服务](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-Log.md)
++ 负载均衡
++ HTTP负载均衡
+ - [x] [简单的负载平衡](http://nginx.org/en/docs/http/ngx_http_core_module.html?&_ga=1.179030369.49817296.1480411319#http)
+ - [x] [简单的负载平衡](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-7-Proxy-1.md)
+ - [x] [负载均衡五个配置实例](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-7-Proxy.md)
+ - [x] [Openresty-Lua动态修改upstream后端服务](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/openresty-nginx-lua-Proxy.md)
++ TCP负载均衡
+ - [x] [Module ngx_stream_core_module](http://nginx.org/en/docs/stream/ngx_stream_core_module.html#stream)
+ - [x] [负载均衡](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-8-tcp-Proxy.md)
++ proxy_pass 代理的URL总结
+ + 在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。
+ + 将url中以/wap/开头的请求转发到后台对应的某台server上,注意最后的?$args,表明把原始url最后的get参数也给代理到后台
+ ```bash
+ location ~* /wap/(\d+)/(.+)
+ {
+ proxy_pass http://mx$1.test.com:6601/$2?$args;
+ }
+ ```
+ + 第一种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/index.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000/;
+ }
+ ```
+ + 第二种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/proxy/index.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000;
+ }
+ ```
+ + 第三种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/video/index.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000/video/;
+ }
+ ```
+ + 第四种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/videoindex.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000/video;
+ }
+ ```
++ location 直接访问:
+ + 以下配置,当访问:`http://127.0.0.1:8000/proxy/index.html` 会被匹配到:`/usr/local/nginx/html/proxy/index.html`
+ ```bash
+ location /proxy/ {
+ root /usr/local/nginx/html;
+ index index.html index.htm;
+ }
+ ```
+
+## 第八章 缓存机制
++ 测试一
+## 第九章 Nginx初探1
++ 测试一
+## 第十章 Nginx初探1
++ 测试一
\ No newline at end of file
diff --git a/Openresty/lua-resty-upstream-healthcheck.md b/Openresty/lua-resty-upstream-healthcheck.md
new file mode 100644
index 0000000..9259818
--- /dev/null
+++ b/Openresty/lua-resty-upstream-healthcheck.md
@@ -0,0 +1,154 @@
+#### lua-resty-upstream-healthcheck使用
++ health.txt 在每个upstream 服务器组的root 目录下创建这个文件,目录结构如下所示
+ ```javascript
+ ├── html
+ │ ├── 50x.html
+ │ ├── index.html
+ │ ├── websocket001.html
+ │ └── websocket02.html
+ ├── html81
+ │ ├── 50x.html
+ │ ├── health.txt
+ │ └── index.html
+ ├── html82
+ │ ├── 50x.html
+ │ ├── health.txt
+ │ └── index.html
+ ├── html83
+ │ ├── 50x.html
+ │ ├── health.txt
+ │ └── index.html
+ ├── html84
+ │ ├── 50x.html
+ │ └── index.html
+ ```
++ nginx.conf
+ ```Lua
+ worker_processes 8;
+
+ error_log logs/error.log;
+ pid logs/nginx.pid;
+
+ events {
+ use epoll;
+ worker_connections 1024;
+ }
+
+ http {
+ include mime.types;
+ default_type text/html;
+ #lua模块路径,其中”;;”表示默认搜索路径,默认到/usr/servers/nginx下找
+ lua_package_path "/home/tinywan/Openresty_Protect/First_Protect/lualib/?.lua;;"; #lua 模块
+ lua_package_cpath "/home/tinywan/Openresty_Protect/First_Protect/lualib/?.so;;"; #c模块
+ include /home/tinywan/Openresty_Protect/First_Protect/nginx_first.conf;
+ }
+
+ ```
++ nginx_first.conf
+ ```Lua
+ upstream tomcat {
+ server 127.0.0.1:8081;
+ server 127.0.0.1:8082;
+ server 127.0.0.1:8083;
+ server 127.0.0.1:8084 backup;
+ }
+
+ lua_shared_dict healthcheck 1m;
+
+ lua_socket_log_errors off;
+
+ init_worker_by_lua_block {
+ local hc = require "resty.upstream.healthcheck"
+ local ok, err = hc.spawn_checker{
+ shm = "healthcheck", -- defined by "lua_shared_dict"
+ upstream = "tomcat", -- defined by "upstream"
+ type = "http",
+
+ http_req = "GET /health.txt HTTP/1.0\r\nHost: tomcat\r\n\r\n",
+ -- raw HTTP request for checking
+
+ interval = 2000, -- run the check cycle every 2 sec
+ timeout = 1000, -- 1 sec is the timeout for network operations
+ fall = 3, -- # of successive failures before turning a peer down
+ rise = 2, -- # of successive successes before turning a peer up
+ valid_statuses = {200, 302}, -- a list valid HTTP status code
+ concurrency = 10, -- concurrency level for test requests
+ }
+ }
+
+ server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ proxy_pass http://tomcat;
+ }
+
+ location /server/status {
+ access_log off;
+ allow 127.0.0.1;
+
+ default_type text/plain;
+ content_by_lua_block {
+ local hc = require "resty.upstream.healthcheck"
+ ngx.say("Nginx Worker PID: ", ngx.worker.pid())
+ ngx.print(hc.status_page())
+ }
+ }
+ }
+
+ server {
+ listen 8081;
+ server_name localhost;
+
+ location / {
+ root html81;
+ index index.html index.htm;
+ }
+
+ location /health_status {
+
+ }
+ }
+
+ server {
+ listen 8082;
+ server_name localhost;
+
+ location / {
+ root html82;
+ index index.html index.htm;
+ }
+
+ location /health_status {
+
+ }
+ }
+
+ server {
+ listen 8083;
+ server_name localhost;
+
+ location / {
+ root html83;
+ index index.html index.htm;
+ }
+
+ location /health_status {
+
+ }
+ }
+
+ server {
+ listen 8084;
+ server_name localhost;
+
+ location / {
+ root html84;
+ index index.html index.htm;
+ }
+ }
+
+ ```
++ 状态查看,通过访问:`http://127.0.0.1/server/status`
+ 
\ No newline at end of file
diff --git a/Openresty/openresty-api.md b/Openresty/openresty-api.md
new file mode 100644
index 0000000..1acc5bc
--- /dev/null
+++ b/Openresty/openresty-api.md
@@ -0,0 +1,217 @@
+#### ngx Lua APi 方法和常量
++ ngx_lua 核心常量
+ ```lua
+ ngx.OK (0)
+ ngx.ERROR (-1)
+ ngx.AGAIN (-2)
+ ngx.DONE (-4)
+ ngx.DECLINED (-5)
+ ngx.nil
+ -- 指令常量
+ ngx.arg[index] #ngx指令参数,当这个变量在set_by_lua或者set_by_lua_file内使用的时候是只读的,指的是在配置指令输入的参数.
+ ngx.var.varname #读写NGINX变量的值,最好在lua脚本里缓存变量值,避免在当前请求的生命周期内内存的泄漏
+ ngx.config.ngx_lua_version #当前ngx_lua模块版本号
+ ngx.config.nginx_version #nginx版本
+ ngx.worker.exiting #当前worker进程是否正在关闭
+ ngx.worker.pid #当前worker进程的PID
+ ngx.config.nginx_configure #编译时的./configure命令选项
+ ngx.config.prefix #编译时的prefix选项
+ ```
++ ngx_lua 方法 (#经常在ngx.location.catpure和ngx.location.capture_multi方法中被调用.)
+ ```lua
+ ngx.HTTP_GET
+ ngx.HTTP_HEAD
+ ngx.HTTP_PUT
+ ngx.HTTP_POST
+ ngx.HTTP_DELETE
+ ngx.HTTP_OPTIONS
+ ngx.HTTP_MKCOL
+ ngx.HTTP_COPY
+ ngx.HTTP_MOVE
+ ngx.HTTP_PROPFIND
+ ngx.HTTP_PROPPATCH
+ ngx.HTTP_LOCK
+ ngx.HTTP_UNLOCK
+ ngx.HTTP_PATCH
+ ngx.HTTP_TRACE
+ ```
++ 错误日志级别常量
+ ```lua
+ ngx.STDERR
+ ngx.EMERG
+ ngx.ALERT
+ ngx.CRIT
+ ngx.ERR
+ ngx.WARN
+ ngx.NOTICE
+ ngx.INFO
+ ngx.DEBUG
+ ```
++ API中的常用方法
+ ```lua
+ print() #与 ngx.print()方法有区别,print() 相当于ngx.log()
+ ngx.ctx #这是一个lua的table,用于保存ngx上下文的变量,在整个请求的生命周期内都有效,详细参考官方
+ ngx.location.capture() #发出一个子请求,详细用法参考官方文档。
+ ngx.location.capture_multi() #发出多个子请求,详细用法参考官方文档。
+ ngx.status #读或者写当前请求的相应状态. 必须在输出相应头之前被调用.
+ ngx.header.HEADER #访问或设置http header头信息,详细参考官方文档。
+ ngx.req.set_uri() #设置当前请求的URI,详细参考官方文档
+ ngx.set_uri_args(args) #根据args参数重新定义当前请求的URI参数.
+ ngx.req.get_uri_args() #返回一个LUA TABLE,包含当前请求的全部的URL参数
+ ngx.req.get_post_args() #返回一个LUA TABLE,包括所有当前请求的POST参数
+ ngx.req.get_headers() #返回一个包含当前请求头信息的lua table.
+ ngx.req.set_header() #设置当前请求头header某字段值.当前请求的子请求不会受到影响.
+ ngx.req.read_body() #在不阻塞ngnix其他事件的情况下同步读取客户端的body信息.[详细]
+ ngx.req.discard_body() #明确丢弃客户端请求的body
+ ngx.req.get_body_data() #以字符串的形式获得客户端的请求body内容
+ ngx.req.get_body_file() #当发送文件请求的时候,获得文件的名字
+ ngx.req.set_body_data() #设置客户端请求的BODY
+ ngx.req.set_body_file() #通过filename来指定当前请求的file data。
+ ngx.req.clear_header() #清求某个请求头
+ ngx.exec(uri,args) #执行内部跳转,根据uri和请求参数
+ ngx.redirect(uri, status) #执行301或者302的重定向。
+ ngx.send_headers() #发送指定的响应头
+ ngx.headers_sent #判断头部是否发送给客户端ngx.headers_sent=true
+ ngx.print(str) #发送给客户端的响应页面
+ ngx.say() #作用类似ngx.print,不过say方法输出后会换行
+ ngx.log(log.level,...) #写入nginx日志
+ ngx.flush() #将缓冲区内容输出到页面(刷新响应)
+ ngx.exit(http-status) #结束请求并输出状态码
+ ngx.eof() #明确指定关闭结束输出流
+ ngx.escape_uri() #URI编码(本函数对逗号,不编码,而php的urlencode会编码)
+ ngx.unescape_uri() #uri解码
+ ngx.encode_args(table) #将tabel解析成url参数
+ ngx.decode_args(uri) #将参数字符串编码为一个table
+ ngx.encode_base64(str) #BASE64编码
+ ngx.decode_base64(str) #BASE64解码
+ ngx.crc32_short(str) #字符串的crs32_short哈希
+ ngx.crc32_long(str) #字符串的crs32_long哈希
+ ngx.hmac_sha1(str) #字符串的hmac_sha1哈希
+ ngx.md5(str) #返回16进制MD5
+ ngx.md5_bin(str) #返回2进制MD5
+ ngx.today() #返回当前日期yyyy-mm-dd
+ ngx.time() #返回当前时间戳
+ ngx.now() #返回当前时间
+ ngx.update_time() #刷新后返回
+ ngx.localtime() #返回 yyyy-mm-dd hh:ii:ss
+ ngx.utctime() #返回yyyy-mm-dd hh:ii:ss格式的utc时间
+ ngx.cookie_time(sec) #返回用于COOKIE使用的时间
+ ngx.http_time(sec) #返回可用于http header使用的时间
+ ngx.parse_http_time(str) #解析HTTP头的时间
+ ngx.is_subrequest #是否子请求(值为 true or false)
+ ngx.re.match(subject,regex,options,ctx) #ngx正则表达式匹配,详细参考官网
+ ngx.re.gmatch(subject,regex,opt) #全局正则匹配
+ ngx.re.sub(sub,reg,opt) #匹配和替换(未知)
+ ngx.re.gsub() #未知
+ ngx.shared.DICT #ngx.shared.DICT是一个table 里面存储了所有的全局内存共享变量
+ ngx.shared.DICT.get
+ ngx.shared.DICT.get_stale
+ ngx.shared.DICT.set
+ ngx.shared.DICT.safe_set
+ ngx.shared.DICT.add
+ ngx.shared.DICT.safe_add
+ ngx.shared.DICT.replace
+ ngx.shared.DICT.delete
+ ngx.shared.DICT.incr
+ ngx.shared.DICT.flush_all
+ ngx.shared.DICT.flush_expired
+ ngx.shared.DICT.get_keys
+ ndk.set_var.DIRECTIVE
+ ```
++ Lua HTTP状态常量
+ ```Lua
+ value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)
+ value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)
+ value = ngx.HTTP_OK (200)
+ value = ngx.HTTP_CREATED (201)
+ value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)
+ value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)
+ value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)
+ value = ngx.HTTP_SPECIAL_RESPONSE (300)
+ value = ngx.HTTP_MOVED_PERMANENTLY (301)
+ value = ngx.HTTP_MOVED_TEMPORARILY (302)
+ value = ngx.HTTP_SEE_OTHER (303)
+ value = ngx.HTTP_NOT_MODIFIED (304)
+ value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)
+ value = ngx.HTTP_BAD_REQUEST (400)
+ value = ngx.HTTP_UNAUTHORIZED (401)
+ value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)
+ value = ngx.HTTP_FORBIDDEN (403)
+ value = ngx.HTTP_NOT_FOUND (404)
+ value = ngx.HTTP_NOT_ALLOWED (405)
+ value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)
+ value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)
+ value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)
+ value = ngx.HTTP_GONE (410)
+ value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)
+ value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)
+ value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)
+ value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)
+ value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
+ value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
+ value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)
+ value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
+ value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)
+ value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)
+ value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)
+ ```
++ 案列使用,get_string_md5.lua:
+ ```Lua
+ local args = ngx.req.get_uri_args()
+ local salt = args.salt
+ if not salt then
+ ngx.say(ngx.HTTP_BAD_REQUEST)
+ end
+ local string = ngx.md5(ngx.time()..salt)
+ ngx.say(string)
+
+ ```
++ curl 请求(-i 参数,输出时包括protocol头信息):
+ ```Bash
+ tinywan@tinywan:$ curl -i http://127.0.0.1/get_rand_string?salt=tinywan123
+ HTTP/1.1 200 OK
+ Server: openresty/1.11.2.1
+ Date: Fri, 21 Apr 2017 14:27:16 GMT
+ Content-Type: application/octet-stream
+ Transfer-Encoding: chunked
+ Connection: keep-alive
+ ```
+#### ngx Lua APi 介绍使用
++ 强烈建议使用ngx Lua APi 接口`(非阻塞的)`,而不是Lua自身的API`(阻塞的)`,Lua 自身API会阻塞掉的
++ ngx_lua_api_test.lua
+ ```Lua
+ local json = require "cjson" -- 引入cjson 扩展
+
+ -- 同步读取客户端请求正文,而不会阻止Nginx事件循环
+ ngx.req.read_body()
+ local args = ngx.req.get_post_args()
+
+ if not args or not args.info then
+ ngx.say(ngx.HTTP_BAD_REQUEST) -- ngx.HTTP_BAD_REQUEST (400)
+ end
+
+ local client_id = ngx.var.remote_addr
+ local user_agent = ngx.req.get_headers()['user-agent'] or ""
+ local info = ngx.decode_base64(args.info)
+
+ local response = {}
+ response.info = info
+ response.client_id = client_id
+ response.user_agent = user_agent
+
+ ngx.say(json.encode(response))
+
+ ```
++ CURL Post 请求
+ ```Lua
+ $ curl -i --data "info=b3ZlcmNvbWUud2FuQGdtYWlsLmNvbQ==" http://127.0.0.1/ngx_lua_api_test
+ HTTP/1.1 200 OK
+ Server: openresty/1.11.2.1
+ Date: Sat, 22 Apr 2017 01:22:07 GMT
+ Content-Type: application/octet-stream
+ Transfer-Encoding: chunked
+ Connection: keep-alive
+
+ {"user_agent":"curl\/7.47.0","info":"overcome.wan@gmail.com","client_id":"127.0.0.1"}
+
+ ```
\ No newline at end of file
diff --git a/Openresty/openresty-basic.md b/Openresty/openresty-basic.md
new file mode 100644
index 0000000..51d234d
--- /dev/null
+++ b/Openresty/openresty-basic.md
@@ -0,0 +1,62 @@
++ [安装信息](http://www.cnblogs.com/tinywan/p/6647587.html)
++ [默认配置信息](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/default-config.md)
++ 开发入门
+ + Nginx与Lua的整体目录关系
+ ```javascript
+ .
+ ├── conf
+ │ ├── nginx.conf -- Nginx 配置文件
+ ├── logs
+ │ ├── error.log -- Nginx 错误日子
+ │ └── nginx.pid
+ ├── lua
+ │ ├── m3u8_redis_access.lua -- M3U8地址权限验证文件
+ │ ├── business_redis.lua -- 业务 Redis 处理文件
+ │ ├── http-lua-test.lua -- http lua demo
+ │ ├── ...
+ │ └── resty -- 存放Lua 的所有公共、封装好的库目录
+ │ └── redis_iresty.lua -- Redis 接口的二次封装
+ │ └── param.lua -- 参数过滤库
+ └── sbin
+ └── nginx
+ ```
+ + 参数总结
+ + Lua脚本接受Nginx变量:
+ > [1] 间接获取:`var = ngx.var `,如接受Nginx的变量` $a = 9`,则`lua_a = ngx.var.a --lua_a = 9`
+ [2] 直接获取:`var = ngx.var `,如接受Nginx的location的第二个变量890,` http://127.0.0.1/lua_request/123/890 `,则`lua_2 = ngx.var[2] --lua_2 = 890`
+ + Lua 脚本接受 Nginx 头部 header:
+ > [1] 返回一个包含所有当前请求标头的Lua表:`local headers = ngx.req.get_headers()`
+ [2] 获取单个Host:`headers["Host"] 或者 ngx.req.get_headers()["Host"] `
+ [3] 获取单个user-agent:
+ >> [01]`headers["user-agent"]`
+ [02]`headers.user_agent `
+ [03]`ngx.req.get_headers()['user-agent'] `
+ + Lua 脚本 Get 获取请求uri参数
+ > linux curl Get方式提交数据语法:`curl -G -d "name=value&name2=value2" https://github.com/Tinywan `
+ 返回一个包含所有当前请求URL查询参数的Lua表:`local get_args = ngx.req.get_uri_args()`
+ 请求案例:`curl -G -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789`
+ Lua Get 方式获取提交的name参数的值:`get_args['name'] 或者 ngx.req.get_uri_args()['name']`
+ >> [01]`get_args['name']`
+ [02]`ngx.req.get_uri_args()['name']`
+ + Lua 脚本 Post 获取请求uri参数
+ > linux curl Post方式提交数据语法:
+ >> [01] `curl -d "name=value&name2=value2" https://github.com/Tinywan `
+ [02] `curl -d a=b&c=d&txt@/tmp/txt https://github.com/Tinywan `
+ > 返回一个包含所有当前请求URL查询参数的Lua表:`local post_args = ngx.req.get_post_args()`
+ 请求案例:`curl -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789`
+ Lua Post 方式获取提交的name参数的值:
+ >> [01]`post_args['name']`
+ [02]`ngx.req.get_post_args()['name']`
+ + Lua 脚本请求的http协议版本:`ngx.req.http_version()`
+ + Lua 脚本请求方法:`ngx.req.get_method()`
+ + Lua 脚本原始的请求头内容:`ngx.req.raw_header()`
+ + Lua 脚本请求的body内容体:`ngx.req.get_body_data()`
+ + [接收请求:获取如请求参数、请求头、Body体等信息]()
+ + [接收请求:输出响应需要进行响应状态码、响应头和响应内容体的输出](
++ luajit 执行文件默认安装路径:`/opt/openresty/luajit/bin/luajit`,这样我们直接可以这样运行一个Lua文件:`luajit test.lua `
+ + luajit 运行测试案例:
+ ```Bash
+ tinywan@tinywan:~/Lua$ luajit test.lua
+ The man name is Tinywan
+ The man name is Phalcon
+ ```
\ No newline at end of file
diff --git a/Openresty/openresty-resty-module.md b/Openresty/openresty-resty-module.md
new file mode 100644
index 0000000..2bd82a4
--- /dev/null
+++ b/Openresty/openresty-resty-module.md
@@ -0,0 +1,253 @@
++ [Lua require 绝对和相对路径(已经解决)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-common-package/lua-require.md)
++ [luajit 执行文件默认安装路径](#Openresty_web_knowledge)
++ [lua-resty-redis 扩展](#Openresty_resty-redis)
++ [lua-resty-websocket 扩展](#Openresty_resty-websocket)
++ [lua-cjson 扩展](#Openresty_resty-cjson)
++ [lua-dkjson 扩展](https://github.com/Tinywan/lua_project_v0.01)
++ [Lua 权限验证](#Openresty_resty-access)
++ [lua-resty-string 扩展](#Openresty_resty-string)
++ [lua-resty-http 扩展 ](#Openresty_resty-http)
++ [lua-resty-mysql 扩展](#Openresty_resty-mysql)
++ [lua-resty-shell 扩展](http://www.cnblogs.com/tinywan/p/6809879.html)
++ [lua-resty-template 扩展](https://github.com/Tinywan/lua_project_v0.01)
++ [lua-resty-template 扩展](https://github.com/Tinywan/lua_project_v0.01)
++ [openresty扫描代码全局变量](#Openresty_all-var)
++ [ngx Lua APi 方法和常量](#Openresty_http_status_constants)
+ + ngx_lua 核心常量
+ + ngx_lua 方法
+ + Lua HTTP状态常量
+ + 错误日志级别常量
+ + API中的常用方法
++ [ngx Lua APi 介绍使用](#Openresty_ngx_api_used)
++ [连接数据库](#Openresty_connent_redis)
++ [OpenResty缓存](#Openresty_connent_cache)
++ [lua-resty-upstream-healthcheck 使用](#Openresty_lua_resty_upstream_healthcheck)
++ [Openresty和Nginx_RTMP 模块共存问题](#Openresty_rtmp_share)
++ [Openresty配置RTMP模块的多worker直播流](#Openresty_rtmp_more_worker)
++ [Openresty配置RTMP模块的推流地址鉴权实例](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Openresty_rtmp_obs_push.md)
++ [Ngx_lua 写入Redis数据,通过CURL请求](#Ngx_lua_write_Redis)
++ [Nginx编写的Lua接口使用URL过期和签名验证机制过滤非法访问接口](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Openresty_rtmp_obs_push_auth.md)
++ [Nginx查看并发连接数](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/nginx_status.md)
+#### lua-resty-redis 扩展 (是openresty下操作redis的模块)
++ 代码引入:`lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/?.lua;;";`
++ Lua脚本实现一个CDN的反向代理功能(智能查找CDN节点)(测试成功,可上线)
+ + nginx.conf 配置信息
+ ```Lua
+ http {
+ lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/?.lua;;";
+ server {
+ listen 80;
+ server_name localhost;
+ location ~ \/.+\/.+\.(m3u8|ts) {
+ if ($uri ~ \/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)(|-).*\.(m3u8|ts)) {
+ set $app_name $1;
+ set $a $2;
+ }
+ set $stream_id "";
+ default_type 'text/html';
+ rewrite_by_lua_file /opt/openresty/nginx/lua/proxy_pass_cdn.lua;
+ proxy_connect_timeout 10;
+ proxy_send_timeout 30;
+ proxy_read_timeout 30;
+ proxy_pass $stream_id;
+ }
+
+ }
+ }
+ ```
+ + [Lua脚本proxy_pass_cdn.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/proxy_pass_cdn.lua)
+ + [lua-nginx-module 贡献代码](https://github.com/openresty/lua-nginx-module/issues/275)
+
++ Lua脚本结合 Nginx+Lua+Local Redis+Mysql服务器缓存
+ + Nginx+Lua+Local Redis+Mysql集群架构
+ + 
+ + [Lua脚本Nginx+Lua+Redis+Mysql.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+Mysql.lua)
+ + [Nginx.conf配置文件Nginx+Lua+Redis+Mysql.conf](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+Mysql.conf)
+ + [HELP](http://jinnianshilongnian.iteye.com/blog/2188113)
+
+ + Lua脚本结合 Redis 统计直播流播放次数、链接次数等等信息
+ + nginx.conf
+ ```Lua
+ server { # 配置虚拟服务器80
+ listen 80;
+ server_name 127.0.0.1:8088;
+ location ~* /live/(\w+)/ {
+ set $total_numbers "";
+ set $stream_name $1;
+ lua_code_cache off;
+ rewrite_by_lua_file /opt/openresty/nginx/conf/Lua/total_numbers.lua;
+ proxy_pass http://127.0.0.1:8088;
+ }
+ }
+ ```
+ + 代理服务器
+ ```Lua
+ server { # 配置虚拟服务器8088
+ listen 8088;
+ server_name 127.0.0.1:8088;
+ location /live {
+ add_header Cache-Control no-cache;
+ add_header 'Access-Control-Allow-Origin' '*' always;
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+ add_header 'Access-Control-Allow-Headers' 'Range';
+ types{
+ application/dash+xml mpd;
+ application/vnd.apple.mpegurl m3u8;
+ video/mp2t ts;
+ }
+ alias /home/tinywan/HLS/live/;
+ }
+ }
+
+ ```
+ + CURL请求地址:`http://192.168.18.143/live/tinywan123/index.m3u8`
+ + [Lua 脚本](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Hls-Line-Number-Total.lua)
+
+#### lua-resty-websocket 扩展
++ 代码引入:`lua_package_path "/opt/openresty/nginx/lua/lua-resty-websocket/lib/?.lua;;";`
++ **Lua脚本实现一个websocket连接(测试成功,可上线)**
+ + nginx.conf 配置信息
+ ```Lua
+ http {
+ lua_package_path "/opt/openresty/nginx/lua/lua-resty-websocket/lib/?.lua;;";
+ server {
+ listen 80 so_keepalive=2s:2s:8; #为了防止半开TCP连接,最好在Nginx监听配置指令中启用TCP keepalive:
+ server_name localhost;
+ location /ws {
+ lua_socket_log_errors off;
+ lua_check_client_abort on;
+ lua_code_cache off; # 建议测试的时候最好关闭缓存
+ content_by_lua_file /opt/openresty/nginx/conf/Lua/websocket.lua;
+ }
+ }
+ }
+ ```
+ + [WebSockets服务器Lua脚本websocket.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-websocket/websocket.lua)
+ + [websockets.html客户端代码,代码路径:/usr/local/openresty/nginx/html](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-websocket/websocket.html)
+ + 然后打开启用了WebSocket支持的浏览器,然后打开以下url:
+ 
+#### lua-cjson 扩展
++ 基本用法
+ + nginx.conf
+ ```Lua
+ location /cjson {
+ content_by_lua_block {
+ local cjson = require "cjson"
+ local json = cjson.encode({
+ foo = "bar",
+ some_object = {},
+ some_array = cjson.empty_array
+ })
+ ngx.say(json)
+ }
+ }
+ ```
+ + curl 请求
+ ```Bash
+ root@tinywan:/opt/openresty/nginx/conf# curl http://127.0.0.1/cjson
+ {"some_object":{"tel":13669313112,"age":24},"name":"tinywan","some_array":[]}
+ ```
++ [lua对象到字符串、字符串到lua对象](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-cjson/cjson-str-obj.lua)
+#### lua-resty-session 扩展
++ OpenResty 引用第三方 resty 库非常简单,只需要将相应的文件拷贝到 resty 目录下即可
++ 我服务器OpenResty 的 resty 路径:`/opt/openresty/lualib/resty`
++ 下载第三方 resty 库:git clone lua-resty-session 文件路径以及内容:
+ ```Bash
+ tinywan@tinywan:/opt/openresty/nginx/lua/lua-resty-session/lib/resty$ ls
+ session session.lua
+ ```
++ 特别注意:这里拷贝的时候要要把session文件和session.lua 文件同时吧、拷贝过去,否则会报错误:
+ ```Bash
+ /opt/openresty/lualib/resty/session.lua:34: in function 'prequire'
+ /opt/openresty/lualib/resty/session.lua:211: in function 'new'
+ /opt/openresty/lualib/resty/session.lua:257: in function 'open'
+ /opt/openresty/lualib/resty/session.lua:320: in function 'start'
+ ```
++ 拷贝完毕后`/opt/openresty/lualib/resty` OpenResty 引用第三方 resty 的所有库文件
+ ```Bash
+ tinywan@tinywan:/opt/openresty/lualib/resty$ ls
+ aes.lua core.lua http_headers.lua lock.lua lrucache.lua memcached.lua random.lua session sha1.lua sha256.lua sha512.lua string.lua upstream
+ core dns http.lua lrucache md5.lua mysql.lua redis.lua session.lua sha224.lua sha384.lua sha.lua upload.lua websocket
+ ```
++ 基本用法
+ ```Lua
+ location /start {
+ content_by_lua_block {
+ local session = require "resty.session".start()
+ session.data.name = "OpenResty Fan Tinywan"
+ session:save()
+ ngx.say("Session started. ",
+ "Check if it is working!")
+ ngx.say(session.data.name,"Anonymous")
+ }
+ }
+ ```
++ curl 请求
+ ```Bash
+ tinywan@tinywan:/opt/openresty/nginx/conf$ curl http://192.168.18.143/start
+ Session started. Check if it is working!
+ OpenResty Fan Tinywan Anonymous
+ ```
+#### Lua 权限验证
++ Lua 一个HLS的简单地址访问权限验证
+ + Nginx.conf 配置
+ ```Lua
+ location ^~ /live/ {
+ add_header Cache-Control no-cache;
+ add_header 'Access-Control-Allow-Origin' '*' always;
+ add_header 'Access-Control-Allow-Credentials' 'true';
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+ add_header 'Access-Control-Allow-Headers' 'Range';
+
+ types{
+ application/dash+xml mpd;
+ application/vnd.apple.mpegurl m3u8;
+ video/mp2t ts;
+ }
+ if ( $uri ~ \.m3u8 ) {
+ lua_code_cache off;
+ access_by_lua_file /opt/openresty/nginx/lua/access.lua;
+ }
+ root /home/tinywan/HLS;
+ }
+ ```
+ + access.lua 文件内容
+ ```Lua
+ if ngx.req.get_uri_args()["wsSecret"] ~= "e65e6a01cf26523e206d5bb0e2a8a95a" then
+ return ngx.exit(403)
+ end
+ ```
+#### lua-resty-string 扩展
++ MD5加密的简单基本用法 md5.lua
+ ```Lua
+ local resty_md5 = require "resty.md5"
+ local md5 = resty_md5:new()
+ if not md5 then
+ ngx.say("failed to create md5 object")
+ return
+ end
+ local ok = md5:update("hello")
+ if not ok then
+ ngx.say("failed to add data")
+ return
+ end
+ local digest = md5:final()
+ -- ngx.say("md5",digest) ---注意:这样直接输出是乱码
+ local str = require "resty.string"
+ ngx.say("md5: ", str.to_hex(digest)) ---注意:必须通过字符串转码方可打印输出
+ -- yield "md5: 5d41402abc4b2a76b9719d911017c592"
+ ```
+#### lua-resty-http 扩展 (ngx_lua的HTTP客户端cosocket驱动程序)
++ [简单测试:lua-http-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-http/lua-http-test.lua)
+#### lua-resty-mysql 扩展
++ [简单测试:lua-msyql-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-mysql/lua-msyql-test.lua)
+#### srcache-nginx-module 扩展 ([nginx下的一个缓存模块](https://github.com/openresty/srcache-nginx-module))
++ [openresty–redis–srcache缓存的应用](http://www.xtgxiso.com/openresty-redis-srcache-nginx-module%e7%bc%93%e5%ad%98%e7%9a%84%e5%ba%94%e7%94%a8/)
+#### openresty扫描代码全局变量
++ 在OpenResty中需要避免全局变量的使用,为此春哥写了一个perl工具,可以扫描openresty lua代码的全局变量
++ [https://github.com/openresty/openresty-devel-utils/blob/master/lua-releng](https://github.com/openresty/openresty-devel-utils/blob/master/lua-releng)
++ 用法相当简单
+ 1. 将代码保存成lua-releng文件
+ 2. 更改lua-releng的权限,chmod 777 lua-releng
+ 3. 假设有一个源码文件为test.lua
+ 4. 执行./lua-releng test.lua,则会扫描test.lua文件的全局变量,并在屏幕打印结果
\ No newline at end of file
diff --git a/Openresty/openresty-rtmp.md b/Openresty/openresty-rtmp.md
new file mode 100644
index 0000000..bc96331
--- /dev/null
+++ b/Openresty/openresty-rtmp.md
@@ -0,0 +1,37 @@
+#### OpenResty缓存
++ 指令:`lua_shared_dict`
+ + 纯内存的操作,多个worker之间共享的(比如nginx开启10个Worker,则每个worker之间是共享该内存的)
+ + 同一份数据在多个worker之间是共享的,只要存储一份数据就可以了
+ + 锁的竞争(数据原子性)
+
+#### Openresty和Nginx_RTMP 模块共存问题
++ RTMP 流的状态(stat.xsl)不生效Bug 问题
+ - 1. 修改完nginx.conf 配置文件
+ - 1. ~~执行:`nginx -s reload` 会不起作用~~
+ - 2. 一定要执行以下命令:杀掉所有nginx进程`sudo killall nginx ` 重启即可`sbin/nignx`
+#### 配置RTMP模块的多worker直播流
++ 配置文件,[Multi-worker live streaming官方文档](https://github.com/arut/nginx-rtmp-module/wiki/Directives#multi-worker-live-streaming)
+ ```Shell
+ user www www;
+ worker_processes auto;
+ error_log logs/error.log debug;
+
+ pid /var/run/nginx.pid;
+ events {
+ use epoll;
+ worker_connections 1024;
+ multi_accept on;
+ }
+
+ rtmp_auto_push on;
+ rtmp_auto_push_reconnect 1s;
+ rtmp_socket_dir /var/sock;
+ rtmp {
+ server {
+ listen 1935;
+ application live {
+ live on;
+ }
+ }
+ }
+ ```
\ No newline at end of file
diff --git a/README.md b/README.md
index 288d3f5..797a254 100644
--- a/README.md
+++ b/README.md
@@ -1,1586 +1,63 @@
## 目录
-+ [Nginx基础知识](#Nginx_base_knowledge)
-+ [Linux基础知识](#Linux_base_knowledge)
-+ [Redis基础知识](#Redis_base_knowledge)
++ Nginx 教程
+ + [Nginx基础知识](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-basic.md)
+ + [Nginx高性能WEB服务器详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-high-basic.md)
+ + 第一章 初探
+ + 第二章 安装部署
+ + 第三章 架构初探
+ + 第四章 高级配置
+ + 第五章 Gzip压缩
+ + 第六章 Rewrite 功能
+ + 第七章 代理服务
+ + 第八章 缓存机制
+ + [nginx 并发数问题思考](#Nginx_base_knowledge)
++ Lua 教程
+ + [Lua 基础语法](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/lua-basic.md)
+ + [Lua 模块与包](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/openresty-resty-module.md)
+ + [luajit 执行文件默认安装路径](#Nginx_base_knowledge)
+ + [lua中self.__index = self 详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/oop/self__index.md)
++ Redis 教程
+ + [Redis基础知识](#Redis_base_knowledge)
+ [Redis 简易安装教程](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis/redis-install.md)
+ [Redis执行Lua脚本基本用法](#Redis_Run_Lua)
-+ [PHP脚本](#PHP_base_knowledge)
- + [PHP脚本运行Redis](#PHP_Run_Redis)
-+ [Shell脚本](#Shell_base_knowledge)
- - [x] 编写快速安全Bash脚本的建议
- - [x] Shell脚本实现分日志级别记录日志
- - [x] Nginx日志定时备份和删除
- - [x] SHELL脚本小技巧
- - [x] Mysql 自动备份脚本安全加锁机制
-+ [Lua基础知识](#Lua_base_knowledge)
- + [Lua 基础语法](#Lua-base)
- + [luajit 执行文件默认安装路径](#Nginx_base_knowledge)
- + [Table 操作常用的方法](#Lua_table)
- - [x] table.concat()
- - [x] table.insert()
- - [x] table.maxn()
- - [x] table.concat()
- + [Lua 模块与包](#Lua_module_package)
- + [lua中self.__index = self 详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/oop/self__index.md)
+ + [Redis 开发与运维](#Redis-DevOps)
+ - [ ] [第一章 初始Redis ](#Redis-DevOps-1)
+ - [ ] [第二章 API的理解和使用](#Redis-DevOps-2)
+ - [ ] [第三章 小功能大用处 ](#Redis-DevOps-3)
+ - [ ] [第四章 客户端 ](#Redis-DevOps-4)
+ - [ ] [第五章 持久化](#Redis-DevOps-5)
+ - [ ] [第六章 复制](#Redis-DevOps-6)
+ - [ ] [第七章 Redis 的恶魔 ](#Redis-DevOps-7)
+ - [ ] [第八章 理解内存 ](#Redis-DevOps-8)
++ Openresty 教程
+ + [安装默认配置信息](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/openresty-basic.md)
+ + [扩展模块学习](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/openresty-resty-module.md)
+ + [ngx_lua APi 方法和常量](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/openresty-resty-module.md)
+ + [lua-resty-upstream-healthcheck使用](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-upstream-healthcheck.md)
+ + [Openresty与Nginx_RTMP](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/openresty-rtmp.md)
++ PHP 教程
+ + [PHP脚本](#PHP_base_knowledge)
+ + [PHP脚本运行Redis](#PHP_Run_Redis)
+ + [PHP7中php.ini/php-fpm/www.conf的配置,Nginx和PHP-FPM的开机自动启动脚本](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/PHP/PHP-FPM/config.md)
++ Shell 教程
+ + Shell脚本
+ + [编写快速安全Bash脚本的建议](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Shell/write-shell-suggestions.md)
+ + [shell脚本实现分日志级别记录日志](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_Log.sh)
+ + [Nginx日志定时备份和删除](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_Nginx_Log_cut.sh)
+ + [SHELL脚本小技巧](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_script.md)
+ + [Mysql 自动备份脚本安全加锁机制](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/backup_mysql.sh)
+ [流媒体视频直播、点播](#live_base_knowledge)
-+ [Nginx高性能WEB服务器详解](#Nginx_Web_knowledge)
- + [第一章 初探 ](#Nginx_Web1_knowledge)
- + [第二章 安装部署](#Nginx_Web2_knowledge)
- + [第三章 架构初探 ](#Nginx_Web3_knowledge)
- + [第四章 高级配置 ](#Nginx_Web4_knowledge)
- + [第五章 Gzip压缩](#Nginx_Web5_knowledge)
- + [第六章 Rewrite 功能](#Nginx_Web6_knowledge)
- + [第七章 代理服务 ](#Nginx_Web7_knowledge)
- + [第八章 缓存机制 ](#Nginx_Web8_knowledge)
-+ [Openresty 学习](#Openresty_web_knowledge)
- + [安装](#Openresty_install_knowledge)
- + [默认配置信息](#Openresty_config_knowledge)
- + [Lua require 绝对和相对路径(已经解决)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-common-package/lua-require.md)
- + [luajit 执行文件默认安装路径](#Openresty_web_knowledge)
- + [lua-resty-redis 扩展](#Openresty_resty-redis)
- + [lua-resty-websocket 扩展](#Openresty_resty-websocket)
- + [lua-cjson 扩展](#Openresty_resty-cjson)
- + [lua-dkjson 扩展](https://github.com/Tinywan/lua_project_v0.01)
- + [Lua 权限验证](#Openresty_resty-access)
- + [lua-resty-string 扩展](#Openresty_resty-string)
- + [lua-resty-http 扩展 ](#Openresty_resty-http)
- + [lua-resty-mysql 扩展](#Openresty_resty-mysql)
- + [lua-resty-shell 扩展](http://www.cnblogs.com/tinywan/p/6809879.html)
- + [lua-resty-template 扩展](https://github.com/Tinywan/lua_project_v0.01)
- + [lua-resty-template 扩展](https://github.com/Tinywan/lua_project_v0.01)
- + [openresty扫描代码全局变量](#Openresty_all-var)
- + [ngx Lua APi 方法和常量](#Openresty_http_status_constants)
- + ngx_lua 核心常量
- + ngx_lua 方法
- + Lua HTTP状态常量
- + 错误日志级别常量
- + API中的常用方法
- + [ngx Lua APi 介绍使用](#Openresty_ngx_api_used)
- + [连接数据库](#Openresty_connent_redis)
- + [OpenResty缓存](#Openresty_connent_cache)
- + [lua-resty-upstream-healthcheck 使用](#Openresty_lua_resty_upstream_healthcheck)
- + [Openresty和Nginx_RTMP 模块共存问题](#Openresty_rtmp_share)
- + [Openresty配置RTMP模块的多worker直播流](#Openresty_rtmp_more_worker)
- + [Openresty配置RTMP模块的推流地址鉴权实例](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Openresty_rtmp_obs_push.md)
- + [Ngx_lua 写入Redis数据,通过CURL请求](#Ngx_lua_write_Redis)
- + [Nginx编写的Lua接口使用URL过期和签名验证机制过滤非法访问接口](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Openresty_rtmp_obs_push_auth.md)
- + [Nginx查看并发连接数](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/nginx_status.md)
-+ [Redis 开发与运维](#Redis-DevOps)
- - [ ] [第一章 初始Redis ](#Redis-DevOps-1)
- - [ ] [第二章 API的理解和使用](#Redis-DevOps-2)
- - [ ] [第三章 小功能大用处 ](#Redis-DevOps-3)
- - [ ] [第四章 客户端 ](#Redis-DevOps-4)
- - [ ] [第五章 持久化](#Redis-DevOps-5)
- - [ ] [第六章 复制](#Redis-DevOps-6)
- - [ ] [第七章 Redis 的恶魔 ](#Redis-DevOps-7)
- - [ ] [第八章 理解内存 ](#Redis-DevOps-8)
+ [Copyright and License](#Copyright_and_License)
## 开发过程记录
+ [解决 Visual Studio Code 向github提交代码不用输入帐号密码](#githubpush)
+ phase的意义:就是几个MR的一个集合,不定数目的MR job视为一个phase。一个请求经过nginx处理的过程中,会经过一系列的阶段(phases)
-## Nginx基础知识
-+ [NGINX 所有 Modules](https://www.nginx.com/resources/wiki/modules/)
-+ [Nginx 配置文件 nginx.conf 详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-base-config.md)
-#### agentzh的Nginx教程(版本2016.07.21)
-+ [agentzh的Nginx教程地址](https://openresty.org/download/agentzh-nginx-tutorials-zhcn.html)
-+ Nginx 变量漫谈(一)
- + Nginx 变量的值只有一种类型,那就是字符串
- + Nginx “变量插值”
- ```bash
- location /test {
- set $first "hello ";
- echo "${first}world";
- }
- ```
- + set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时
- + Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块
- + Nginx 变量的生命期是不可能跨越请求边界的
-+ Nginx 变量漫谈(二)
- + 跳转
- + 内部跳转:就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。
- + 外部跳转: HTTP 状态码 301 和 302 所进行的“外部跳转”
- + 标准 ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”
- + Nginx 核心和各个 Nginx 模块提供的“预定义变量”
- + Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式
- + 如果你尝试改写另外一些只读的内建变量,比如 $arg_XXX 变量,在某些 Nginx 的版本中甚至可能导致进程崩溃。
-+ Nginx 变量漫谈(四)
- + map 指令:用于定义两个 Nginx 变量之间的映射关系,或者说是函数关系
- + map 指令只能在 http 块中使用
- + map 配置指令的工作原理是为用户变量注册 “取处理程序”,并且实际的映射计算是在“取处理程序”中完成的,而“取处理程序”只有在该用户变量被实际读取时才会执行(当然,因为缓存的存在,只在请求生命期中的第一次读取中才被执行),所以对于那些根本没有用到相关变量的请求来说,就根本不会执行任何的无用计算。
-+ Nginx 变量漫谈(四)
-+ [Nginx的11个Phases](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-phases.md)
-+ [Nginx 陷阱和常见错误](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-1-config.md)
-+ [Nginx 高并发系统内核优化](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-parameter-config.md)
-
-## Redis基础知识
-+ [Redis 简易安装教程](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis/redis-install.md)
-## PHP脚本
-+ [PHP7中php.ini/php-fpm/www.conf的配置,Nginx和PHP-FPM的开机自动启动脚本](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/PHP/PHP-FPM/config.md)
-## Shell脚本
-+ [编写快速安全Bash脚本的建议](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Shell/write-shell-suggestions.md)
-+ [shell脚本实现分日志级别记录日志](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_Log.sh)
-+ [Nginx日志定时备份和删除](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_Nginx_Log_cut.sh)
-+ [SHELL脚本小技巧](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_script.md)
-+ [Mysql 自动备份脚本安全加锁机制](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/backup_mysql.sh)
-## Lua基础知识
-#### Lua 基础语法
-+ 删除一个全局变量,只要将变量值赋值为nil:`a = nil`,当且仅当一个变量不为nil 时,这个变量存在
-+ `Boolean`类型:在控制条件中除了`false`和`nil` 为假,其他值都为真,所以lua认为0和空字符串也是真
-+ `String`类型:
- + 字符串替换:`string.gsub()`
- ```lua
- a = 'one HELLO'
- b = string.gsub(a,'one','two')
- print(a) -- one HELLO
- print(b) -- two HELLO
- ```
- + 字符串和数字
- ```lua
- print("10" + 1) -- 11
- print("10" + "1") -- 11
- print("10 + 1") -- 10 + 1
- print("hello " .. " world") -- hello world
- --print("hello" + 1) -- 错误写法
- ```
- + 字符串和数字转换
- ```lua
- a = 10
- print(tostring(a)) -- 10
- b = "20"
- print(tonumber(b)) -- "20"
-
- print(tostring(10) == "10") -- true
- print(10 .. "" == "10") -- true
- ```
-+ 表达式
- + 如果两个值类型不相等,Lua认为两者不同
- + nil 只和自己相等
- + 逻辑运算符
- ```lua
- -- a and b -- 如果a为false,则返回a ,否则返回b
- -- a or b -- 如果a为true,则返回a ,否则返回b
- print(4 and 5) -- 5
- print(nil and 12 ) -- nill
- print(false and 12) -- false
- print(4 or 5) -- 4
- print(false or 5) -- 5
- ```
- + 注意:`and`的优先级比`or`高
- + Lua 三元运算符:`( a and b) or c`
-+ 变量
- + 赋值语句
- ```lua
- x = 20
- y = 30
- x,y = y,x
- print(x,y) -- 30 20
-
- a,b,c = 10,20
- print(a,b,c) --10 20 nil
-
- x,y,z = 10
- print(x,y,z) -- 10 nil nil
- ```
- + 局部变量与代码块
- + 代码块:指一个控制结构内,一个函数体,或者一个chunk(变量被声明的哪个文件或者文本串)
- + ```lua
- a = 12
- if a>10 then
- local i = 19
- print(i) -- 19
- end
- print(i) -- nil
- ```
-+ 控制语句
- ```lua
- members = { Tom = 10, Jake = 11, Dodo = 12, Jhon = 16 }
-
- for k, v in pairs(members) do
- if v == 10 then
- print(k, 'is 10 years old') -- Tom is 10 years old
- elseif v == 11 then
- print(k, 'is 11 years old') -- Jake is 11 years old
- elseif v == 12 then
- print(k, 'is 12 years old') -- Dodo is 12 years old
- else
- print(k, "is not 10,11,12 years old") -- Jhon is not 10,11,12 years old
- end
- end
- ```
-+ 函数
- + 单个返回值
- ```lua
- function max(a,b)
- if a > b then
- return a
- else
- return b
- end
- end
- print(max(10,20)) -- 20
- ```
- + 多个返回值
- ```lua
- function more()
- return 10 , 20 ,30
- end
- a , b , c = more()
- print(a,b,c) -- 10 20 30
- ```
- + 可变数目的参数
- ```lua
- function more()
- return 10 , 20 ,30
- end
- -- 当函数位于最后一位的时候,返回全部值,否则值返回一个数值
- a , b , c ,d = 100, more()
- print(a,b,c,d) -- 100 10 20 30
- ```
- + 闭合函数
- ```lua
- function count()
- -- i属于一个非局部变量,因为它既不是全局变量,也不是单纯的局部变量(因为另外一个函数可以访问到它)
- local i = 0
- return function()
- i =i +1
- return i
- end
- end
- -- 以上 count()函数里的那个函数,加上一个非全局变量i,就构成一个闭合函数
- -- 所以每次调用闭合函数,非局部变量的值都不会被重置
- local func = count()
- print(func()) -- 1
- print(func()) -- 2
- ```
- + 非全局函数,在定义函数的使用要注意定义函数的顺序
- ```lua
- local eat
- local drink
- eat = function()
- print("eat")
- return drink() -- 这里的drink()属于尾调用
- end
- drink = function()
- print("drink")
- end
- eat()
- ```
-+ table 使用
- + Lua table 第一个索引为1
- + 简单
- ```lua
- a = {}
- a.x = 100
- a.y = 200
- a["z"] = 300 -- a.z = 300
- print(a.x) -- 100
- print(a.y) -- 200
- print(a.z) -- 300
- ```
-+ 泛型迭代器
- + 标准库迭代器包括:
- + 迭代文件每行:`io.lines`
- + 迭代table元素:`pairs`
- - [x] 可以遍历表中的所有key
- - [x] 并且除了迭代器本身以及遍历表本身,还可以返回nil
- + 迭代数组元素:`ipairs`
- - [x] ipairs不能返回nil,只能返回数字0,如果遇到nil则退出
- - [x] 只能遍历表中出现的第一个不是整数的key
- + 泛型迭代器
- ```lua
- config = {host = '127.0.0.1',port = '3306', dbname = 'LuaDB' }
- config.redis_host = "192.168.1.1"
- config.redis_port = "6379"
- config.redis_db = "12"
- print(config['redis_host']) -- 192.168.1.1
- print(config.redis_port) -- 6379
- print(config.dbname) -- LuaDB
-
- for k, v in pairs(config) do
- print(k,v)
- end
-
- --[[
- host 127.0.0.1
- dbname LuaDB
- redis_host 192.168.1.1
- redis_db 12
- redis_port 6379
- port 3306
- -- ]]
- ```
- + 迭代table元素
- ```lua
- arr = {}
- for var = 1,100 do -- for 循环
- table.insert(arr,1,var)
- end
-
- for k, v in pairs(arr) do -- 遍历表
- print(k,v)
- end
- --[[ 打印结果
- 1 100
- 2 99
- ... ...
- 99 2
- 100 1
-
- -- ]]
- print(table.maxn(arr)) -- table长度 100
- print(#arr) -- table长度(快捷方式) 100
- ```
- + 迭代数组元素:`ipairs`
- ```lua
- arr = {host = '127.0.0.1',port = '3306','Tinywan'}
- -- 如果没有找到下标为整数的则直接退出,是整数的则直接输出,如上面的'Tinywan'
- for k, v in ipairs(arr) do -- 只能遍历key 为整数的下标
- print(k,v) -- 1 Tinywan
- end
- ```
- + 循环迭代table元素(如:lua-resty-mysql 扩展查询的数据)
- + 查询 :`res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)`
- + 转换成JSON结果集输出2条记录:
- ```lua
- ngx.say("result: ", cjson.encode(res))
- result: [{"age":"24123","name":"tinywan123","address":"China","id":"1"},{"age":"24","name":"tinywan","address":"China","id":"2"}]
- ```
- + 遍历该结果集:
- ```lua
- res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)
- if not res then
- ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
- return
- end
-
- for k, v in pairs(res) do
- if type(v) == "table" then
- for new_table_index, new_table_value in pairs(v) do
- ngx.say(new_table_index.." = "..new_table_value)
- end
- else
- ngx.say(k,v)
- end
- end
- --[[ 打印结果
- age = 24123
- name = tinywan123
- address = China
- id = 1
- age = 24
- name = tinywan
- address = China
- id = 2
- ]]
- ```
- + json 和 lua table 转换
- + [1] 将 json 转换成 lua table
- ```lua
- local json_str = '{"is_male":"nan","name":"zhangsan","id":1}'
- local t = json.decode(json_str)
- ngx.say(format_table(t))
- ```
- + [2] 将 lua table 转换成 json 字符串
- ```lua
- local t = [[{key="table key",value="table value"}]]
- local json_str = json.encode(t)
- ngx.say(json_str) -- "{key=\"table key\",value=\"table value\"}"
- ```
- + [3] 将lua table转换成 json 数组 (lua 两个大括号表示一个数组)
- ```lua
- local t = {keys={"list1","list2","list3"},num=1}
- local str = json.encode(t)
- ngx.say(str) -- {"keys":["list1","list2","list3"],"num":1}
- ```
-+ 编译执行与错误
- + error 错误
- ```lua
- local name = "Lua1"
- if name ~= "Lua"
- then
- error("this is not Lua ");
- end
- ```
- + assert 错误:`assert(name~="Lua"," this is not Lua")`
- + pcall 捕获错误代码
- ```lua
- function test()
- print(a[1])
- end
- -- pcall 除了会返回true或者false外,还能返回函数的错误信息。
- -- 如果没有错误信息,err 会返回一个nil
- local status,err = pcall(test)
- if status then
- print('success')
- else
- print('函数执行出错了')
- print('错误信息:',err)
- end
- ```
-+ Lua面向对象(重点)
- + [博客详细地址描述](http://www.cnblogs.com/tinywan/p/6940784.html)
- + :white_check_mark: `__add` 元方法 #demo1
- ```lua
- local mt = {}
- mt.__add = function(t1, t2)
- print("两个Table 相加的时候会调用我")
- end
- local t1 = {}
- local t2 = {}
- -- 给两个table 设置新的元表,一个元表就是一个table的值
- setmetatable(t1, mt) -- meta:元素
- setmetatable(t2, mt)
- -- 进行相加操作
- local t = t1 + t2
- print(t)
-
- --[[输出结果
- 两个Table 相加的时候会调用我
- nil
- --]]
- ```
- + :white_check_mark: `__add` 元方法 #demo2
- ```lua
- -- 创建一个元表 (是创建一个类吗?)
- local mt = {}
- mt.__add = function(s1, s2)
- local result = ""
- if s1.sex == "boy" and s2.sex == "girl" then
- result = "一个男孩和一个女孩的家庭"
- elseif s1.sex == "girl" and s2.sex == "girl" then
- result = "两个女孩的家庭"
- else
- result = "未知孩子的家庭"
- end
- return result
- end
- -- 创建两个table,可以想象成是两个类的对象(实例化两个类)
- local s1 = { name = "Per1", sex = "boy" }
- local s2 = { name = "Per2", sex = "girl" }
- -- 给两个table 设置新的元表,一个元表就是一个table的值
- setmetatable(s1, mt)
- setmetatable(s2, mt)
- -- 进行加法操作
- local result = s1 + s2
- print(result)
-
- -- 输出结果 一个男孩和一个女孩的家庭
- ```
- + :white_check_mark: `__index` 元方法 #demo1
- ```lua
- local t = {
- name = "Tinywan"
- }
- local mt = {
- __index = function(table, key)
- print("虽然你调用了我不存在的字段和方法,不过没关系,我能检测出来" .. key)
- end
- }
- setmetatable(t, mt)
- print(t.name)
- print(t.age)
-
- --[[输出结果
- -- Tinywan
- -- 虽然你调用了我不存在的字段和方法,不过没关系,我能检测出来age
- -- nil
- ---- ]]
- ```
- + :white_check_mark: `__index` 元方法 #demo2
- ```lua
- local t = {
- name = "Tinywan"
- }
- local mt = {
- money = 808080
- }
-
- mt.__index = mt
- setmetatable(t, mt)
- print(t.money)
- -- 输出结果 808080
- ```
- + :white_check_mark: `__index` 元方法 #demo3
- ```lua
- local t = {
- name = "Tinywan"
- }
- local mt = {
- __index = {
- money = 909090
- }
- }
- setmetatable(t, mt)
- print(t.money)
- -- 输出结果 909090
- ```
- + :white_check_mark: `__index` 元方法 #demo4
- ```lua
- local smartMan = {
- name = "Tinywan",
- age = 26,
- money = 800000,
- say_fun = function()
- print("Tinywan say 大家好")
- end
- }
-
- local t1 = {}
- local t2 = {}
- local mt = { __index = smartMan } -- __index 可以是一个表,也可以是一个函数
- setmetatable(t1, mt)
- setmetatable(t2, mt)
- print(t1.money)
- t2.say_fun()
- --- 输出结果
- -- 800000
- -- Tinywan say 大家好
- ```
- + Lua面向对象1
- + Lua面向对象1
- + Lua面向对象3 更新中...
-+ Lua 排序算法
- + [Lua 排序算法 - 选择排序](https://www.openresty.com.cn/ms2008-select-sort.html#section-1)
- + 选择排序
- ```lua
- local function selectionSort(arr)
- for i = 1,#arr-1 do
- local idx = i
- -- 迭代剩下的元素,寻找最小的元素
- for j = i+1,#arr do
- if arr[j] < arr[idx] then
- idx = j
- end
- end
- --
- arr[i],arr[idx]= arr[idx],arr[i]
- end
- end
-
- local list = {
- -81, -93, -36.85, -53, -31, 79, 45.94, 36, 94, -95.03, 11, 56, 23, -39,
- 14, 1, -20.1, -21, 91, 31, 91, -23, 36.5, 44, 82, -30, 51, 96, 64, -41
- }
-
- selectionSort(list)
- print(table.concat( list, ", "))
- ```
-#### 控制结构
-+ [if-elseif-end 语句](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/if-else-example.lua)
-+ [for 语句](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/for-example.lua)
-+ [Lua 只有一个容器,那就是table](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/container-table.lua)
-#### [Lua 实现简单封装](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/function1.lua)
-#### Table 操作常用的方法
-+ table.concat (table [, sep [, start [, end]]])
- + concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开
- + demo
- ```lua
- fruits = {"banana","orange","apple"}
- -- 返回 table 连接后的字符串 value = banana orange apple
- print("连接后的字符串 ",table.concat(fruits))
- -- 指定连接字符 value = banana, orange, apple
- print("指定连接字符连接后的字符串 ",table.concat(fruits,", "))
- ```
-+ table.insert (table, [pos,] value):
- + 在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾
- + demo
- ```lua
- fruits = {"banana","orange","apple"}
-
- -- 在末尾插入
- table.insert(fruits,"Tinywan4")
- print("索引为 4 的元素为 ",fruits[4]) -- 索引为 4 的元素为 Tinywan
-
- -- 在索引为 2 的键处插入
- table.insert(fruits,2,'Tinywan2')
- print("索引为 2 的元素为 ",fruits[2]) -- 索引为 2 的元素为 Tinywan
-
- print("最后一个元素为 ",fruits[5]) -- 最后一个元素为 Tinywan4
- table.remove(fruits)
- print("移除后最后一个元素为 ",fruits[5]) -- 移除后最后一个元素为 nil
- ```
-+ table.sort (table [, comp])
- + 对给定的table进行升序排序
-#### Lua 模块与包
-+ 定义:Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行.
## 流媒体视频直播、点播
+ [Nginx配置Rtmp支持Hls的直播和点播功能](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/HLS-live-vod.md)
+ [HLS视频直播和点播的Nginx的Location的配置信息(成功)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/HLS-live-vod-locatiuon-config.md)
-
-## Nginx高性能WEB服务器详解
-#### 第一章 初探
-+ [Nginx 编译安装以及参数详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-2-config.md)
-+ NGINX变量详解
- - [x] [nginx变量使用方法详解笔记(1)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/notes-1.md)
- - [x] [nginx变量使用方法详解笔记(2)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/notes-2.md)
- - [x] [nginx变量使用方法详解笔记(3)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-2-config.md)
-+ Nginx指令执行顺序
- - [x] [Nginx指令执行命令(01)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/command-order-01.md)
-#### 第二章 安装部署
-+ 启动错误:`Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)`,执行:`sudo fuser -k 80/tcp`
-+ [基于域名、IP的虚拟主机配置](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-all-config.md)
-+ [完整、标准配置实际示列](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-basic-config.md)
-+ [日志文件配置与切割](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-log-cut.md)
-+ alias 和 root 在location 下的应用
- - 通过alias 实现别名功能
- ```
- location /live {
- alias /home/tinywan/HLS/;
- }
- ```
- - curl 请求结果
- ```
- tinywan@tinywan:~/HLS$ cat index.html
- alias /home/tinywan/HLS/index.html
- tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/index.html
- alias /home/tinywan/HLS/index.html
- ```
- - 结论:
- 1. cul 请求 `/live/index.html`,那么Nginx将会在服务器上查找`/home/tinywan/HLS/index.html` 文件
- 1. 请求的`url` 中的`location`后面的部分会被追加到`alias `指定的目录后面,而`location`后面的`/live`路径将会别自动抛弃
- - 类似案例[2]:
- - config配置信息
- ```
- location ~ ^/live/(.*)$ {
- alias /home/tinywan/HLS/$1;
- }
- ```
- - curl 请求结果
- ```
- tinywan@tinywan:~/HLS$ pwd
- /home/tinywan/HLS
- tinywan@tinywan:~/HLS$ cat txt.txt
- txt file
- tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
- txt file
- ```
- - 如果url请求`/live/txt.txt`那么Nginx将会在服务器上查找`/home/tinywan/HLS/txt.txt` 文件
- - **与root 功能的差别**:
- - config配置信息,注意:一下的`alias` 换成 `root `
- ```
- location ~ ^/live/(.*)$ {
- root /home/tinywan/HLS/$1;
- }
- ```
- - curl 请求结果
- ```
- tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
-
- 404 Not Found
-
- 404 Not Found
-
openresty/1.11.2.1
-
-
- ```
- - 日志文件信息(打开Nginx的rewrite日志:rewrite_log on;):
- ```
- /home/tinywan/HLS/txt.txt/live/txt.txt
- ```
- - **二者的区别**
- 1. `alias` 指定的目录是当前目录
- 1. `root` 指定的是根目录
- 1. 一般建议的`location /`中通过`root`命令配置目录,其他目录匹配的位置使用`alias`命令
- - 案例[3]:
- - config配置信息
- ```
- location ~ ^/live/(\w+)/(.*) {
- alias /home/tinywan/HLS/live/$1/$2;
- }
- ```
- - curl 请求结果
- ```
- tinywan@tinywan:~/HLS/live/stream123$ pwd
- /home/tinywan/HLS/live/stream123
- tinywan@tinywan:~/HLS/live/stream123$ cat index.m3u8
- 12312312312
- tinywan@tinywan:~/HLS/live/stream123$ curl "http://127.0.0.1/live/stream123/index.m3u8?token=1234&api=009132"
- 12312312312
- ```
-#### 第三章 架构初探
-- [ ] 测试一
-#### 第四章 高级配置
-+ 基本语法:location [=|~|~*|^~] /uri/ { … }
- 1. `= `:严格匹配。如果这个查询匹配,那么将停止搜索并立即处理此请求。
- 2. `~ `:为区分大小写匹配(可用正则表达式)
- 3. `!~ `:为区分大小写不匹配
- 4. `!~*`:为不区分大小写不匹配
- 5. ` ^~ `:如果把这个前缀用于一个常规字符串,那么告诉nginx 如果路径匹配那么不测试正则表达式
-+ [Perl 正则表达式参考](http://www.runoob.com/perl/perl-regular-expressions.html)
-+ 正则中需要转义的特殊字符小结
- - [1] ` $` 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n' 或 ‘\r'。要匹配 $ 字符本身,请使用 \$。
- - [2] ` ( )` 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 和。
- - [3] ` * ` 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
- - [4] ` +` 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
- - [5] ` . ` 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
- - [6] ` [ ]` 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
- - [7] ` ? ` 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
- - [8] ` \ ` 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n' 匹配字符 ‘n'。'\n' 匹配换行符。序列 ‘\\' 匹配 “\”,而 ‘\(' 则匹配 “(”。
- - [9] ` ^ ` 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
- - [10] ` { }` 标记限定符表达式的开始。要匹配 {,请使用 \{。
- - [11] ` | ` 指明两项之间的一个选择。要匹配 |,请使用 \|。
-
-+ 正则表达式 (Regular expression) 匹配location
- - [1] `location ~* \.(gif|jpg|jpeg)$ { }`:匹配所有以 gif,jpg或jpeg 结尾的请求
- - [2] `location ~ /documents/Abc { }`:匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
- - [3] **目录匹配:**
- 1. 可以匹配静态文件目录`(static/lib)`
- 2. HLS直播目录`(/home/HLS/stream123/index.m3u8)`
- 3. HLS/MP4/FLV点播视频目录`(/home/HLS/stream123.m3u8)`
- 4. 匹配URL地址:`http://127.0.0.1/live/stream123/index.m3u8`
- 5. nginx.conf 配置信息
- ```
- # 匹配任何以/live/ 开头的任何查询并且停止搜索。任何正则表达式将不会被测试
- location ^~ /live/ {
- root /home/tinywan/HLS/;
- }
- # 以上匹配成功后的组合:/home/tinywan/HLS/live/....
- ```
-+ 后缀匹配
- 1. 匹配任何后缀文件名`gif|jpg|jpeg|png|css|js|ico|m3u8|ts` 结尾的请求
- 2. TS 文件匹配`http://127.0.0.1/live/stream123/11.ts`
- 3. M3U8 文件匹配`http://127.0.0.1/live/stream123/index.m3u8`
- 4. 匹配URL地址:`http://127.0.0.1/hls/123.m3u8`
- 5. nginx.conf 配置信息
- ```
- location ~* \.(gif|jpg|jpeg|png|css|js|ico|m3u8|ts)$ {
- root /home/tinywan/HLS/;
- }
- ```
-+ HSL直播目录匹配实际案例(请测试上线)
- 1. 可以后缀文件名:`http://127.0.0.1/live/stream123/index.m3u8`
- ```
- location ^~ /live/ {
- root /home/tinywan/HLS/;
- }
- ```
-
-+ [nginx配置location总结及rewrite规则写法](http://seanlook.com/2015/05/17/nginx-location-rewrite/)
-#### 第五章 Gzip压缩
-+ 测试一
-#### 第六章 Rewrite 功能
-+ Rewrite 常用全局变量
- + 请求案例: `curl -G -d "name=Tinywan&age=24" http://127.0.0.1/rewrite_var/1192/index.m3u8`
- + 接受结果:
-
- | 变量 | 值 |描述 |
- | --------- | ----------- |----------- |
- | $args | name=Tinywan&age=24 |存放URL 请求的指令 |
- | $content_length | 0 | 请求头中的Content-length字段|
- | $content_type | 0 |请求头中的Content-Type字段 |
- | $document_root | /opt/openresty/nginx/html | 当前请求在root指令中指定的值 |
- | $document_uri | /rewrite_var/1192/index.m3u8 | 与$uri相同 |
- | $host | 127.0.0.1 |请求主机头字段,否则为服务器名称 |
- | $http_user_agent | curl/7.47.0 | 客户端agent信息|
- | $http_cookie | 0 | COOKIE变量的值|
- | $limit_rate | 0 | 限制连接速率|
- | $request_body_file | null | 客户端请求主体信息的临时文件名|
- | $request_method | GET | 客户端请求的动作,通常为GET或POST |
- | $remote_addr | 127.0.0.1 |客户端的IP地址 |
- | $remote_port | 33516 |客户端端口|
- | $remote_user | 0 | 已经经过Auth Basic Module验证的用户名|
- | $request_filename | /opt/openresty/nginx/html/rewrite_var/1192/index.m3u8 |当前请求的文件路径 |
- | $request_uri | /rewrite_var/1192/index.m3u8?name=Tinywan&age=24 |包含请求参数的原始URI,不包含主机名 |
- | $query_string | name=Tinywan&age=24 | 与$args相同|
- | $scheme | http |HTTP方法(如http,https |
- | $server_protocol | HTTP/1.1 |请求使用的协议,通常是HTTP/1.0或HTTP/1.1 |
- | $server_addr | 127.0.0.1 |服务器地址 |
- | $server_name | localhost | 服务器名称|
- | $server_port | 80 |请求到达服务器的端口号 |
- | $uri | /rewrite_var/1192/index.m3u8 | 不带请求参数的当前URI|
- | $binary_remote_addr | 乱码 | 二进制格式的客户端地址|
-
- + uri 介绍 **(Nginx中的URI是相对的URI)**
- + URL:`https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
- + 绝对URI:`https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
- + 相对URI:`/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
- 
-
-+ Rewrite 正则匹配` uri `参数接收
- 1. 请求案例:`curl http://192.168.18.143/live/tinywan123/index.m3u8`
- 2. Nginx.conf配置文件
- ```Lua
- location ~* ^/live/(\w+)/(\D+)\.(m3u8|ts)$ {
- set $num $2;
- set $arg1 $1;
- echo "args === ${arg1}";
- echo "1==$1 2==$2 3==$3";
- echo "Total_numbser :: $num";
- echo "URI $uri";
- }
-
- ```
- 3. 输出结果
- ```
- args === tinywan123
- $1==tinywan123 $2==index $3==m3u8
- Total_numbser :: index
- URI /live/tinywan123/index.m3u8
- Total_numbser ::
- ```
- 4. $1为正则匹配多个英文字母或数字的字符串 `(\w+)`
- $2 为正则匹配多个非数字 `(\D+)`
- $3 为正则匹配的第一个值 `(m3u8|ts)`
- `.` 需要用转义字符转义`\.`
-## 第七章 代理服务
-+ [正向代理和反向代理的概念](#title)
-+ [正向代理服务](#title)
-+ [反向代理的服务](#title)
-+ [Nginx日志服务](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-Log.md)
-+ 负载均衡
-+ HTTP负载均衡
- - [x] [简单的负载平衡](http://nginx.org/en/docs/http/ngx_http_core_module.html?&_ga=1.179030369.49817296.1480411319#http)
- - [x] [简单的负载平衡](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-7-Proxy-1.md)
- - [x] [负载均衡五个配置实例](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-7-Proxy.md)
- - [x] [Openresty-Lua动态修改upstream后端服务](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/openresty-nginx-lua-Proxy.md)
-+ TCP负载均衡
- - [x] [Module ngx_stream_core_module](http://nginx.org/en/docs/stream/ngx_stream_core_module.html#stream)
- - [x] [负载均衡](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-8-tcp-Proxy.md)
-+ proxy_pass 代理的URL总结
- + 在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。
- + 将url中以/wap/开头的请求转发到后台对应的某台server上,注意最后的?$args,表明把原始url最后的get参数也给代理到后台
- ```bash
- location ~* /wap/(\d+)/(.+)
- {
- proxy_pass http://mx$1.test.com:6601/$2?$args;
- }
- ```
- + 第一种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/index.html`
- ```bash
- location /proxy/ {
- proxy_pass http://127.0.0.1:8000/;
- }
- ```
- + 第二种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/proxy/index.html`
- ```bash
- location /proxy/ {
- proxy_pass http://127.0.0.1:8000;
- }
- ```
- + 第三种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/video/index.html`
- ```bash
- location /proxy/ {
- proxy_pass http://127.0.0.1:8000/video/;
- }
- ```
- + 第四种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/videoindex.html`
- ```bash
- location /proxy/ {
- proxy_pass http://127.0.0.1:8000/video;
- }
- ```
-+ location 直接访问:
- + 以下配置,当访问:`http://127.0.0.1:8000/proxy/index.html` 会被匹配到:`/usr/local/nginx/html/proxy/index.html`
- ```bash
- location /proxy/ {
- root /usr/local/nginx/html;
- index index.html index.htm;
- }
- ```
-
-## 第八章 缓存机制
-+ 测试一
-## 第九章 Nginx初探1
-+ 测试一
-## 第十章 Nginx初探1
-+ 测试一
## PHP脚本运行Redis]
+ [PHP 脚本执行一个Redis 订阅功能,用于监听键过期事件,返回一个回调,API接受改事件](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis-PHP/Php-Run-Redis-psubscribe/nohupRedisNotify.php)
-+ 单行文本1
-## Openresty 学习
-+ [安装信息](http://www.cnblogs.com/tinywan/p/6647587.html)
-+ [默认配置信息](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/default-config.md)
-+ 开发入门
- + Nginx与Lua的整体目录关系
- ```javascript
- .
- ├── conf
- │ ├── nginx.conf -- Nginx 配置文件
- ├── logs
- │ ├── error.log -- Nginx 错误日子
- │ └── nginx.pid
- ├── lua
- │ ├── m3u8_redis_access.lua -- M3U8地址权限验证文件
- │ ├── business_redis.lua -- 业务 Redis 处理文件
- │ ├── http-lua-test.lua -- http lua demo
- │ ├── ...
- │ └── resty -- 存放Lua 的所有公共、封装好的库目录
- │ └── redis_iresty.lua -- Redis 接口的二次封装
- │ └── param.lua -- 参数过滤库
- └── sbin
- └── nginx
- ```
- + 参数总结
- + Lua脚本接受Nginx变量:
- > [1] 间接获取:`var = ngx.var `,如接受Nginx的变量` $a = 9`,则`lua_a = ngx.var.a --lua_a = 9`
- [2] 直接获取:`var = ngx.var `,如接受Nginx的location的第二个变量890,` http://127.0.0.1/lua_request/123/890 `,则`lua_2 = ngx.var[2] --lua_2 = 890`
- + Lua 脚本接受 Nginx 头部 header:
- > [1] 返回一个包含所有当前请求标头的Lua表:`local headers = ngx.req.get_headers()`
- [2] 获取单个Host:`headers["Host"] 或者 ngx.req.get_headers()["Host"] `
- [3] 获取单个user-agent:
- >> [01]`headers["user-agent"]`
- [02]`headers.user_agent `
- [03]`ngx.req.get_headers()['user-agent'] `
- + Lua 脚本 Get 获取请求uri参数
- > linux curl Get方式提交数据语法:`curl -G -d "name=value&name2=value2" https://github.com/Tinywan `
- 返回一个包含所有当前请求URL查询参数的Lua表:`local get_args = ngx.req.get_uri_args()`
- 请求案例:`curl -G -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789`
- Lua Get 方式获取提交的name参数的值:`get_args['name'] 或者 ngx.req.get_uri_args()['name']`
- >> [01]`get_args['name']`
- [02]`ngx.req.get_uri_args()['name']`
- + Lua 脚本 Post 获取请求uri参数
- > linux curl Post方式提交数据语法:
- >> [01] `curl -d "name=value&name2=value2" https://github.com/Tinywan `
- [02] `curl -d a=b&c=d&txt@/tmp/txt https://github.com/Tinywan `
- > 返回一个包含所有当前请求URL查询参数的Lua表:`local post_args = ngx.req.get_post_args()`
- 请求案例:`curl -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789`
- Lua Post 方式获取提交的name参数的值:
- >> [01]`post_args['name']`
- [02]`ngx.req.get_post_args()['name']`
- + Lua 脚本请求的http协议版本:`ngx.req.http_version()`
- + Lua 脚本请求方法:`ngx.req.get_method()`
- + Lua 脚本原始的请求头内容:`ngx.req.raw_header()`
- + Lua 脚本请求的body内容体:`ngx.req.get_body_data()`
- + [接收请求:获取如请求参数、请求头、Body体等信息]()
- + [接收请求:输出响应需要进行响应状态码、响应头和响应内容体的输出](
-+ luajit 执行文件默认安装路径:`/opt/openresty/luajit/bin/luajit`,这样我们直接可以这样运行一个Lua文件:`luajit test.lua `
- + luajit 运行测试案例:
- ```Bash
- tinywan@tinywan:~/Lua$ luajit test.lua
- The man name is Tinywan
- The man name is Phalcon
- ```
-#### lua-resty-redis 扩展 (是openresty下操作redis的模块)
-+ 代码引入:`lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/?.lua;;";`
-+ Lua脚本实现一个CDN的反向代理功能(智能查找CDN节点)(测试成功,可上线)
- + nginx.conf 配置信息
- ```Lua
- http {
- lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/?.lua;;";
- server {
- listen 80;
- server_name localhost;
- location ~ \/.+\/.+\.(m3u8|ts) {
- if ($uri ~ \/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)(|-).*\.(m3u8|ts)) {
- set $app_name $1;
- set $a $2;
- }
- set $stream_id "";
- default_type 'text/html';
- rewrite_by_lua_file /opt/openresty/nginx/lua/proxy_pass_cdn.lua;
- proxy_connect_timeout 10;
- proxy_send_timeout 30;
- proxy_read_timeout 30;
- proxy_pass $stream_id;
- }
-
- }
- }
- ```
- + [Lua脚本proxy_pass_cdn.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/proxy_pass_cdn.lua)
- + [lua-nginx-module 贡献代码](https://github.com/openresty/lua-nginx-module/issues/275)
-
-+ Lua脚本结合 Nginx+Lua+Local Redis+Mysql服务器缓存
- + Nginx+Lua+Local Redis+Mysql集群架构
- + 
- + [Lua脚本Nginx+Lua+Redis+Mysql.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+Mysql.lua)
- + [Nginx.conf配置文件Nginx+Lua+Redis+Mysql.conf](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+Mysql.conf)
- + [HELP](http://jinnianshilongnian.iteye.com/blog/2188113)
-
- + Lua脚本结合 Redis 统计直播流播放次数、链接次数等等信息
- + nginx.conf
- ```Lua
- server { # 配置虚拟服务器80
- listen 80;
- server_name 127.0.0.1:8088;
- location ~* /live/(\w+)/ {
- set $total_numbers "";
- set $stream_name $1;
- lua_code_cache off;
- rewrite_by_lua_file /opt/openresty/nginx/conf/Lua/total_numbers.lua;
- proxy_pass http://127.0.0.1:8088;
- }
- }
- ```
- + 代理服务器
- ```Lua
- server { # 配置虚拟服务器8088
- listen 8088;
- server_name 127.0.0.1:8088;
- location /live {
- add_header Cache-Control no-cache;
- add_header 'Access-Control-Allow-Origin' '*' always;
- add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
- add_header 'Access-Control-Allow-Headers' 'Range';
- types{
- application/dash+xml mpd;
- application/vnd.apple.mpegurl m3u8;
- video/mp2t ts;
- }
- alias /home/tinywan/HLS/live/;
- }
- }
-
- ```
- + CURL请求地址:`http://192.168.18.143/live/tinywan123/index.m3u8`
- + [Lua 脚本](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Hls-Line-Number-Total.lua)
-
-#### lua-resty-websocket 扩展
-+ 代码引入:`lua_package_path "/opt/openresty/nginx/lua/lua-resty-websocket/lib/?.lua;;";`
-+ **Lua脚本实现一个websocket连接(测试成功,可上线)**
- + nginx.conf 配置信息
- ```Lua
- http {
- lua_package_path "/opt/openresty/nginx/lua/lua-resty-websocket/lib/?.lua;;";
- server {
- listen 80 so_keepalive=2s:2s:8; #为了防止半开TCP连接,最好在Nginx监听配置指令中启用TCP keepalive:
- server_name localhost;
- location /ws {
- lua_socket_log_errors off;
- lua_check_client_abort on;
- lua_code_cache off; # 建议测试的时候最好关闭缓存
- content_by_lua_file /opt/openresty/nginx/conf/Lua/websocket.lua;
- }
- }
- }
- ```
- + [WebSockets服务器Lua脚本websocket.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-websocket/websocket.lua)
- + [websockets.html客户端代码,代码路径:/usr/local/openresty/nginx/html](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-websocket/websocket.html)
- + 然后打开启用了WebSocket支持的浏览器,然后打开以下url:
- 
-#### lua-cjson 扩展
-+ 基本用法
- + nginx.conf
- ```Lua
- location /cjson {
- content_by_lua_block {
- local cjson = require "cjson"
- local json = cjson.encode({
- foo = "bar",
- some_object = {},
- some_array = cjson.empty_array
- })
- ngx.say(json)
- }
- }
- ```
- + curl 请求
- ```Bash
- root@tinywan:/opt/openresty/nginx/conf# curl http://127.0.0.1/cjson
- {"some_object":{"tel":13669313112,"age":24},"name":"tinywan","some_array":[]}
- ```
-+ [lua对象到字符串、字符串到lua对象](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-cjson/cjson-str-obj.lua)
-#### lua-resty-session 扩展
-+ OpenResty 引用第三方 resty 库非常简单,只需要将相应的文件拷贝到 resty 目录下即可
-+ 我服务器OpenResty 的 resty 路径:`/opt/openresty/lualib/resty`
-+ 下载第三方 resty 库:git clone lua-resty-session 文件路径以及内容:
- ```Bash
- tinywan@tinywan:/opt/openresty/nginx/lua/lua-resty-session/lib/resty$ ls
- session session.lua
- ```
-+ 特别注意:这里拷贝的时候要要把session文件和session.lua 文件同时吧、拷贝过去,否则会报错误:
- ```Bash
- /opt/openresty/lualib/resty/session.lua:34: in function 'prequire'
- /opt/openresty/lualib/resty/session.lua:211: in function 'new'
- /opt/openresty/lualib/resty/session.lua:257: in function 'open'
- /opt/openresty/lualib/resty/session.lua:320: in function 'start'
- ```
-+ 拷贝完毕后`/opt/openresty/lualib/resty` OpenResty 引用第三方 resty 的所有库文件
- ```Bash
- tinywan@tinywan:/opt/openresty/lualib/resty$ ls
- aes.lua core.lua http_headers.lua lock.lua lrucache.lua memcached.lua random.lua session sha1.lua sha256.lua sha512.lua string.lua upstream
- core dns http.lua lrucache md5.lua mysql.lua redis.lua session.lua sha224.lua sha384.lua sha.lua upload.lua websocket
- ```
-+ 基本用法
- ```Lua
- location /start {
- content_by_lua_block {
- local session = require "resty.session".start()
- session.data.name = "OpenResty Fan Tinywan"
- session:save()
- ngx.say("Session started. ",
- "Check if it is working!")
- ngx.say(session.data.name,"Anonymous")
- }
- }
- ```
-+ curl 请求
- ```Bash
- tinywan@tinywan:/opt/openresty/nginx/conf$ curl http://192.168.18.143/start
- Session started. Check if it is working!
- OpenResty Fan Tinywan Anonymous
- ```
-#### Lua 权限验证
-+ Lua 一个HLS的简单地址访问权限验证
- + Nginx.conf 配置
- ```Lua
- location ^~ /live/ {
- add_header Cache-Control no-cache;
- add_header 'Access-Control-Allow-Origin' '*' always;
- add_header 'Access-Control-Allow-Credentials' 'true';
- add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
- add_header 'Access-Control-Allow-Headers' 'Range';
- types{
- application/dash+xml mpd;
- application/vnd.apple.mpegurl m3u8;
- video/mp2t ts;
- }
- if ( $uri ~ \.m3u8 ) {
- lua_code_cache off;
- access_by_lua_file /opt/openresty/nginx/lua/access.lua;
- }
- root /home/tinywan/HLS;
- }
- ```
- + access.lua 文件内容
- ```Lua
- if ngx.req.get_uri_args()["wsSecret"] ~= "e65e6a01cf26523e206d5bb0e2a8a95a" then
- return ngx.exit(403)
- end
- ```
-#### lua-resty-string 扩展
-+ MD5加密的简单基本用法 md5.lua
- ```Lua
- local resty_md5 = require "resty.md5"
- local md5 = resty_md5:new()
- if not md5 then
- ngx.say("failed to create md5 object")
- return
- end
- local ok = md5:update("hello")
- if not ok then
- ngx.say("failed to add data")
- return
- end
- local digest = md5:final()
- -- ngx.say("md5",digest) ---注意:这样直接输出是乱码
- local str = require "resty.string"
- ngx.say("md5: ", str.to_hex(digest)) ---注意:必须通过字符串转码方可打印输出
- -- yield "md5: 5d41402abc4b2a76b9719d911017c592"
- ```
-#### lua-resty-http 扩展 (ngx_lua的HTTP客户端cosocket驱动程序)
-+ [简单测试:lua-http-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-http/lua-http-test.lua)
-#### lua-resty-mysql 扩展
-+ [简单测试:lua-msyql-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-mysql/lua-msyql-test.lua)
-#### srcache-nginx-module 扩展 ([nginx下的一个缓存模块](https://github.com/openresty/srcache-nginx-module))
-+ [openresty–redis–srcache缓存的应用](http://www.xtgxiso.com/openresty-redis-srcache-nginx-module%e7%bc%93%e5%ad%98%e7%9a%84%e5%ba%94%e7%94%a8/)
-#### openresty扫描代码全局变量
-+ 在OpenResty中需要避免全局变量的使用,为此春哥写了一个perl工具,可以扫描openresty lua代码的全局变量
-+ [https://github.com/openresty/openresty-devel-utils/blob/master/lua-releng](https://github.com/openresty/openresty-devel-utils/blob/master/lua-releng)
-+ 用法相当简单
- 1. 将代码保存成lua-releng文件
- 2. 更改lua-releng的权限,chmod 777 lua-releng
- 3. 假设有一个源码文件为test.lua
- 4. 执行./lua-releng test.lua,则会扫描test.lua文件的全局变量,并在屏幕打印结果
-#### ngx Lua APi 方法和常量
-+ ngx_lua 核心常量
- ```lua
- ngx.OK (0)
- ngx.ERROR (-1)
- ngx.AGAIN (-2)
- ngx.DONE (-4)
- ngx.DECLINED (-5)
- ngx.nil
- -- 指令常量
- ngx.arg[index] #ngx指令参数,当这个变量在set_by_lua或者set_by_lua_file内使用的时候是只读的,指的是在配置指令输入的参数.
- ngx.var.varname #读写NGINX变量的值,最好在lua脚本里缓存变量值,避免在当前请求的生命周期内内存的泄漏
- ngx.config.ngx_lua_version #当前ngx_lua模块版本号
- ngx.config.nginx_version #nginx版本
- ngx.worker.exiting #当前worker进程是否正在关闭
- ngx.worker.pid #当前worker进程的PID
- ngx.config.nginx_configure #编译时的./configure命令选项
- ngx.config.prefix #编译时的prefix选项
- ```
-+ ngx_lua 方法 (#经常在ngx.location.catpure和ngx.location.capture_multi方法中被调用.)
- ```lua
- ngx.HTTP_GET
- ngx.HTTP_HEAD
- ngx.HTTP_PUT
- ngx.HTTP_POST
- ngx.HTTP_DELETE
- ngx.HTTP_OPTIONS
- ngx.HTTP_MKCOL
- ngx.HTTP_COPY
- ngx.HTTP_MOVE
- ngx.HTTP_PROPFIND
- ngx.HTTP_PROPPATCH
- ngx.HTTP_LOCK
- ngx.HTTP_UNLOCK
- ngx.HTTP_PATCH
- ngx.HTTP_TRACE
- ```
-+ 错误日志级别常量
- ```lua
- ngx.STDERR
- ngx.EMERG
- ngx.ALERT
- ngx.CRIT
- ngx.ERR
- ngx.WARN
- ngx.NOTICE
- ngx.INFO
- ngx.DEBUG
- ```
-+ API中的常用方法
- ```lua
- print() #与 ngx.print()方法有区别,print() 相当于ngx.log()
- ngx.ctx #这是一个lua的table,用于保存ngx上下文的变量,在整个请求的生命周期内都有效,详细参考官方
- ngx.location.capture() #发出一个子请求,详细用法参考官方文档。
- ngx.location.capture_multi() #发出多个子请求,详细用法参考官方文档。
- ngx.status #读或者写当前请求的相应状态. 必须在输出相应头之前被调用.
- ngx.header.HEADER #访问或设置http header头信息,详细参考官方文档。
- ngx.req.set_uri() #设置当前请求的URI,详细参考官方文档
- ngx.set_uri_args(args) #根据args参数重新定义当前请求的URI参数.
- ngx.req.get_uri_args() #返回一个LUA TABLE,包含当前请求的全部的URL参数
- ngx.req.get_post_args() #返回一个LUA TABLE,包括所有当前请求的POST参数
- ngx.req.get_headers() #返回一个包含当前请求头信息的lua table.
- ngx.req.set_header() #设置当前请求头header某字段值.当前请求的子请求不会受到影响.
- ngx.req.read_body() #在不阻塞ngnix其他事件的情况下同步读取客户端的body信息.[详细]
- ngx.req.discard_body() #明确丢弃客户端请求的body
- ngx.req.get_body_data() #以字符串的形式获得客户端的请求body内容
- ngx.req.get_body_file() #当发送文件请求的时候,获得文件的名字
- ngx.req.set_body_data() #设置客户端请求的BODY
- ngx.req.set_body_file() #通过filename来指定当前请求的file data。
- ngx.req.clear_header() #清求某个请求头
- ngx.exec(uri,args) #执行内部跳转,根据uri和请求参数
- ngx.redirect(uri, status) #执行301或者302的重定向。
- ngx.send_headers() #发送指定的响应头
- ngx.headers_sent #判断头部是否发送给客户端ngx.headers_sent=true
- ngx.print(str) #发送给客户端的响应页面
- ngx.say() #作用类似ngx.print,不过say方法输出后会换行
- ngx.log(log.level,...) #写入nginx日志
- ngx.flush() #将缓冲区内容输出到页面(刷新响应)
- ngx.exit(http-status) #结束请求并输出状态码
- ngx.eof() #明确指定关闭结束输出流
- ngx.escape_uri() #URI编码(本函数对逗号,不编码,而php的urlencode会编码)
- ngx.unescape_uri() #uri解码
- ngx.encode_args(table) #将tabel解析成url参数
- ngx.decode_args(uri) #将参数字符串编码为一个table
- ngx.encode_base64(str) #BASE64编码
- ngx.decode_base64(str) #BASE64解码
- ngx.crc32_short(str) #字符串的crs32_short哈希
- ngx.crc32_long(str) #字符串的crs32_long哈希
- ngx.hmac_sha1(str) #字符串的hmac_sha1哈希
- ngx.md5(str) #返回16进制MD5
- ngx.md5_bin(str) #返回2进制MD5
- ngx.today() #返回当前日期yyyy-mm-dd
- ngx.time() #返回当前时间戳
- ngx.now() #返回当前时间
- ngx.update_time() #刷新后返回
- ngx.localtime() #返回 yyyy-mm-dd hh:ii:ss
- ngx.utctime() #返回yyyy-mm-dd hh:ii:ss格式的utc时间
- ngx.cookie_time(sec) #返回用于COOKIE使用的时间
- ngx.http_time(sec) #返回可用于http header使用的时间
- ngx.parse_http_time(str) #解析HTTP头的时间
- ngx.is_subrequest #是否子请求(值为 true or false)
- ngx.re.match(subject,regex,options,ctx) #ngx正则表达式匹配,详细参考官网
- ngx.re.gmatch(subject,regex,opt) #全局正则匹配
- ngx.re.sub(sub,reg,opt) #匹配和替换(未知)
- ngx.re.gsub() #未知
- ngx.shared.DICT #ngx.shared.DICT是一个table 里面存储了所有的全局内存共享变量
- ngx.shared.DICT.get
- ngx.shared.DICT.get_stale
- ngx.shared.DICT.set
- ngx.shared.DICT.safe_set
- ngx.shared.DICT.add
- ngx.shared.DICT.safe_add
- ngx.shared.DICT.replace
- ngx.shared.DICT.delete
- ngx.shared.DICT.incr
- ngx.shared.DICT.flush_all
- ngx.shared.DICT.flush_expired
- ngx.shared.DICT.get_keys
- ndk.set_var.DIRECTIVE
- ```
-+ Lua HTTP状态常量
- ```Lua
- value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)
- value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)
- value = ngx.HTTP_OK (200)
- value = ngx.HTTP_CREATED (201)
- value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)
- value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)
- value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)
- value = ngx.HTTP_SPECIAL_RESPONSE (300)
- value = ngx.HTTP_MOVED_PERMANENTLY (301)
- value = ngx.HTTP_MOVED_TEMPORARILY (302)
- value = ngx.HTTP_SEE_OTHER (303)
- value = ngx.HTTP_NOT_MODIFIED (304)
- value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)
- value = ngx.HTTP_BAD_REQUEST (400)
- value = ngx.HTTP_UNAUTHORIZED (401)
- value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)
- value = ngx.HTTP_FORBIDDEN (403)
- value = ngx.HTTP_NOT_FOUND (404)
- value = ngx.HTTP_NOT_ALLOWED (405)
- value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)
- value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)
- value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)
- value = ngx.HTTP_GONE (410)
- value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)
- value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)
- value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)
- value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)
- value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
- value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
- value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)
- value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
- value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)
- value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)
- value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)
- ```
-+ 案列使用,get_string_md5.lua:
- ```Lua
- local args = ngx.req.get_uri_args()
- local salt = args.salt
- if not salt then
- ngx.say(ngx.HTTP_BAD_REQUEST)
- end
- local string = ngx.md5(ngx.time()..salt)
- ngx.say(string)
-
- ```
-+ curl 请求(-i 参数,输出时包括protocol头信息):
- ```Bash
- tinywan@tinywan:$ curl -i http://127.0.0.1/get_rand_string?salt=tinywan123
- HTTP/1.1 200 OK
- Server: openresty/1.11.2.1
- Date: Fri, 21 Apr 2017 14:27:16 GMT
- Content-Type: application/octet-stream
- Transfer-Encoding: chunked
- Connection: keep-alive
- ```
-#### ngx Lua APi 介绍使用
-+ 强烈建议使用ngx Lua APi 接口`(非阻塞的)`,而不是Lua自身的API`(阻塞的)`,Lua 自身API会阻塞掉的
-+ ngx_lua_api_test.lua
- ```Lua
- local json = require "cjson" -- 引入cjson 扩展
-
- -- 同步读取客户端请求正文,而不会阻止Nginx事件循环
- ngx.req.read_body()
- local args = ngx.req.get_post_args()
-
- if not args or not args.info then
- ngx.say(ngx.HTTP_BAD_REQUEST) -- ngx.HTTP_BAD_REQUEST (400)
- end
-
- local client_id = ngx.var.remote_addr
- local user_agent = ngx.req.get_headers()['user-agent'] or ""
- local info = ngx.decode_base64(args.info)
-
- local response = {}
- response.info = info
- response.client_id = client_id
- response.user_agent = user_agent
-
- ngx.say(json.encode(response))
-
- ```
-+ CURL Post 请求
- ```Lua
- $ curl -i --data "info=b3ZlcmNvbWUud2FuQGdtYWlsLmNvbQ==" http://127.0.0.1/ngx_lua_api_test
- HTTP/1.1 200 OK
- Server: openresty/1.11.2.1
- Date: Sat, 22 Apr 2017 01:22:07 GMT
- Content-Type: application/octet-stream
- Transfer-Encoding: chunked
- Connection: keep-alive
-
- {"user_agent":"curl\/7.47.0","info":"overcome.wan@gmail.com","client_id":"127.0.0.1"}
-
- ```
-#### OpenResty缓存
-+ 指令:`lua_shared_dict`
- + 纯内存的操作,多个worker之间共享的(比如nginx开启10个Worker,则每个worker之间是共享该内存的)
- + 同一份数据在多个worker之间是共享的,只要存储一份数据就可以了
- + 锁的竞争(数据原子性)
-#### lua-resty-upstream-healthcheck使用
-+ health.txt 在每个upstream 服务器组的root 目录下创建这个文件,目录结构如下所示
- ```javascript
- ├── html
- │ ├── 50x.html
- │ ├── index.html
- │ ├── websocket001.html
- │ └── websocket02.html
- ├── html81
- │ ├── 50x.html
- │ ├── health.txt
- │ └── index.html
- ├── html82
- │ ├── 50x.html
- │ ├── health.txt
- │ └── index.html
- ├── html83
- │ ├── 50x.html
- │ ├── health.txt
- │ └── index.html
- ├── html84
- │ ├── 50x.html
- │ └── index.html
- ```
-+ nginx.conf
- ```Lua
- worker_processes 8;
-
- error_log logs/error.log;
- pid logs/nginx.pid;
-
- events {
- use epoll;
- worker_connections 1024;
- }
-
- http {
- include mime.types;
- default_type text/html;
- #lua模块路径,其中”;;”表示默认搜索路径,默认到/usr/servers/nginx下找
- lua_package_path "/home/tinywan/Openresty_Protect/First_Protect/lualib/?.lua;;"; #lua 模块
- lua_package_cpath "/home/tinywan/Openresty_Protect/First_Protect/lualib/?.so;;"; #c模块
- include /home/tinywan/Openresty_Protect/First_Protect/nginx_first.conf;
- }
-
- ```
-+ nginx_first.conf
- ```Lua
- upstream tomcat {
- server 127.0.0.1:8081;
- server 127.0.0.1:8082;
- server 127.0.0.1:8083;
- server 127.0.0.1:8084 backup;
- }
-
- lua_shared_dict healthcheck 1m;
-
- lua_socket_log_errors off;
-
- init_worker_by_lua_block {
- local hc = require "resty.upstream.healthcheck"
- local ok, err = hc.spawn_checker{
- shm = "healthcheck", -- defined by "lua_shared_dict"
- upstream = "tomcat", -- defined by "upstream"
- type = "http",
-
- http_req = "GET /health.txt HTTP/1.0\r\nHost: tomcat\r\n\r\n",
- -- raw HTTP request for checking
-
- interval = 2000, -- run the check cycle every 2 sec
- timeout = 1000, -- 1 sec is the timeout for network operations
- fall = 3, -- # of successive failures before turning a peer down
- rise = 2, -- # of successive successes before turning a peer up
- valid_statuses = {200, 302}, -- a list valid HTTP status code
- concurrency = 10, -- concurrency level for test requests
- }
- }
-
- server {
- listen 80;
- server_name localhost;
-
- location / {
- proxy_pass http://tomcat;
- }
-
- location /server/status {
- access_log off;
- allow 127.0.0.1;
-
- default_type text/plain;
- content_by_lua_block {
- local hc = require "resty.upstream.healthcheck"
- ngx.say("Nginx Worker PID: ", ngx.worker.pid())
- ngx.print(hc.status_page())
- }
- }
- }
-
- server {
- listen 8081;
- server_name localhost;
-
- location / {
- root html81;
- index index.html index.htm;
- }
-
- location /health_status {
-
- }
- }
-
- server {
- listen 8082;
- server_name localhost;
-
- location / {
- root html82;
- index index.html index.htm;
- }
-
- location /health_status {
-
- }
- }
-
- server {
- listen 8083;
- server_name localhost;
-
- location / {
- root html83;
- index index.html index.htm;
- }
-
- location /health_status {
-
- }
- }
-
- server {
- listen 8084;
- server_name localhost;
-
- location / {
- root html84;
- index index.html index.htm;
- }
- }
-
- ```
-+ 状态查看,通过访问:`http://127.0.0.1/server/status`
- 
-#### Openresty和Nginx_RTMP 模块共存问题
-+ RTMP 流的状态(stat.xsl)不生效Bug 问题
- - 1. 修改完nginx.conf 配置文件
- - 1. ~~执行:`nginx -s reload` 会不起作用~~
- - 2. 一定要执行以下命令:杀掉所有nginx进程`sudo killall nginx ` 重启即可`sbin/nignx`
-#### 配置RTMP模块的多worker直播流
-+ 配置文件,[Multi-worker live streaming官方文档](https://github.com/arut/nginx-rtmp-module/wiki/Directives#multi-worker-live-streaming)
- ```Shell
- user www www;
- worker_processes auto;
- error_log logs/error.log debug;
-
- pid /var/run/nginx.pid;
- events {
- use epoll;
- worker_connections 1024;
- multi_accept on;
- }
-
- rtmp_auto_push on;
- rtmp_auto_push_reconnect 1s;
- rtmp_socket_dir /var/sock;
- rtmp {
- server {
- listen 1935;
- application live {
- live on;
- }
- }
- }
- ```
+ [nginx 并发数问题思考:worker_connections,worker_processes与 max clients](http://liuqunying.blog.51cto.com/3984207/1420556?utm_source=tuicool)
+ 从用户的角度,http 1.1协议下,由于浏览器默认使用两个并发连接,因此计算方法:
1. nginx作为http服务器的时候:
diff --git a/README_BAK.md b/README_BAK.md
new file mode 100644
index 0000000..288d3f5
--- /dev/null
+++ b/README_BAK.md
@@ -0,0 +1,1961 @@
+## 目录
++ [Nginx基础知识](#Nginx_base_knowledge)
++ [Linux基础知识](#Linux_base_knowledge)
++ [Redis基础知识](#Redis_base_knowledge)
+ + [Redis 简易安装教程](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis/redis-install.md)
+ + [Redis执行Lua脚本基本用法](#Redis_Run_Lua)
++ [PHP脚本](#PHP_base_knowledge)
+ + [PHP脚本运行Redis](#PHP_Run_Redis)
++ [Shell脚本](#Shell_base_knowledge)
+ - [x] 编写快速安全Bash脚本的建议
+ - [x] Shell脚本实现分日志级别记录日志
+ - [x] Nginx日志定时备份和删除
+ - [x] SHELL脚本小技巧
+ - [x] Mysql 自动备份脚本安全加锁机制
++ [Lua基础知识](#Lua_base_knowledge)
+ + [Lua 基础语法](#Lua-base)
+ + [luajit 执行文件默认安装路径](#Nginx_base_knowledge)
+ + [Table 操作常用的方法](#Lua_table)
+ - [x] table.concat()
+ - [x] table.insert()
+ - [x] table.maxn()
+ - [x] table.concat()
+ + [Lua 模块与包](#Lua_module_package)
+ + [lua中self.__index = self 详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/oop/self__index.md)
++ [流媒体视频直播、点播](#live_base_knowledge)
++ [Nginx高性能WEB服务器详解](#Nginx_Web_knowledge)
+ + [第一章 初探 ](#Nginx_Web1_knowledge)
+ + [第二章 安装部署](#Nginx_Web2_knowledge)
+ + [第三章 架构初探 ](#Nginx_Web3_knowledge)
+ + [第四章 高级配置 ](#Nginx_Web4_knowledge)
+ + [第五章 Gzip压缩](#Nginx_Web5_knowledge)
+ + [第六章 Rewrite 功能](#Nginx_Web6_knowledge)
+ + [第七章 代理服务 ](#Nginx_Web7_knowledge)
+ + [第八章 缓存机制 ](#Nginx_Web8_knowledge)
++ [Openresty 学习](#Openresty_web_knowledge)
+ + [安装](#Openresty_install_knowledge)
+ + [默认配置信息](#Openresty_config_knowledge)
+ + [Lua require 绝对和相对路径(已经解决)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-common-package/lua-require.md)
+ + [luajit 执行文件默认安装路径](#Openresty_web_knowledge)
+ + [lua-resty-redis 扩展](#Openresty_resty-redis)
+ + [lua-resty-websocket 扩展](#Openresty_resty-websocket)
+ + [lua-cjson 扩展](#Openresty_resty-cjson)
+ + [lua-dkjson 扩展](https://github.com/Tinywan/lua_project_v0.01)
+ + [Lua 权限验证](#Openresty_resty-access)
+ + [lua-resty-string 扩展](#Openresty_resty-string)
+ + [lua-resty-http 扩展 ](#Openresty_resty-http)
+ + [lua-resty-mysql 扩展](#Openresty_resty-mysql)
+ + [lua-resty-shell 扩展](http://www.cnblogs.com/tinywan/p/6809879.html)
+ + [lua-resty-template 扩展](https://github.com/Tinywan/lua_project_v0.01)
+ + [lua-resty-template 扩展](https://github.com/Tinywan/lua_project_v0.01)
+ + [openresty扫描代码全局变量](#Openresty_all-var)
+ + [ngx Lua APi 方法和常量](#Openresty_http_status_constants)
+ + ngx_lua 核心常量
+ + ngx_lua 方法
+ + Lua HTTP状态常量
+ + 错误日志级别常量
+ + API中的常用方法
+ + [ngx Lua APi 介绍使用](#Openresty_ngx_api_used)
+ + [连接数据库](#Openresty_connent_redis)
+ + [OpenResty缓存](#Openresty_connent_cache)
+ + [lua-resty-upstream-healthcheck 使用](#Openresty_lua_resty_upstream_healthcheck)
+ + [Openresty和Nginx_RTMP 模块共存问题](#Openresty_rtmp_share)
+ + [Openresty配置RTMP模块的多worker直播流](#Openresty_rtmp_more_worker)
+ + [Openresty配置RTMP模块的推流地址鉴权实例](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Openresty_rtmp_obs_push.md)
+ + [Ngx_lua 写入Redis数据,通过CURL请求](#Ngx_lua_write_Redis)
+ + [Nginx编写的Lua接口使用URL过期和签名验证机制过滤非法访问接口](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Openresty_rtmp_obs_push_auth.md)
+ + [Nginx查看并发连接数](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/nginx_status.md)
++ [Redis 开发与运维](#Redis-DevOps)
+ - [ ] [第一章 初始Redis ](#Redis-DevOps-1)
+ - [ ] [第二章 API的理解和使用](#Redis-DevOps-2)
+ - [ ] [第三章 小功能大用处 ](#Redis-DevOps-3)
+ - [ ] [第四章 客户端 ](#Redis-DevOps-4)
+ - [ ] [第五章 持久化](#Redis-DevOps-5)
+ - [ ] [第六章 复制](#Redis-DevOps-6)
+ - [ ] [第七章 Redis 的恶魔 ](#Redis-DevOps-7)
+ - [ ] [第八章 理解内存 ](#Redis-DevOps-8)
++ [Copyright and License](#Copyright_and_License)
+## 开发过程记录
++ [解决 Visual Studio Code 向github提交代码不用输入帐号密码](#githubpush)
++ phase的意义:就是几个MR的一个集合,不定数目的MR job视为一个phase。一个请求经过nginx处理的过程中,会经过一系列的阶段(phases)
+## Nginx基础知识
++ [NGINX 所有 Modules](https://www.nginx.com/resources/wiki/modules/)
++ [Nginx 配置文件 nginx.conf 详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-base-config.md)
+#### agentzh的Nginx教程(版本2016.07.21)
++ [agentzh的Nginx教程地址](https://openresty.org/download/agentzh-nginx-tutorials-zhcn.html)
++ Nginx 变量漫谈(一)
+ + Nginx 变量的值只有一种类型,那就是字符串
+ + Nginx “变量插值”
+ ```bash
+ location /test {
+ set $first "hello ";
+ echo "${first}world";
+ }
+ ```
+ + set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时
+ + Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块
+ + Nginx 变量的生命期是不可能跨越请求边界的
++ Nginx 变量漫谈(二)
+ + 跳转
+ + 内部跳转:就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。
+ + 外部跳转: HTTP 状态码 301 和 302 所进行的“外部跳转”
+ + 标准 ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”
+ + Nginx 核心和各个 Nginx 模块提供的“预定义变量”
+ + Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式
+ + 如果你尝试改写另外一些只读的内建变量,比如 $arg_XXX 变量,在某些 Nginx 的版本中甚至可能导致进程崩溃。
++ Nginx 变量漫谈(四)
+ + map 指令:用于定义两个 Nginx 变量之间的映射关系,或者说是函数关系
+ + map 指令只能在 http 块中使用
+ + map 配置指令的工作原理是为用户变量注册 “取处理程序”,并且实际的映射计算是在“取处理程序”中完成的,而“取处理程序”只有在该用户变量被实际读取时才会执行(当然,因为缓存的存在,只在请求生命期中的第一次读取中才被执行),所以对于那些根本没有用到相关变量的请求来说,就根本不会执行任何的无用计算。
++ Nginx 变量漫谈(四)
++ [Nginx的11个Phases](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-phases.md)
++ [Nginx 陷阱和常见错误](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-1-config.md)
++ [Nginx 高并发系统内核优化](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-parameter-config.md)
+
+## Redis基础知识
++ [Redis 简易安装教程](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis/redis-install.md)
+## PHP脚本
++ [PHP7中php.ini/php-fpm/www.conf的配置,Nginx和PHP-FPM的开机自动启动脚本](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/PHP/PHP-FPM/config.md)
+## Shell脚本
++ [编写快速安全Bash脚本的建议](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Shell/write-shell-suggestions.md)
++ [shell脚本实现分日志级别记录日志](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_Log.sh)
++ [Nginx日志定时备份和删除](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_Nginx_Log_cut.sh)
++ [SHELL脚本小技巧](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/Shell_script.md)
++ [Mysql 自动备份脚本安全加锁机制](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/backup_mysql.sh)
+## Lua基础知识
+#### Lua 基础语法
++ 删除一个全局变量,只要将变量值赋值为nil:`a = nil`,当且仅当一个变量不为nil 时,这个变量存在
++ `Boolean`类型:在控制条件中除了`false`和`nil` 为假,其他值都为真,所以lua认为0和空字符串也是真
++ `String`类型:
+ + 字符串替换:`string.gsub()`
+ ```lua
+ a = 'one HELLO'
+ b = string.gsub(a,'one','two')
+ print(a) -- one HELLO
+ print(b) -- two HELLO
+ ```
+ + 字符串和数字
+ ```lua
+ print("10" + 1) -- 11
+ print("10" + "1") -- 11
+ print("10 + 1") -- 10 + 1
+ print("hello " .. " world") -- hello world
+ --print("hello" + 1) -- 错误写法
+ ```
+ + 字符串和数字转换
+ ```lua
+ a = 10
+ print(tostring(a)) -- 10
+ b = "20"
+ print(tonumber(b)) -- "20"
+
+ print(tostring(10) == "10") -- true
+ print(10 .. "" == "10") -- true
+ ```
++ 表达式
+ + 如果两个值类型不相等,Lua认为两者不同
+ + nil 只和自己相等
+ + 逻辑运算符
+ ```lua
+ -- a and b -- 如果a为false,则返回a ,否则返回b
+ -- a or b -- 如果a为true,则返回a ,否则返回b
+ print(4 and 5) -- 5
+ print(nil and 12 ) -- nill
+ print(false and 12) -- false
+ print(4 or 5) -- 4
+ print(false or 5) -- 5
+ ```
+ + 注意:`and`的优先级比`or`高
+ + Lua 三元运算符:`( a and b) or c`
++ 变量
+ + 赋值语句
+ ```lua
+ x = 20
+ y = 30
+ x,y = y,x
+ print(x,y) -- 30 20
+
+ a,b,c = 10,20
+ print(a,b,c) --10 20 nil
+
+ x,y,z = 10
+ print(x,y,z) -- 10 nil nil
+ ```
+ + 局部变量与代码块
+ + 代码块:指一个控制结构内,一个函数体,或者一个chunk(变量被声明的哪个文件或者文本串)
+ + ```lua
+ a = 12
+ if a>10 then
+ local i = 19
+ print(i) -- 19
+ end
+ print(i) -- nil
+ ```
++ 控制语句
+ ```lua
+ members = { Tom = 10, Jake = 11, Dodo = 12, Jhon = 16 }
+
+ for k, v in pairs(members) do
+ if v == 10 then
+ print(k, 'is 10 years old') -- Tom is 10 years old
+ elseif v == 11 then
+ print(k, 'is 11 years old') -- Jake is 11 years old
+ elseif v == 12 then
+ print(k, 'is 12 years old') -- Dodo is 12 years old
+ else
+ print(k, "is not 10,11,12 years old") -- Jhon is not 10,11,12 years old
+ end
+ end
+ ```
++ 函数
+ + 单个返回值
+ ```lua
+ function max(a,b)
+ if a > b then
+ return a
+ else
+ return b
+ end
+ end
+ print(max(10,20)) -- 20
+ ```
+ + 多个返回值
+ ```lua
+ function more()
+ return 10 , 20 ,30
+ end
+ a , b , c = more()
+ print(a,b,c) -- 10 20 30
+ ```
+ + 可变数目的参数
+ ```lua
+ function more()
+ return 10 , 20 ,30
+ end
+ -- 当函数位于最后一位的时候,返回全部值,否则值返回一个数值
+ a , b , c ,d = 100, more()
+ print(a,b,c,d) -- 100 10 20 30
+ ```
+ + 闭合函数
+ ```lua
+ function count()
+ -- i属于一个非局部变量,因为它既不是全局变量,也不是单纯的局部变量(因为另外一个函数可以访问到它)
+ local i = 0
+ return function()
+ i =i +1
+ return i
+ end
+ end
+ -- 以上 count()函数里的那个函数,加上一个非全局变量i,就构成一个闭合函数
+ -- 所以每次调用闭合函数,非局部变量的值都不会被重置
+ local func = count()
+ print(func()) -- 1
+ print(func()) -- 2
+ ```
+ + 非全局函数,在定义函数的使用要注意定义函数的顺序
+ ```lua
+ local eat
+ local drink
+ eat = function()
+ print("eat")
+ return drink() -- 这里的drink()属于尾调用
+ end
+ drink = function()
+ print("drink")
+ end
+ eat()
+ ```
++ table 使用
+ + Lua table 第一个索引为1
+ + 简单
+ ```lua
+ a = {}
+ a.x = 100
+ a.y = 200
+ a["z"] = 300 -- a.z = 300
+ print(a.x) -- 100
+ print(a.y) -- 200
+ print(a.z) -- 300
+ ```
++ 泛型迭代器
+ + 标准库迭代器包括:
+ + 迭代文件每行:`io.lines`
+ + 迭代table元素:`pairs`
+ - [x] 可以遍历表中的所有key
+ - [x] 并且除了迭代器本身以及遍历表本身,还可以返回nil
+ + 迭代数组元素:`ipairs`
+ - [x] ipairs不能返回nil,只能返回数字0,如果遇到nil则退出
+ - [x] 只能遍历表中出现的第一个不是整数的key
+ + 泛型迭代器
+ ```lua
+ config = {host = '127.0.0.1',port = '3306', dbname = 'LuaDB' }
+ config.redis_host = "192.168.1.1"
+ config.redis_port = "6379"
+ config.redis_db = "12"
+ print(config['redis_host']) -- 192.168.1.1
+ print(config.redis_port) -- 6379
+ print(config.dbname) -- LuaDB
+
+ for k, v in pairs(config) do
+ print(k,v)
+ end
+
+ --[[
+ host 127.0.0.1
+ dbname LuaDB
+ redis_host 192.168.1.1
+ redis_db 12
+ redis_port 6379
+ port 3306
+ -- ]]
+ ```
+ + 迭代table元素
+ ```lua
+ arr = {}
+ for var = 1,100 do -- for 循环
+ table.insert(arr,1,var)
+ end
+
+ for k, v in pairs(arr) do -- 遍历表
+ print(k,v)
+ end
+ --[[ 打印结果
+ 1 100
+ 2 99
+ ... ...
+ 99 2
+ 100 1
+
+ -- ]]
+ print(table.maxn(arr)) -- table长度 100
+ print(#arr) -- table长度(快捷方式) 100
+ ```
+ + 迭代数组元素:`ipairs`
+ ```lua
+ arr = {host = '127.0.0.1',port = '3306','Tinywan'}
+ -- 如果没有找到下标为整数的则直接退出,是整数的则直接输出,如上面的'Tinywan'
+ for k, v in ipairs(arr) do -- 只能遍历key 为整数的下标
+ print(k,v) -- 1 Tinywan
+ end
+ ```
+ + 循环迭代table元素(如:lua-resty-mysql 扩展查询的数据)
+ + 查询 :`res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)`
+ + 转换成JSON结果集输出2条记录:
+ ```lua
+ ngx.say("result: ", cjson.encode(res))
+ result: [{"age":"24123","name":"tinywan123","address":"China","id":"1"},{"age":"24","name":"tinywan","address":"China","id":"2"}]
+ ```
+ + 遍历该结果集:
+ ```lua
+ res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)
+ if not res then
+ ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
+ return
+ end
+
+ for k, v in pairs(res) do
+ if type(v) == "table" then
+ for new_table_index, new_table_value in pairs(v) do
+ ngx.say(new_table_index.." = "..new_table_value)
+ end
+ else
+ ngx.say(k,v)
+ end
+ end
+
+ --[[ 打印结果
+ age = 24123
+ name = tinywan123
+ address = China
+ id = 1
+ age = 24
+ name = tinywan
+ address = China
+ id = 2
+ ]]
+ ```
+ + json 和 lua table 转换
+ + [1] 将 json 转换成 lua table
+ ```lua
+ local json_str = '{"is_male":"nan","name":"zhangsan","id":1}'
+ local t = json.decode(json_str)
+ ngx.say(format_table(t))
+ ```
+ + [2] 将 lua table 转换成 json 字符串
+ ```lua
+ local t = [[{key="table key",value="table value"}]]
+ local json_str = json.encode(t)
+ ngx.say(json_str) -- "{key=\"table key\",value=\"table value\"}"
+ ```
+ + [3] 将lua table转换成 json 数组 (lua 两个大括号表示一个数组)
+ ```lua
+ local t = {keys={"list1","list2","list3"},num=1}
+ local str = json.encode(t)
+ ngx.say(str) -- {"keys":["list1","list2","list3"],"num":1}
+ ```
++ 编译执行与错误
+ + error 错误
+ ```lua
+ local name = "Lua1"
+ if name ~= "Lua"
+ then
+ error("this is not Lua ");
+ end
+ ```
+ + assert 错误:`assert(name~="Lua"," this is not Lua")`
+ + pcall 捕获错误代码
+ ```lua
+ function test()
+ print(a[1])
+ end
+ -- pcall 除了会返回true或者false外,还能返回函数的错误信息。
+ -- 如果没有错误信息,err 会返回一个nil
+ local status,err = pcall(test)
+ if status then
+ print('success')
+ else
+ print('函数执行出错了')
+ print('错误信息:',err)
+ end
+ ```
++ Lua面向对象(重点)
+ + [博客详细地址描述](http://www.cnblogs.com/tinywan/p/6940784.html)
+ + :white_check_mark: `__add` 元方法 #demo1
+ ```lua
+ local mt = {}
+ mt.__add = function(t1, t2)
+ print("两个Table 相加的时候会调用我")
+ end
+ local t1 = {}
+ local t2 = {}
+ -- 给两个table 设置新的元表,一个元表就是一个table的值
+ setmetatable(t1, mt) -- meta:元素
+ setmetatable(t2, mt)
+ -- 进行相加操作
+ local t = t1 + t2
+ print(t)
+
+ --[[输出结果
+ 两个Table 相加的时候会调用我
+ nil
+ --]]
+ ```
+ + :white_check_mark: `__add` 元方法 #demo2
+ ```lua
+ -- 创建一个元表 (是创建一个类吗?)
+ local mt = {}
+ mt.__add = function(s1, s2)
+ local result = ""
+ if s1.sex == "boy" and s2.sex == "girl" then
+ result = "一个男孩和一个女孩的家庭"
+ elseif s1.sex == "girl" and s2.sex == "girl" then
+ result = "两个女孩的家庭"
+ else
+ result = "未知孩子的家庭"
+ end
+ return result
+ end
+ -- 创建两个table,可以想象成是两个类的对象(实例化两个类)
+ local s1 = { name = "Per1", sex = "boy" }
+ local s2 = { name = "Per2", sex = "girl" }
+ -- 给两个table 设置新的元表,一个元表就是一个table的值
+ setmetatable(s1, mt)
+ setmetatable(s2, mt)
+ -- 进行加法操作
+ local result = s1 + s2
+ print(result)
+
+ -- 输出结果 一个男孩和一个女孩的家庭
+ ```
+ + :white_check_mark: `__index` 元方法 #demo1
+ ```lua
+ local t = {
+ name = "Tinywan"
+ }
+ local mt = {
+ __index = function(table, key)
+ print("虽然你调用了我不存在的字段和方法,不过没关系,我能检测出来" .. key)
+ end
+ }
+ setmetatable(t, mt)
+ print(t.name)
+ print(t.age)
+
+ --[[输出结果
+ -- Tinywan
+ -- 虽然你调用了我不存在的字段和方法,不过没关系,我能检测出来age
+ -- nil
+ ---- ]]
+ ```
+ + :white_check_mark: `__index` 元方法 #demo2
+ ```lua
+ local t = {
+ name = "Tinywan"
+ }
+ local mt = {
+ money = 808080
+ }
+
+ mt.__index = mt
+ setmetatable(t, mt)
+ print(t.money)
+ -- 输出结果 808080
+ ```
+ + :white_check_mark: `__index` 元方法 #demo3
+ ```lua
+ local t = {
+ name = "Tinywan"
+ }
+ local mt = {
+ __index = {
+ money = 909090
+ }
+ }
+ setmetatable(t, mt)
+ print(t.money)
+ -- 输出结果 909090
+ ```
+ + :white_check_mark: `__index` 元方法 #demo4
+ ```lua
+ local smartMan = {
+ name = "Tinywan",
+ age = 26,
+ money = 800000,
+ say_fun = function()
+ print("Tinywan say 大家好")
+ end
+ }
+
+ local t1 = {}
+ local t2 = {}
+ local mt = { __index = smartMan } -- __index 可以是一个表,也可以是一个函数
+ setmetatable(t1, mt)
+ setmetatable(t2, mt)
+ print(t1.money)
+ t2.say_fun()
+ --- 输出结果
+ -- 800000
+ -- Tinywan say 大家好
+ ```
+ + Lua面向对象1
+ + Lua面向对象1
+ + Lua面向对象3 更新中...
++ Lua 排序算法
+ + [Lua 排序算法 - 选择排序](https://www.openresty.com.cn/ms2008-select-sort.html#section-1)
+ + 选择排序
+ ```lua
+ local function selectionSort(arr)
+ for i = 1,#arr-1 do
+ local idx = i
+ -- 迭代剩下的元素,寻找最小的元素
+ for j = i+1,#arr do
+ if arr[j] < arr[idx] then
+ idx = j
+ end
+ end
+ --
+ arr[i],arr[idx]= arr[idx],arr[i]
+ end
+ end
+
+ local list = {
+ -81, -93, -36.85, -53, -31, 79, 45.94, 36, 94, -95.03, 11, 56, 23, -39,
+ 14, 1, -20.1, -21, 91, 31, 91, -23, 36.5, 44, 82, -30, 51, 96, 64, -41
+ }
+
+ selectionSort(list)
+ print(table.concat( list, ", "))
+ ```
+#### 控制结构
++ [if-elseif-end 语句](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/if-else-example.lua)
++ [for 语句](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/for-example.lua)
++ [Lua 只有一个容器,那就是table](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/chapter-one/container-table.lua)
+#### [Lua 实现简单封装](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Lua-Script/function1.lua)
+#### Table 操作常用的方法
++ table.concat (table [, sep [, start [, end]]])
+ + concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开
+ + demo
+ ```lua
+ fruits = {"banana","orange","apple"}
+ -- 返回 table 连接后的字符串 value = banana orange apple
+ print("连接后的字符串 ",table.concat(fruits))
+ -- 指定连接字符 value = banana, orange, apple
+ print("指定连接字符连接后的字符串 ",table.concat(fruits,", "))
+ ```
++ table.insert (table, [pos,] value):
+ + 在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾
+ + demo
+ ```lua
+ fruits = {"banana","orange","apple"}
+
+ -- 在末尾插入
+ table.insert(fruits,"Tinywan4")
+ print("索引为 4 的元素为 ",fruits[4]) -- 索引为 4 的元素为 Tinywan
+
+ -- 在索引为 2 的键处插入
+ table.insert(fruits,2,'Tinywan2')
+ print("索引为 2 的元素为 ",fruits[2]) -- 索引为 2 的元素为 Tinywan
+
+ print("最后一个元素为 ",fruits[5]) -- 最后一个元素为 Tinywan4
+ table.remove(fruits)
+ print("移除后最后一个元素为 ",fruits[5]) -- 移除后最后一个元素为 nil
+ ```
++ table.sort (table [, comp])
+ + 对给定的table进行升序排序
+#### Lua 模块与包
++ 定义:Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行.
+## 流媒体视频直播、点播
++ [Nginx配置Rtmp支持Hls的直播和点播功能](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/HLS-live-vod.md)
++ [HLS视频直播和点播的Nginx的Location的配置信息(成功)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Rtmp/HLS-live-vod-locatiuon-config.md)
+
+## Nginx高性能WEB服务器详解
+#### 第一章 初探
++ [Nginx 编译安装以及参数详解](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-2-config.md)
++ NGINX变量详解
+ - [x] [nginx变量使用方法详解笔记(1)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/notes-1.md)
+ - [x] [nginx变量使用方法详解笔记(2)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/notes-2.md)
+ - [x] [nginx变量使用方法详解笔记(3)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/nginx-2-config.md)
++ Nginx指令执行顺序
+ - [x] [Nginx指令执行命令(01)](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx-Develop/command-order-01.md)
+#### 第二章 安装部署
++ 启动错误:`Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)`,执行:`sudo fuser -k 80/tcp`
++ [基于域名、IP的虚拟主机配置](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-all-config.md)
++ [完整、标准配置实际示列](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-basic-config.md)
++ [日志文件配置与切割](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-4-log-cut.md)
++ alias 和 root 在location 下的应用
+ - 通过alias 实现别名功能
+ ```
+ location /live {
+ alias /home/tinywan/HLS/;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS$ cat index.html
+ alias /home/tinywan/HLS/index.html
+ tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/index.html
+ alias /home/tinywan/HLS/index.html
+ ```
+ - 结论:
+ 1. cul 请求 `/live/index.html`,那么Nginx将会在服务器上查找`/home/tinywan/HLS/index.html` 文件
+ 1. 请求的`url` 中的`location`后面的部分会被追加到`alias `指定的目录后面,而`location`后面的`/live`路径将会别自动抛弃
+ - 类似案例[2]:
+ - config配置信息
+ ```
+ location ~ ^/live/(.*)$ {
+ alias /home/tinywan/HLS/$1;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS$ pwd
+ /home/tinywan/HLS
+ tinywan@tinywan:~/HLS$ cat txt.txt
+ txt file
+ tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
+ txt file
+ ```
+ - 如果url请求`/live/txt.txt`那么Nginx将会在服务器上查找`/home/tinywan/HLS/txt.txt` 文件
+ - **与root 功能的差别**:
+ - config配置信息,注意:一下的`alias` 换成 `root `
+ ```
+ location ~ ^/live/(.*)$ {
+ root /home/tinywan/HLS/$1;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
+
+ 404 Not Found
+
+ 404 Not Found
+
openresty/1.11.2.1
+
+
+ ```
+ - 日志文件信息(打开Nginx的rewrite日志:rewrite_log on;):
+ ```
+ /home/tinywan/HLS/txt.txt/live/txt.txt
+ ```
+ - **二者的区别**
+ 1. `alias` 指定的目录是当前目录
+ 1. `root` 指定的是根目录
+ 1. 一般建议的`location /`中通过`root`命令配置目录,其他目录匹配的位置使用`alias`命令
+ - 案例[3]:
+ - config配置信息
+ ```
+ location ~ ^/live/(\w+)/(.*) {
+ alias /home/tinywan/HLS/live/$1/$2;
+ }
+ ```
+ - curl 请求结果
+ ```
+ tinywan@tinywan:~/HLS/live/stream123$ pwd
+ /home/tinywan/HLS/live/stream123
+ tinywan@tinywan:~/HLS/live/stream123$ cat index.m3u8
+ 12312312312
+ tinywan@tinywan:~/HLS/live/stream123$ curl "http://127.0.0.1/live/stream123/index.m3u8?token=1234&api=009132"
+ 12312312312
+ ```
+#### 第三章 架构初探
+- [ ] 测试一
+#### 第四章 高级配置
++ 基本语法:location [=|~|~*|^~] /uri/ { … }
+ 1. `= `:严格匹配。如果这个查询匹配,那么将停止搜索并立即处理此请求。
+ 2. `~ `:为区分大小写匹配(可用正则表达式)
+ 3. `!~ `:为区分大小写不匹配
+ 4. `!~*`:为不区分大小写不匹配
+ 5. ` ^~ `:如果把这个前缀用于一个常规字符串,那么告诉nginx 如果路径匹配那么不测试正则表达式
++ [Perl 正则表达式参考](http://www.runoob.com/perl/perl-regular-expressions.html)
++ 正则中需要转义的特殊字符小结
+ - [1] ` $` 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n' 或 ‘\r'。要匹配 $ 字符本身,请使用 \$。
+ - [2] ` ( )` 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 和。
+ - [3] ` * ` 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+ - [4] ` +` 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
+ - [5] ` . ` 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
+ - [6] ` [ ]` 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
+ - [7] ` ? ` 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
+ - [8] ` \ ` 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n' 匹配字符 ‘n'。'\n' 匹配换行符。序列 ‘\\' 匹配 “\”,而 ‘\(' 则匹配 “(”。
+ - [9] ` ^ ` 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
+ - [10] ` { }` 标记限定符表达式的开始。要匹配 {,请使用 \{。
+ - [11] ` | ` 指明两项之间的一个选择。要匹配 |,请使用 \|。
+
++ 正则表达式 (Regular expression) 匹配location
+ - [1] `location ~* \.(gif|jpg|jpeg)$ { }`:匹配所有以 gif,jpg或jpeg 结尾的请求
+ - [2] `location ~ /documents/Abc { }`:匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
+ - [3] **目录匹配:**
+ 1. 可以匹配静态文件目录`(static/lib)`
+ 2. HLS直播目录`(/home/HLS/stream123/index.m3u8)`
+ 3. HLS/MP4/FLV点播视频目录`(/home/HLS/stream123.m3u8)`
+ 4. 匹配URL地址:`http://127.0.0.1/live/stream123/index.m3u8`
+ 5. nginx.conf 配置信息
+ ```
+ # 匹配任何以/live/ 开头的任何查询并且停止搜索。任何正则表达式将不会被测试
+ location ^~ /live/ {
+ root /home/tinywan/HLS/;
+ }
+ # 以上匹配成功后的组合:/home/tinywan/HLS/live/....
+ ```
++ 后缀匹配
+ 1. 匹配任何后缀文件名`gif|jpg|jpeg|png|css|js|ico|m3u8|ts` 结尾的请求
+ 2. TS 文件匹配`http://127.0.0.1/live/stream123/11.ts`
+ 3. M3U8 文件匹配`http://127.0.0.1/live/stream123/index.m3u8`
+ 4. 匹配URL地址:`http://127.0.0.1/hls/123.m3u8`
+ 5. nginx.conf 配置信息
+ ```
+ location ~* \.(gif|jpg|jpeg|png|css|js|ico|m3u8|ts)$ {
+ root /home/tinywan/HLS/;
+ }
+ ```
++ HSL直播目录匹配实际案例(请测试上线)
+ 1. 可以后缀文件名:`http://127.0.0.1/live/stream123/index.m3u8`
+ ```
+ location ^~ /live/ {
+ root /home/tinywan/HLS/;
+ }
+ ```
+
++ [nginx配置location总结及rewrite规则写法](http://seanlook.com/2015/05/17/nginx-location-rewrite/)
+#### 第五章 Gzip压缩
++ 测试一
+#### 第六章 Rewrite 功能
++ Rewrite 常用全局变量
+ + 请求案例: `curl -G -d "name=Tinywan&age=24" http://127.0.0.1/rewrite_var/1192/index.m3u8`
+ + 接受结果:
+
+ | 变量 | 值 |描述 |
+ | --------- | ----------- |----------- |
+ | $args | name=Tinywan&age=24 |存放URL 请求的指令 |
+ | $content_length | 0 | 请求头中的Content-length字段|
+ | $content_type | 0 |请求头中的Content-Type字段 |
+ | $document_root | /opt/openresty/nginx/html | 当前请求在root指令中指定的值 |
+ | $document_uri | /rewrite_var/1192/index.m3u8 | 与$uri相同 |
+ | $host | 127.0.0.1 |请求主机头字段,否则为服务器名称 |
+ | $http_user_agent | curl/7.47.0 | 客户端agent信息|
+ | $http_cookie | 0 | COOKIE变量的值|
+ | $limit_rate | 0 | 限制连接速率|
+ | $request_body_file | null | 客户端请求主体信息的临时文件名|
+ | $request_method | GET | 客户端请求的动作,通常为GET或POST |
+ | $remote_addr | 127.0.0.1 |客户端的IP地址 |
+ | $remote_port | 33516 |客户端端口|
+ | $remote_user | 0 | 已经经过Auth Basic Module验证的用户名|
+ | $request_filename | /opt/openresty/nginx/html/rewrite_var/1192/index.m3u8 |当前请求的文件路径 |
+ | $request_uri | /rewrite_var/1192/index.m3u8?name=Tinywan&age=24 |包含请求参数的原始URI,不包含主机名 |
+ | $query_string | name=Tinywan&age=24 | 与$args相同|
+ | $scheme | http |HTTP方法(如http,https |
+ | $server_protocol | HTTP/1.1 |请求使用的协议,通常是HTTP/1.0或HTTP/1.1 |
+ | $server_addr | 127.0.0.1 |服务器地址 |
+ | $server_name | localhost | 服务器名称|
+ | $server_port | 80 |请求到达服务器的端口号 |
+ | $uri | /rewrite_var/1192/index.m3u8 | 不带请求参数的当前URI|
+ | $binary_remote_addr | 乱码 | 二进制格式的客户端地址|
+
+ + uri 介绍 **(Nginx中的URI是相对的URI)**
+ + URL:`https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
+ + 绝对URI:`https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
+ + 相对URI:`/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md`
+ 
+
++ Rewrite 正则匹配` uri `参数接收
+ 1. 请求案例:`curl http://192.168.18.143/live/tinywan123/index.m3u8`
+ 2. Nginx.conf配置文件
+ ```Lua
+ location ~* ^/live/(\w+)/(\D+)\.(m3u8|ts)$ {
+ set $num $2;
+ set $arg1 $1;
+ echo "args === ${arg1}";
+ echo "1==$1 2==$2 3==$3";
+ echo "Total_numbser :: $num";
+ echo "URI $uri";
+ }
+
+ ```
+ 3. 输出结果
+ ```
+ args === tinywan123
+ $1==tinywan123 $2==index $3==m3u8
+ Total_numbser :: index
+ URI /live/tinywan123/index.m3u8
+ Total_numbser ::
+ ```
+ 4. $1为正则匹配多个英文字母或数字的字符串 `(\w+)`
+ $2 为正则匹配多个非数字 `(\D+)`
+ $3 为正则匹配的第一个值 `(m3u8|ts)`
+ `.` 需要用转义字符转义`\.`
+## 第七章 代理服务
++ [正向代理和反向代理的概念](#title)
++ [正向代理服务](#title)
++ [反向代理的服务](#title)
++ [Nginx日志服务](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-Log.md)
++ 负载均衡
++ HTTP负载均衡
+ - [x] [简单的负载平衡](http://nginx.org/en/docs/http/ngx_http_core_module.html?&_ga=1.179030369.49817296.1480411319#http)
+ - [x] [简单的负载平衡](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-7-Proxy-1.md)
+ - [x] [负载均衡五个配置实例](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-7-Proxy.md)
+ - [x] [Openresty-Lua动态修改upstream后端服务](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/openresty-nginx-lua-Proxy.md)
++ TCP负载均衡
+ - [x] [Module ngx_stream_core_module](http://nginx.org/en/docs/stream/ngx_stream_core_module.html#stream)
+ - [x] [负载均衡](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-8-tcp-Proxy.md)
++ proxy_pass 代理的URL总结
+ + 在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。
+ + 将url中以/wap/开头的请求转发到后台对应的某台server上,注意最后的?$args,表明把原始url最后的get参数也给代理到后台
+ ```bash
+ location ~* /wap/(\d+)/(.+)
+ {
+ proxy_pass http://mx$1.test.com:6601/$2?$args;
+ }
+ ```
+ + 第一种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/index.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000/;
+ }
+ ```
+ + 第二种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/proxy/index.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000;
+ }
+ ```
+ + 第三种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/video/index.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000/video/;
+ }
+ ```
+ + 第四种配置,访问:`http://127.0.0.1/proxy/index.html` 会被代理到:`http://127.0.0.1:8000/videoindex.html`
+ ```bash
+ location /proxy/ {
+ proxy_pass http://127.0.0.1:8000/video;
+ }
+ ```
++ location 直接访问:
+ + 以下配置,当访问:`http://127.0.0.1:8000/proxy/index.html` 会被匹配到:`/usr/local/nginx/html/proxy/index.html`
+ ```bash
+ location /proxy/ {
+ root /usr/local/nginx/html;
+ index index.html index.htm;
+ }
+ ```
+
+## 第八章 缓存机制
++ 测试一
+## 第九章 Nginx初探1
++ 测试一
+## 第十章 Nginx初探1
++ 测试一
+## PHP脚本运行Redis]
++ [PHP 脚本执行一个Redis 订阅功能,用于监听键过期事件,返回一个回调,API接受改事件](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis-PHP/Php-Run-Redis-psubscribe/nohupRedisNotify.php)
++ 单行文本1
+## Openresty 学习
++ [安装信息](http://www.cnblogs.com/tinywan/p/6647587.html)
++ [默认配置信息](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/default-config.md)
++ 开发入门
+ + Nginx与Lua的整体目录关系
+ ```javascript
+ .
+ ├── conf
+ │ ├── nginx.conf -- Nginx 配置文件
+ ├── logs
+ │ ├── error.log -- Nginx 错误日子
+ │ └── nginx.pid
+ ├── lua
+ │ ├── m3u8_redis_access.lua -- M3U8地址权限验证文件
+ │ ├── business_redis.lua -- 业务 Redis 处理文件
+ │ ├── http-lua-test.lua -- http lua demo
+ │ ├── ...
+ │ └── resty -- 存放Lua 的所有公共、封装好的库目录
+ │ └── redis_iresty.lua -- Redis 接口的二次封装
+ │ └── param.lua -- 参数过滤库
+ └── sbin
+ └── nginx
+ ```
+ + 参数总结
+ + Lua脚本接受Nginx变量:
+ > [1] 间接获取:`var = ngx.var `,如接受Nginx的变量` $a = 9`,则`lua_a = ngx.var.a --lua_a = 9`
+ [2] 直接获取:`var = ngx.var `,如接受Nginx的location的第二个变量890,` http://127.0.0.1/lua_request/123/890 `,则`lua_2 = ngx.var[2] --lua_2 = 890`
+ + Lua 脚本接受 Nginx 头部 header:
+ > [1] 返回一个包含所有当前请求标头的Lua表:`local headers = ngx.req.get_headers()`
+ [2] 获取单个Host:`headers["Host"] 或者 ngx.req.get_headers()["Host"] `
+ [3] 获取单个user-agent:
+ >> [01]`headers["user-agent"]`
+ [02]`headers.user_agent `
+ [03]`ngx.req.get_headers()['user-agent'] `
+ + Lua 脚本 Get 获取请求uri参数
+ > linux curl Get方式提交数据语法:`curl -G -d "name=value&name2=value2" https://github.com/Tinywan `
+ 返回一个包含所有当前请求URL查询参数的Lua表:`local get_args = ngx.req.get_uri_args()`
+ 请求案例:`curl -G -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789`
+ Lua Get 方式获取提交的name参数的值:`get_args['name'] 或者 ngx.req.get_uri_args()['name']`
+ >> [01]`get_args['name']`
+ [02]`ngx.req.get_uri_args()['name']`
+ + Lua 脚本 Post 获取请求uri参数
+ > linux curl Post方式提交数据语法:
+ >> [01] `curl -d "name=value&name2=value2" https://github.com/Tinywan `
+ [02] `curl -d a=b&c=d&txt@/tmp/txt https://github.com/Tinywan `
+ > 返回一个包含所有当前请求URL查询参数的Lua表:`local post_args = ngx.req.get_post_args()`
+ 请求案例:`curl -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789`
+ Lua Post 方式获取提交的name参数的值:
+ >> [01]`post_args['name']`
+ [02]`ngx.req.get_post_args()['name']`
+ + Lua 脚本请求的http协议版本:`ngx.req.http_version()`
+ + Lua 脚本请求方法:`ngx.req.get_method()`
+ + Lua 脚本原始的请求头内容:`ngx.req.raw_header()`
+ + Lua 脚本请求的body内容体:`ngx.req.get_body_data()`
+ + [接收请求:获取如请求参数、请求头、Body体等信息]()
+ + [接收请求:输出响应需要进行响应状态码、响应头和响应内容体的输出](
++ luajit 执行文件默认安装路径:`/opt/openresty/luajit/bin/luajit`,这样我们直接可以这样运行一个Lua文件:`luajit test.lua `
+ + luajit 运行测试案例:
+ ```Bash
+ tinywan@tinywan:~/Lua$ luajit test.lua
+ The man name is Tinywan
+ The man name is Phalcon
+ ```
+#### lua-resty-redis 扩展 (是openresty下操作redis的模块)
++ 代码引入:`lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/?.lua;;";`
++ Lua脚本实现一个CDN的反向代理功能(智能查找CDN节点)(测试成功,可上线)
+ + nginx.conf 配置信息
+ ```Lua
+ http {
+ lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/?.lua;;";
+ server {
+ listen 80;
+ server_name localhost;
+ location ~ \/.+\/.+\.(m3u8|ts) {
+ if ($uri ~ \/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)(|-).*\.(m3u8|ts)) {
+ set $app_name $1;
+ set $a $2;
+ }
+ set $stream_id "";
+ default_type 'text/html';
+ rewrite_by_lua_file /opt/openresty/nginx/lua/proxy_pass_cdn.lua;
+ proxy_connect_timeout 10;
+ proxy_send_timeout 30;
+ proxy_read_timeout 30;
+ proxy_pass $stream_id;
+ }
+
+ }
+ }
+ ```
+ + [Lua脚本proxy_pass_cdn.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/proxy_pass_cdn.lua)
+ + [lua-nginx-module 贡献代码](https://github.com/openresty/lua-nginx-module/issues/275)
+
++ Lua脚本结合 Nginx+Lua+Local Redis+Mysql服务器缓存
+ + Nginx+Lua+Local Redis+Mysql集群架构
+ + 
+ + [Lua脚本Nginx+Lua+Redis+Mysql.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+Mysql.lua)
+ + [Nginx.conf配置文件Nginx+Lua+Redis+Mysql.conf](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+Mysql.conf)
+ + [HELP](http://jinnianshilongnian.iteye.com/blog/2188113)
+
+ + Lua脚本结合 Redis 统计直播流播放次数、链接次数等等信息
+ + nginx.conf
+ ```Lua
+ server { # 配置虚拟服务器80
+ listen 80;
+ server_name 127.0.0.1:8088;
+ location ~* /live/(\w+)/ {
+ set $total_numbers "";
+ set $stream_name $1;
+ lua_code_cache off;
+ rewrite_by_lua_file /opt/openresty/nginx/conf/Lua/total_numbers.lua;
+ proxy_pass http://127.0.0.1:8088;
+ }
+ }
+ ```
+ + 代理服务器
+ ```Lua
+ server { # 配置虚拟服务器8088
+ listen 8088;
+ server_name 127.0.0.1:8088;
+ location /live {
+ add_header Cache-Control no-cache;
+ add_header 'Access-Control-Allow-Origin' '*' always;
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+ add_header 'Access-Control-Allow-Headers' 'Range';
+ types{
+ application/dash+xml mpd;
+ application/vnd.apple.mpegurl m3u8;
+ video/mp2t ts;
+ }
+ alias /home/tinywan/HLS/live/;
+ }
+ }
+
+ ```
+ + CURL请求地址:`http://192.168.18.143/live/tinywan123/index.m3u8`
+ + [Lua 脚本](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Hls-Line-Number-Total.lua)
+
+#### lua-resty-websocket 扩展
++ 代码引入:`lua_package_path "/opt/openresty/nginx/lua/lua-resty-websocket/lib/?.lua;;";`
++ **Lua脚本实现一个websocket连接(测试成功,可上线)**
+ + nginx.conf 配置信息
+ ```Lua
+ http {
+ lua_package_path "/opt/openresty/nginx/lua/lua-resty-websocket/lib/?.lua;;";
+ server {
+ listen 80 so_keepalive=2s:2s:8; #为了防止半开TCP连接,最好在Nginx监听配置指令中启用TCP keepalive:
+ server_name localhost;
+ location /ws {
+ lua_socket_log_errors off;
+ lua_check_client_abort on;
+ lua_code_cache off; # 建议测试的时候最好关闭缓存
+ content_by_lua_file /opt/openresty/nginx/conf/Lua/websocket.lua;
+ }
+ }
+ }
+ ```
+ + [WebSockets服务器Lua脚本websocket.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-websocket/websocket.lua)
+ + [websockets.html客户端代码,代码路径:/usr/local/openresty/nginx/html](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-websocket/websocket.html)
+ + 然后打开启用了WebSocket支持的浏览器,然后打开以下url:
+ 
+#### lua-cjson 扩展
++ 基本用法
+ + nginx.conf
+ ```Lua
+ location /cjson {
+ content_by_lua_block {
+ local cjson = require "cjson"
+ local json = cjson.encode({
+ foo = "bar",
+ some_object = {},
+ some_array = cjson.empty_array
+ })
+ ngx.say(json)
+ }
+ }
+ ```
+ + curl 请求
+ ```Bash
+ root@tinywan:/opt/openresty/nginx/conf# curl http://127.0.0.1/cjson
+ {"some_object":{"tel":13669313112,"age":24},"name":"tinywan","some_array":[]}
+ ```
++ [lua对象到字符串、字符串到lua对象](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-cjson/cjson-str-obj.lua)
+#### lua-resty-session 扩展
++ OpenResty 引用第三方 resty 库非常简单,只需要将相应的文件拷贝到 resty 目录下即可
++ 我服务器OpenResty 的 resty 路径:`/opt/openresty/lualib/resty`
++ 下载第三方 resty 库:git clone lua-resty-session 文件路径以及内容:
+ ```Bash
+ tinywan@tinywan:/opt/openresty/nginx/lua/lua-resty-session/lib/resty$ ls
+ session session.lua
+ ```
++ 特别注意:这里拷贝的时候要要把session文件和session.lua 文件同时吧、拷贝过去,否则会报错误:
+ ```Bash
+ /opt/openresty/lualib/resty/session.lua:34: in function 'prequire'
+ /opt/openresty/lualib/resty/session.lua:211: in function 'new'
+ /opt/openresty/lualib/resty/session.lua:257: in function 'open'
+ /opt/openresty/lualib/resty/session.lua:320: in function 'start'
+ ```
++ 拷贝完毕后`/opt/openresty/lualib/resty` OpenResty 引用第三方 resty 的所有库文件
+ ```Bash
+ tinywan@tinywan:/opt/openresty/lualib/resty$ ls
+ aes.lua core.lua http_headers.lua lock.lua lrucache.lua memcached.lua random.lua session sha1.lua sha256.lua sha512.lua string.lua upstream
+ core dns http.lua lrucache md5.lua mysql.lua redis.lua session.lua sha224.lua sha384.lua sha.lua upload.lua websocket
+ ```
++ 基本用法
+ ```Lua
+ location /start {
+ content_by_lua_block {
+ local session = require "resty.session".start()
+ session.data.name = "OpenResty Fan Tinywan"
+ session:save()
+ ngx.say("Session started. ",
+ "Check if it is working!")
+ ngx.say(session.data.name,"Anonymous")
+ }
+ }
+ ```
++ curl 请求
+ ```Bash
+ tinywan@tinywan:/opt/openresty/nginx/conf$ curl http://192.168.18.143/start
+ Session started. Check if it is working!
+ OpenResty Fan Tinywan Anonymous
+ ```
+#### Lua 权限验证
++ Lua 一个HLS的简单地址访问权限验证
+ + Nginx.conf 配置
+ ```Lua
+ location ^~ /live/ {
+ add_header Cache-Control no-cache;
+ add_header 'Access-Control-Allow-Origin' '*' always;
+ add_header 'Access-Control-Allow-Credentials' 'true';
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+ add_header 'Access-Control-Allow-Headers' 'Range';
+
+ types{
+ application/dash+xml mpd;
+ application/vnd.apple.mpegurl m3u8;
+ video/mp2t ts;
+ }
+ if ( $uri ~ \.m3u8 ) {
+ lua_code_cache off;
+ access_by_lua_file /opt/openresty/nginx/lua/access.lua;
+ }
+ root /home/tinywan/HLS;
+ }
+ ```
+ + access.lua 文件内容
+ ```Lua
+ if ngx.req.get_uri_args()["wsSecret"] ~= "e65e6a01cf26523e206d5bb0e2a8a95a" then
+ return ngx.exit(403)
+ end
+ ```
+#### lua-resty-string 扩展
++ MD5加密的简单基本用法 md5.lua
+ ```Lua
+ local resty_md5 = require "resty.md5"
+ local md5 = resty_md5:new()
+ if not md5 then
+ ngx.say("failed to create md5 object")
+ return
+ end
+ local ok = md5:update("hello")
+ if not ok then
+ ngx.say("failed to add data")
+ return
+ end
+ local digest = md5:final()
+ -- ngx.say("md5",digest) ---注意:这样直接输出是乱码
+ local str = require "resty.string"
+ ngx.say("md5: ", str.to_hex(digest)) ---注意:必须通过字符串转码方可打印输出
+ -- yield "md5: 5d41402abc4b2a76b9719d911017c592"
+ ```
+#### lua-resty-http 扩展 (ngx_lua的HTTP客户端cosocket驱动程序)
++ [简单测试:lua-http-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-http/lua-http-test.lua)
+#### lua-resty-mysql 扩展
++ [简单测试:lua-msyql-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-mysql/lua-msyql-test.lua)
+#### srcache-nginx-module 扩展 ([nginx下的一个缓存模块](https://github.com/openresty/srcache-nginx-module))
++ [openresty–redis–srcache缓存的应用](http://www.xtgxiso.com/openresty-redis-srcache-nginx-module%e7%bc%93%e5%ad%98%e7%9a%84%e5%ba%94%e7%94%a8/)
+#### openresty扫描代码全局变量
++ 在OpenResty中需要避免全局变量的使用,为此春哥写了一个perl工具,可以扫描openresty lua代码的全局变量
++ [https://github.com/openresty/openresty-devel-utils/blob/master/lua-releng](https://github.com/openresty/openresty-devel-utils/blob/master/lua-releng)
++ 用法相当简单
+ 1. 将代码保存成lua-releng文件
+ 2. 更改lua-releng的权限,chmod 777 lua-releng
+ 3. 假设有一个源码文件为test.lua
+ 4. 执行./lua-releng test.lua,则会扫描test.lua文件的全局变量,并在屏幕打印结果
+#### ngx Lua APi 方法和常量
++ ngx_lua 核心常量
+ ```lua
+ ngx.OK (0)
+ ngx.ERROR (-1)
+ ngx.AGAIN (-2)
+ ngx.DONE (-4)
+ ngx.DECLINED (-5)
+ ngx.nil
+ -- 指令常量
+ ngx.arg[index] #ngx指令参数,当这个变量在set_by_lua或者set_by_lua_file内使用的时候是只读的,指的是在配置指令输入的参数.
+ ngx.var.varname #读写NGINX变量的值,最好在lua脚本里缓存变量值,避免在当前请求的生命周期内内存的泄漏
+ ngx.config.ngx_lua_version #当前ngx_lua模块版本号
+ ngx.config.nginx_version #nginx版本
+ ngx.worker.exiting #当前worker进程是否正在关闭
+ ngx.worker.pid #当前worker进程的PID
+ ngx.config.nginx_configure #编译时的./configure命令选项
+ ngx.config.prefix #编译时的prefix选项
+ ```
++ ngx_lua 方法 (#经常在ngx.location.catpure和ngx.location.capture_multi方法中被调用.)
+ ```lua
+ ngx.HTTP_GET
+ ngx.HTTP_HEAD
+ ngx.HTTP_PUT
+ ngx.HTTP_POST
+ ngx.HTTP_DELETE
+ ngx.HTTP_OPTIONS
+ ngx.HTTP_MKCOL
+ ngx.HTTP_COPY
+ ngx.HTTP_MOVE
+ ngx.HTTP_PROPFIND
+ ngx.HTTP_PROPPATCH
+ ngx.HTTP_LOCK
+ ngx.HTTP_UNLOCK
+ ngx.HTTP_PATCH
+ ngx.HTTP_TRACE
+ ```
++ 错误日志级别常量
+ ```lua
+ ngx.STDERR
+ ngx.EMERG
+ ngx.ALERT
+ ngx.CRIT
+ ngx.ERR
+ ngx.WARN
+ ngx.NOTICE
+ ngx.INFO
+ ngx.DEBUG
+ ```
++ API中的常用方法
+ ```lua
+ print() #与 ngx.print()方法有区别,print() 相当于ngx.log()
+ ngx.ctx #这是一个lua的table,用于保存ngx上下文的变量,在整个请求的生命周期内都有效,详细参考官方
+ ngx.location.capture() #发出一个子请求,详细用法参考官方文档。
+ ngx.location.capture_multi() #发出多个子请求,详细用法参考官方文档。
+ ngx.status #读或者写当前请求的相应状态. 必须在输出相应头之前被调用.
+ ngx.header.HEADER #访问或设置http header头信息,详细参考官方文档。
+ ngx.req.set_uri() #设置当前请求的URI,详细参考官方文档
+ ngx.set_uri_args(args) #根据args参数重新定义当前请求的URI参数.
+ ngx.req.get_uri_args() #返回一个LUA TABLE,包含当前请求的全部的URL参数
+ ngx.req.get_post_args() #返回一个LUA TABLE,包括所有当前请求的POST参数
+ ngx.req.get_headers() #返回一个包含当前请求头信息的lua table.
+ ngx.req.set_header() #设置当前请求头header某字段值.当前请求的子请求不会受到影响.
+ ngx.req.read_body() #在不阻塞ngnix其他事件的情况下同步读取客户端的body信息.[详细]
+ ngx.req.discard_body() #明确丢弃客户端请求的body
+ ngx.req.get_body_data() #以字符串的形式获得客户端的请求body内容
+ ngx.req.get_body_file() #当发送文件请求的时候,获得文件的名字
+ ngx.req.set_body_data() #设置客户端请求的BODY
+ ngx.req.set_body_file() #通过filename来指定当前请求的file data。
+ ngx.req.clear_header() #清求某个请求头
+ ngx.exec(uri,args) #执行内部跳转,根据uri和请求参数
+ ngx.redirect(uri, status) #执行301或者302的重定向。
+ ngx.send_headers() #发送指定的响应头
+ ngx.headers_sent #判断头部是否发送给客户端ngx.headers_sent=true
+ ngx.print(str) #发送给客户端的响应页面
+ ngx.say() #作用类似ngx.print,不过say方法输出后会换行
+ ngx.log(log.level,...) #写入nginx日志
+ ngx.flush() #将缓冲区内容输出到页面(刷新响应)
+ ngx.exit(http-status) #结束请求并输出状态码
+ ngx.eof() #明确指定关闭结束输出流
+ ngx.escape_uri() #URI编码(本函数对逗号,不编码,而php的urlencode会编码)
+ ngx.unescape_uri() #uri解码
+ ngx.encode_args(table) #将tabel解析成url参数
+ ngx.decode_args(uri) #将参数字符串编码为一个table
+ ngx.encode_base64(str) #BASE64编码
+ ngx.decode_base64(str) #BASE64解码
+ ngx.crc32_short(str) #字符串的crs32_short哈希
+ ngx.crc32_long(str) #字符串的crs32_long哈希
+ ngx.hmac_sha1(str) #字符串的hmac_sha1哈希
+ ngx.md5(str) #返回16进制MD5
+ ngx.md5_bin(str) #返回2进制MD5
+ ngx.today() #返回当前日期yyyy-mm-dd
+ ngx.time() #返回当前时间戳
+ ngx.now() #返回当前时间
+ ngx.update_time() #刷新后返回
+ ngx.localtime() #返回 yyyy-mm-dd hh:ii:ss
+ ngx.utctime() #返回yyyy-mm-dd hh:ii:ss格式的utc时间
+ ngx.cookie_time(sec) #返回用于COOKIE使用的时间
+ ngx.http_time(sec) #返回可用于http header使用的时间
+ ngx.parse_http_time(str) #解析HTTP头的时间
+ ngx.is_subrequest #是否子请求(值为 true or false)
+ ngx.re.match(subject,regex,options,ctx) #ngx正则表达式匹配,详细参考官网
+ ngx.re.gmatch(subject,regex,opt) #全局正则匹配
+ ngx.re.sub(sub,reg,opt) #匹配和替换(未知)
+ ngx.re.gsub() #未知
+ ngx.shared.DICT #ngx.shared.DICT是一个table 里面存储了所有的全局内存共享变量
+ ngx.shared.DICT.get
+ ngx.shared.DICT.get_stale
+ ngx.shared.DICT.set
+ ngx.shared.DICT.safe_set
+ ngx.shared.DICT.add
+ ngx.shared.DICT.safe_add
+ ngx.shared.DICT.replace
+ ngx.shared.DICT.delete
+ ngx.shared.DICT.incr
+ ngx.shared.DICT.flush_all
+ ngx.shared.DICT.flush_expired
+ ngx.shared.DICT.get_keys
+ ndk.set_var.DIRECTIVE
+ ```
++ Lua HTTP状态常量
+ ```Lua
+ value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)
+ value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)
+ value = ngx.HTTP_OK (200)
+ value = ngx.HTTP_CREATED (201)
+ value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)
+ value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)
+ value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)
+ value = ngx.HTTP_SPECIAL_RESPONSE (300)
+ value = ngx.HTTP_MOVED_PERMANENTLY (301)
+ value = ngx.HTTP_MOVED_TEMPORARILY (302)
+ value = ngx.HTTP_SEE_OTHER (303)
+ value = ngx.HTTP_NOT_MODIFIED (304)
+ value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)
+ value = ngx.HTTP_BAD_REQUEST (400)
+ value = ngx.HTTP_UNAUTHORIZED (401)
+ value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)
+ value = ngx.HTTP_FORBIDDEN (403)
+ value = ngx.HTTP_NOT_FOUND (404)
+ value = ngx.HTTP_NOT_ALLOWED (405)
+ value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)
+ value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)
+ value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)
+ value = ngx.HTTP_GONE (410)
+ value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)
+ value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)
+ value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)
+ value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)
+ value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
+ value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
+ value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)
+ value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
+ value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)
+ value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)
+ value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)
+ ```
++ 案列使用,get_string_md5.lua:
+ ```Lua
+ local args = ngx.req.get_uri_args()
+ local salt = args.salt
+ if not salt then
+ ngx.say(ngx.HTTP_BAD_REQUEST)
+ end
+ local string = ngx.md5(ngx.time()..salt)
+ ngx.say(string)
+
+ ```
++ curl 请求(-i 参数,输出时包括protocol头信息):
+ ```Bash
+ tinywan@tinywan:$ curl -i http://127.0.0.1/get_rand_string?salt=tinywan123
+ HTTP/1.1 200 OK
+ Server: openresty/1.11.2.1
+ Date: Fri, 21 Apr 2017 14:27:16 GMT
+ Content-Type: application/octet-stream
+ Transfer-Encoding: chunked
+ Connection: keep-alive
+ ```
+#### ngx Lua APi 介绍使用
++ 强烈建议使用ngx Lua APi 接口`(非阻塞的)`,而不是Lua自身的API`(阻塞的)`,Lua 自身API会阻塞掉的
++ ngx_lua_api_test.lua
+ ```Lua
+ local json = require "cjson" -- 引入cjson 扩展
+
+ -- 同步读取客户端请求正文,而不会阻止Nginx事件循环
+ ngx.req.read_body()
+ local args = ngx.req.get_post_args()
+
+ if not args or not args.info then
+ ngx.say(ngx.HTTP_BAD_REQUEST) -- ngx.HTTP_BAD_REQUEST (400)
+ end
+
+ local client_id = ngx.var.remote_addr
+ local user_agent = ngx.req.get_headers()['user-agent'] or ""
+ local info = ngx.decode_base64(args.info)
+
+ local response = {}
+ response.info = info
+ response.client_id = client_id
+ response.user_agent = user_agent
+
+ ngx.say(json.encode(response))
+
+ ```
++ CURL Post 请求
+ ```Lua
+ $ curl -i --data "info=b3ZlcmNvbWUud2FuQGdtYWlsLmNvbQ==" http://127.0.0.1/ngx_lua_api_test
+ HTTP/1.1 200 OK
+ Server: openresty/1.11.2.1
+ Date: Sat, 22 Apr 2017 01:22:07 GMT
+ Content-Type: application/octet-stream
+ Transfer-Encoding: chunked
+ Connection: keep-alive
+
+ {"user_agent":"curl\/7.47.0","info":"overcome.wan@gmail.com","client_id":"127.0.0.1"}
+
+ ```
+#### OpenResty缓存
++ 指令:`lua_shared_dict`
+ + 纯内存的操作,多个worker之间共享的(比如nginx开启10个Worker,则每个worker之间是共享该内存的)
+ + 同一份数据在多个worker之间是共享的,只要存储一份数据就可以了
+ + 锁的竞争(数据原子性)
+#### lua-resty-upstream-healthcheck使用
++ health.txt 在每个upstream 服务器组的root 目录下创建这个文件,目录结构如下所示
+ ```javascript
+ ├── html
+ │ ├── 50x.html
+ │ ├── index.html
+ │ ├── websocket001.html
+ │ └── websocket02.html
+ ├── html81
+ │ ├── 50x.html
+ │ ├── health.txt
+ │ └── index.html
+ ├── html82
+ │ ├── 50x.html
+ │ ├── health.txt
+ │ └── index.html
+ ├── html83
+ │ ├── 50x.html
+ │ ├── health.txt
+ │ └── index.html
+ ├── html84
+ │ ├── 50x.html
+ │ └── index.html
+ ```
++ nginx.conf
+ ```Lua
+ worker_processes 8;
+
+ error_log logs/error.log;
+ pid logs/nginx.pid;
+
+ events {
+ use epoll;
+ worker_connections 1024;
+ }
+
+ http {
+ include mime.types;
+ default_type text/html;
+ #lua模块路径,其中”;;”表示默认搜索路径,默认到/usr/servers/nginx下找
+ lua_package_path "/home/tinywan/Openresty_Protect/First_Protect/lualib/?.lua;;"; #lua 模块
+ lua_package_cpath "/home/tinywan/Openresty_Protect/First_Protect/lualib/?.so;;"; #c模块
+ include /home/tinywan/Openresty_Protect/First_Protect/nginx_first.conf;
+ }
+
+ ```
++ nginx_first.conf
+ ```Lua
+ upstream tomcat {
+ server 127.0.0.1:8081;
+ server 127.0.0.1:8082;
+ server 127.0.0.1:8083;
+ server 127.0.0.1:8084 backup;
+ }
+
+ lua_shared_dict healthcheck 1m;
+
+ lua_socket_log_errors off;
+
+ init_worker_by_lua_block {
+ local hc = require "resty.upstream.healthcheck"
+ local ok, err = hc.spawn_checker{
+ shm = "healthcheck", -- defined by "lua_shared_dict"
+ upstream = "tomcat", -- defined by "upstream"
+ type = "http",
+
+ http_req = "GET /health.txt HTTP/1.0\r\nHost: tomcat\r\n\r\n",
+ -- raw HTTP request for checking
+
+ interval = 2000, -- run the check cycle every 2 sec
+ timeout = 1000, -- 1 sec is the timeout for network operations
+ fall = 3, -- # of successive failures before turning a peer down
+ rise = 2, -- # of successive successes before turning a peer up
+ valid_statuses = {200, 302}, -- a list valid HTTP status code
+ concurrency = 10, -- concurrency level for test requests
+ }
+ }
+
+ server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ proxy_pass http://tomcat;
+ }
+
+ location /server/status {
+ access_log off;
+ allow 127.0.0.1;
+
+ default_type text/plain;
+ content_by_lua_block {
+ local hc = require "resty.upstream.healthcheck"
+ ngx.say("Nginx Worker PID: ", ngx.worker.pid())
+ ngx.print(hc.status_page())
+ }
+ }
+ }
+
+ server {
+ listen 8081;
+ server_name localhost;
+
+ location / {
+ root html81;
+ index index.html index.htm;
+ }
+
+ location /health_status {
+
+ }
+ }
+
+ server {
+ listen 8082;
+ server_name localhost;
+
+ location / {
+ root html82;
+ index index.html index.htm;
+ }
+
+ location /health_status {
+
+ }
+ }
+
+ server {
+ listen 8083;
+ server_name localhost;
+
+ location / {
+ root html83;
+ index index.html index.htm;
+ }
+
+ location /health_status {
+
+ }
+ }
+
+ server {
+ listen 8084;
+ server_name localhost;
+
+ location / {
+ root html84;
+ index index.html index.htm;
+ }
+ }
+
+ ```
++ 状态查看,通过访问:`http://127.0.0.1/server/status`
+ 
+#### Openresty和Nginx_RTMP 模块共存问题
++ RTMP 流的状态(stat.xsl)不生效Bug 问题
+ - 1. 修改完nginx.conf 配置文件
+ - 1. ~~执行:`nginx -s reload` 会不起作用~~
+ - 2. 一定要执行以下命令:杀掉所有nginx进程`sudo killall nginx ` 重启即可`sbin/nignx`
+#### 配置RTMP模块的多worker直播流
++ 配置文件,[Multi-worker live streaming官方文档](https://github.com/arut/nginx-rtmp-module/wiki/Directives#multi-worker-live-streaming)
+ ```Shell
+ user www www;
+ worker_processes auto;
+ error_log logs/error.log debug;
+
+ pid /var/run/nginx.pid;
+ events {
+ use epoll;
+ worker_connections 1024;
+ multi_accept on;
+ }
+
+ rtmp_auto_push on;
+ rtmp_auto_push_reconnect 1s;
+ rtmp_socket_dir /var/sock;
+ rtmp {
+ server {
+ listen 1935;
+ application live {
+ live on;
+ }
+ }
+ }
+ ```
++ [nginx 并发数问题思考:worker_connections,worker_processes与 max clients](http://liuqunying.blog.51cto.com/3984207/1420556?utm_source=tuicool)
+ + 从用户的角度,http 1.1协议下,由于浏览器默认使用两个并发连接,因此计算方法:
+ 1. nginx作为http服务器的时候:
+ `max_clients = worker_processes * worker_connections/2`
+ 1. nginx作为反向代理服务器的时候:
+ `max_clients = worker_processes * worker_connections/4`
+ + 从一般建立连接的角度,客户并发连接为1:
+ 1. nginx作为http服务器的时候:
+ `max_clients = worker_processes * worker_connections`
+ 1. nginx作为反向代理服务器的时候:
+ `max_clients = worker_processes * worker_connections/2`
+ + nginx做反向代理时,和客户端之间保持一个连接,和后端服务器保持一个连接
+ + clients与用户数
+ 同一时间的clients(客户端数)和用户数还是有区别的,当一个用户请求发送一个连接时这两个是相等的,但是当一个用户默认发送多个连接请求的时候,clients数就是用户数*默认发送的连接并发数了。
+
+
+## Redis、Lua、Nginx一起工作事迹
++ 解决一个set_by_lua $sum 命令受上下文限制的解决思路,已完美解决
++ - [x] [API disabled in the context of set_by_lua](https://github.com/openresty/lua-nginx-module/issues/275)
++ 解决2
++ 解决3
+## Redis执行Lua脚本
+## Lua 基本语法
+---
++ Hello, Lua!
+
+ > 我们的第一个Redis Lua 脚本仅仅返回一个字符串,而不会去与redis 以任何有意义的方式交互
+
+ ```Lua
+ local msg = "Hello, world!"
+ return msg
+ ```
+
+ > 这是非常简单的,第一行代码定义了一个本地变量msg存储我们的信息, 第二行代码表示 从redis 服务端返回msg的值给客户端。 保存这个文件到Hello.lua,像这样去运行:
+
+ ```Bash
+ www@iZ239kcyg8rZ:~/lua$ redis-cli EVAL "$(cat Hello.lua)" 0
+ "Hello, world!"
+ ```
+
+ > 运行这段代码会打印"Hello,world!", EVAL在第一个参数是我们的lua脚本, 这我们用cat命令从文件中读取我们的脚本内容。第二个参数是这个脚本需要访问的Redis 的键的数字号。我们简单的 “Hello Script" 不会访问任何键,所以我们使用0
+
++ redis.call() 与 redis.pcall()的区别
+
+ * 他们唯一的区别是当redis命令执行结果返回错误时
+ * redis.call()将返回给调用者一个错误.
+ * redis.pcall()会将捕获的错误以Lua表的形式返回.
+ * redis.call() 和 redis.pcall() 两个函数的参数可以是任意的 Redis 命令
++ Lua网络编程
+## Lua 脚本
++ Lua 实现简单封装
+ + man.lua
+ ```Lua
+ local _name = "Tinywan"
+ local man = {}
+
+ function man.GetName()
+ return _name
+ end
+
+ function man.SetName(name)
+ _name = name
+ end
+
+ return man
+ ```
+ + 测试封装,test.lua
+
+ ```Lua
+ local man = require('man')
+ print("The man name is "..man.GetName())
+ man.SetName("Phalcon")
+ print("The man name is "..man.GetName())
+ ```
+#### Redis执行Lua脚本基本用法
++ EVAL命令格式
+ + 基本语法
+ ```
+ EVAL script numkeys key [key ...] arg [arg ...]
+ ```
+ + 语义
+ 1. script即为lua脚本或lua脚本文件
+ 1. key一般指lua脚本操作的键,在lua脚本文件中,通过KEYS[i]获取
+ 1. arg指外部传递给lua脚本的参数,可以通过ARGV[i]获取
+ + eval命令的用法
+ ```
+ 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
+ 1) "key1"
+ 2) "key2"
+ 3) "first"
+ 4) "second"
+ ```
+ > 这个示例中lua脚本为一个return语句,返回了lua一个数组,这个数组四个元素分别是通过外部传入lua脚本。
+ 因为redis内嵌了Lua虚拟机,因此redis接收到这个lua脚本之后,然后交给lua虚拟机执行。
+ 当lua虚拟机执行结束,即将执行结果返回给redis,redis将结果按自己的协议转换为返回给客户端的回复,最后再通过TCP将回复发回给客户端
+ + lua脚本参数的接受
+ + 键值:`KEYS[i]` 来获取外部传入的键值
+ + 参数:`ARGV[i]` 来获取外部传入的参数
++ 案例介绍
+ + 通过Redis命令`EVAL`执行一个简单的Lua脚本文件
+ + 给Redis添加测试数据(通过有序集合和哈希对应的集合信息)
+ ```javascript
+ 127.0.0.1:6379> ZADD WEB 1 google
+ (integer) 1
+ 127.0.0.1:6379> ZADD WEB 2 apple
+ (integer) 1
+ 127.0.0.1:6379> ZADD WEB 3 baidu
+ (integer) 1
+ 127.0.0.1:6379> ZRANGE WEB 0 3
+ 1) "google"
+ 2) "apple"
+ 3) "baidu"
+ 127.0.0.1:6379> hmset google domain_name www.google.com ip 192.168.1.100
+ OK
+ 127.0.0.1:6379> hmset baidu domain_name www.baidu.com ip 192.168.1.200
+ OK
+ 127.0.0.1:6379> hmset apple domain_name www.apple.com ip 192.168.1.300
+ OK
+ 127.0.0.1:6379> hgetall google
+ 1) "domain_name"
+ 2) "www.google.com"
+ 3) "ip"
+ 4) "192.168.1.100"
+ 127.0.0.1:6379> hgetall apple
+ 1) "domain_name"
+ 2) "www.apple.com"
+ 3) "ip"
+ 4) "192.168.1.300"
+ 127.0.0.1:6379> hgetall baidu
+ 1) "domain_name"
+ 2) "www.baidu.com"
+ 3) "ip"
+ 4) "192.168.1.200"
+ ```
+ + Lua脚本,lua_get_redis.lua 文件
+ ```Lua
+ -- 获取键值/参数
+ local key,offset,limit = KEYS[1], ARGV[1], ARGV[2]
+ -- 通过ZRANGE获取键为key的有序集合元素,偏移量为offset,个数为limit,即所有WEB信息
+ local names = redis.call('ZRANGE', key, offset, limit)
+ -- infos table 存储所有WEB信息
+ local infos = {}
+ -- 遍历所有WEB信息
+ for i=1,#names do
+ local ck = names[i]
+ -- 通过HGETALL命令获取每WEB的信息
+ local info = redis.call('HGETALL',ck)
+ -- 并且在WEB信息中插入对应的集合信息
+ table.insert(info,'HOST_NAME')
+ table.insert(info,names[i])
+ --table.insert(info,'author',"Tinywan")
+ -- 插入infos中
+ infos[i] = info
+ end
+ -- 将结果返回给redis
+ return infos
+ ```
+ 1. redis.call() 函数的参数可以是任意的 Redis 命令
+ 1. table.insert(table, pos, value)
+ > [1]table.insert()函数在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾
+ + 执行结果:
+ ```
+ tinywan@:~/Lua$ sudo redis-cli --eval /home/tinywan/Lua/lua_get_redis.lua WEB , 0 2
+ 1) 1) "domain_name"
+ 2) "www.google.com"
+ 3) "ip"
+ 4) "192.168.1.100"
+ 5) "HOST_NAME"
+ 6) "google"
+ 2) 1) "domain_name"
+ 2) "www.apple.com"
+ 3) "ip"
+ 4) "192.168.1.300"
+ 5) "HOST_NAME"
+ 6) "apple"
+ 3) 1) "domain_name"
+ 2) "www.baidu.com"
+ 3) "ip"
+ 4) "192.168.1.200"
+ 5) "HOST_NAME"
+ 6) "baidu"
+ ```
+ + 注意:`lua_get_redis.lua WEB , 0 2` 之间的空格,不然会提示错误
+ + 错误:`(error) ERR Error running script command arguments must be strings or integers`
+ + Ngx_lua 写入Redis数据,通过CURL请求
+ + curl_get_redis.lua 文件内容
+ ```Lua
+ local json = require("cjson")
+ local redis = require("resty.redis")
+ local red = redis:new()
+
+ red:set_timeout(1000)
+
+ local ip = "127.0.0.1"
+ local port = 6379
+ local ok, err = red:connect(ip, port)
+ if not ok then
+ ngx.say("connect to redis error : ", err)
+ return ngx.exit(500)
+ end
+
+ local key = ngx.var[1]
+ local new_timer = ngx.localtime() -- 本地时间:2017-04-16 15:56:59
+ local value = key.."::"..new_timer
+ local ok , err = red:set(key,value)
+ if not ok then
+ ngx.say("failed to set "..key, err)
+ return
+ end
+ ngx.say("set result: ", ok)
+
+ local res, err = red:get(key)
+ if not res then
+ ngx.say("get from redis error : ", err)
+ return
+ end
+ if res == ngx.null then
+ ngx.say(key.."not found.")
+ return
+ end
+ red:close()
+ ngx.say("Success get Redis Data",json.encode({content=res}))
+ ```
+ + nginx.conf
+ ```Lua
+ location ~* /curl_insert_redis/(\w+)$ {
+ default_type 'text/html';
+ lua_code_cache off;
+ content_by_lua_file /opt/openresty/nginx/conf/Lua/curl_get_redis.lua;
+ }
+ ```
+ + curl 和浏览器请求结果(查询Redis数据库,数据已经插入成功)
+ ```Lua
+ root@tinywan:# curl http://127.0.0.1/curl_insert_redis/Tinywan1227
+ set result: OK
+ Success get Redis Data{"content":"Tinywan1227::2017-04-16 15:57:56"}
+ ```
+ + 通过lua脚本获取指定的key的List中的所有数据
+ ```Lua
+ local key=KEYS[1]
+ local list=redis.call("lrange",key,0,-1);
+ return list;
+ ```
+ + 根据外面传过来的IDList 做“集合去重”的lua脚本逻辑:
+ ```Lua
+ local result={};
+ local myperson=KEYS[1];
+ local nums=ARGV[1];
+
+ local myresult =redis.call("hkeys",myperson);
+
+ for i,v in ipairs(myresult) do
+ local hval= redis.call("hget",myperson,v);
+ redis.log(redis.LOG_WARNING,hval);
+ if(tonumber(hval) Visual Studio Code 向github提交代码不用输入帐号密码
++ 在命令行输入以下命令
+ ```
+ git config --global credential.helper store
+ ```
+
+ > 这一步会在用户目录下的.gitconfig文件最后添加:
+
+ ```
+ [credential]
+ helper = store
+ ```
++ push 代码
+
+ > push你的代码 (git push), 这时会让你输入用户名和密码, 这一步输入的用户名密码会被记住, 下次再push代码时就不用输入用户名密码!这一步会在用户目录下生成文件.git-credential记录用户名密码的信息。
+
++ Markdown 的超级链接技术
+
+ > 【1】需要链接的地址:
+
+ ```
+ [解决向github提交代码不用输入帐号密码](#githubpush)
+ ```
+
+ > 【2】要链接到的地方:
+
+ ```
+ 解决向github提交代码不用输入帐号密码
+ ```
+
+ > 通过【1】和【2】可以很完美的实现一个连接哦!
+
+## Linux 基础知识
++ 检查网卡是否正确工作
+ 1. 检查系统路由表信息是否正确
+ 1. [Linux route命令详解和使用示例](http://www.jb51.net/LINUXjishu/152385.html)
+ 1. 案例介绍:
+ ```
+ www@ubuntu1:/var/log$ route
+ Kernel IP routing table
+ Destination Gateway Genmask Flags Metric Ref Use Iface
+ default 122.11.11.161 0.0.0.0 UG 0 0 0 em1
+ 10.10.101.0 * 255.255.255.0 U 0 0 0 em2
+ 122.11.11.160 * 255.255.255.224 U 0 0 0 em1
+ ```
+ + 默认路由为:`122.11.11.161`,绑定在`em1` 网卡上
+ + 而`10.10.101.0` 段的IP仅供局域网主机之间共享数据,没对外连接访问权限,因而外界是没办法通过`10`段网络连接到服务器的
+ + 如果需要`10.10.101.0` 段可以让外网放完的,则需要删除`122.11.11.161` 的默认路由,需要在`em2`网卡上添加`10`段的默认路由即可
+ + 具体步骤:
+ ```
+ www@ubuntu1:/var/log$ route delete defaul
+ www@ubuntu1:/var/log$ route add defaul gw 10.10.101.1
+ ```
+ + 此时外界就可以通过`ssh www@10.10.101.2`连接到服务器了
++ find 命令
+ + 查找超出7天前的flv的文件进行删除:
+ + 命令:
+ ```Bash
+ find ./ -mindepth 1 -maxdepth 3 -type f -name "*.flv" -mmin +10080 | xargs rm -rf
+ ```
+ + `-type f` 按类型查找
+ + `-mmin +10080` 7天之前的文件
+ + xargs与-exec功能类似,` find ~ -type f | xargs ls -l `
+ + -r 就是向下递归,不管有多少级目录,一并删除
+ + -f 就是直接强行删除,不作任何提示的意思
+ + 查找当前目录下.p文件中,最近30分钟内修改过的文件:
+ + `find . -name '*.p' -type f -mmin -30`
+ + 查找当前目录下.phtml文件中,最近30分钟内修改过的文件,的详细de情况加上ls:
+ + `find . -name '*.phtml' -type f -mmin -30 -ls`
+ + 查找当前目录下,最近1天内修改过的常规文件:`find . -type f -mtime -1`
+ + 查找当前目录下,最近1天前(2天内)修改过的常规文件:`find . -type f -mtime +1`
+# 掘金爬虫
+
+
+
+# Lua-Ngx
+
+# Live demo
+
+Changes are automatically rendered as you type.
+
+* Follows the [CommonMark](http://commonmark.org/) spec
+* Renders actual, "native" React DOM elements
+* Allows you to escape or skip HTML (try toggling the checkboxes above)
+* If you escape or skip the HTML, no `dangerouslySetInnerHTML` is used! Yay!
+
+## HTML block below
+
+
+ This blockquote will change based on the HTML settings above.
+
+
+## How about some code?
+```js
+var React = require('react');
+var Markdown = require('react-markdown');
+
+React.render(
+ ,
+ document.getElementById('content')
+);
+```
+
+Pretty neat, eh?
+
+## More info?
+
+Read usage information and more on [GitHub](//github.com/rexxars/react-markdown)
+
+---------------
+
+A component by [VaffelNinja](http://vaffel.ninja) / Espen Hovlandsdal
+
+## Copyright and License
+
+This module is licensed under the BSD license
+
+Copyright (C) 2017, by Wanshaobo "Tinywan".
\ No newline at end of file