Основные сведения о Shell-скриптах
Подробное описание высокопроизводительного WEB-сервера Nginx
Глава 2. Установка и развертывание](#Nginx_Web2_knowledge)
Глава 3. Исследование архитектуры](#Nginx_Web3_knowledge)
Глава 4. Расширенные конфигурации](#Nginx_Web4_knowledge)
Глава 5. Сжатие gzip](#Nginx_Web5_knowledge)
Глава 6. Возможность переадресации rewrite](#Nginx_Web6_knowledge)
Глава 7. Прокси-сервисы](#Nginx_Web7_knowledge)
Глава 8. Механизмы кэширования](#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_ngx_api_used)
Авторское право и лицензия## Записи разработки+ Решение проблемы аутентификации при отправке кода в GitHub с помощью Visual Studio Code
Определение понятия phase: это набор нескольких MR, где количество MR может быть любым. В процессе обработки запроса через nginx происходит прохождение через несколько этапов (phases).
location /test {
set $first "hello ";
echo "${first}world";
}
Удаление глобальной переменной можно присвоить её значением nil: a = nil
. Переменная существует только если она не равна nil.
Тип данных Boolean: В условиях управления, все значения кроме false и nil считаются истинными, поэтому Lua считает 0 и пустую строку также истинными.
Тип данных String:
string.gsub()
a = 'one HELLO'
b = string.gsub(a,'one','two')
print(a) -- one HELLO
print(b) -- two HELLO
print("10" + 1) -- 11
print("10" + "1") -- 11
print("10 + 1") -- 10 + 1
print("hello " .. " world") -- hello world
--print("hello" + 1) -- неправильный способ
a = 10
print(tostring(a)) -- 10
b = "20"
print(tonumber(b)) -- 20
print(tostring(10) == "10") -- true
print(10 .. "" == "10") -- true
Выражения
-- a and b -- если a равно false, вернуть a, иначе вернуть b
-- a или b -- если a истинно, то возвращается a, иначе возвращается b
print(4 and 5) -- 5
print(nil and 12) -- nil
print(false and 12) -- false
print(4 or 5) -- 4
print(false or 5) -- 5
```+ Внимание: приоритет оператора `and` выше, чем оператора `or`.
Lua трёхместный условный оператор: (a and b) or c
.
Переменные
Присваивание
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
Локальные переменные и блоки кода
a = 12
if a > 10 then
local i = 19
print(i) -- 19
end
print(i) -- nil
Управляющие конструкции
members = { Tom = 10, Jake = 11, Dodo = 12, Jhon = 16 }
for k, v in pairs(members) do
if v == 10 then
print(k, 'в возрасте 10 лет') -- Tom в возрасте 10 лет
elseif v == 11 then
print(k, 'в возрасте 11 лет') -- Jake в возрасте 11 лет
elseif v == 12 then
print(k, 'в возрасте 12 лет') -- Dodo в возрасте 12 лет
else
print(k, "не в возрасте 10, 11 или 12 лет") -- Jhon не в возрасте 10, 11 или 12 лет
end
end
Функции
Одиночный возврат значения
function max(a, b)
if a > b then
return a
else
return b
end
end
print(max(10, 20)) -- 20
Множественный возврат значений
function more()
return 10, 20, 30
end
a, b, c = more()
print(a, b, c) -- 10 20 30
``` + Переменное количество аргументов
```lua
function более_одного()
return 10, 20, 30
end
-- Когда функция находится последней позиции, она возвращает все значения, иначе возвращает одно значение
a, b, c, d = 100, более_одного()
print(a, b, c, d) -- 100 10 20 30
``` + Закрытые функции
```lua
function count()
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() -- Это пример хвостового вызова
end
drink = function()
print("drink")
end
eat()
```
+ Использование таблиц
+ В Lua первым индексом таблицы является 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`
+ Итерация по элементам таблицы: `pairs`
- [x] позволяет проходить по всем ключам таблицы
- [x] также возвращает nil, если ключ отсутствует
+ Итерация по элементам массива: `ipairs` - [x] `ipairs` не возвращает `nil`, а выходит из цикла, если встречает `nil`
- [x] работает только с ключами, являющимися целыми числами, начиная с 1
+ Генераторы
```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
-- ]]
```
+ Итерация по элементам таблицы
```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)) -- длина таблицы 100
print(#arr) -- длина таблицы (быстрый способ) 100
```
+ Итерация по элементам массива: `ipairs`
```lua
arr = {host = '127.0.0.1', port = '3306', 'Tinywan'}
-- Если ключ не является целым числом, то цикл завершается, если же ключ целое число, то происходит вывод, как в случае с 'Tinywan' выше
for k, v in ipairs(arr) do -- можно итерировать только по ключам, являющимися целыми числами
print(k, v) -- 1 Tinywan
end
```
+ Циклическая итерация по элементам таблицы (например, данные расширения lua-resty-mysql)
+ Выполнение запроса: `res, err, errcode, sqlstate = db:query("select * from tb_ngx_test order by id asc", 10)````markdown
## Вывод результатов
возраст = 24123 имя = tinywan123 адрес = Китай идентификатор = 1 возраст = 24 имя = tinywan адрес = Китай идентификатор = 2
```### Преобразование JSON и таблиц Lua
+ **Преобразование JSON в таблицу Lua**
+ **[1]** Преобразование строки JSON в таблицу Lua
```lua
local json_str = '{"is_male":"nan","name":"zhangsan","id":1}'
local t = json.decode(json_str)
ngx.say(format_table(t))
```
+ **Преобразование таблицы Lua в строку JSON**
+ **[2]** Преобразование таблицы Lua в строку 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 в массив JSON
```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** Ошибка проверки условия
```lua
assert(name~="Lua"," this is not Lua")
```
+ **pcall** Проверка и захват ошибок
```lua
function test()
print(a[1])
end
local status,err = pcall(test)
if status then
print('Успешно')
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("Сложение двух таблиц вызывает меня")
end
local t1 = {}
local t2 = {}
``` setmetatable(t1, mt) -- meta:элемент
setmetatable(t2, mt)
```
-- Выполняется операция сложения
local t = t1 + t2
print(t)
--[[Результат вывода
При сложении двух таблиц вызывается метод __add
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
-- Создаем два таблицы, можно представить как объекты двух классов (инстанцирование двух классов)
local s1 = { name = "Per1", sex = "boy" }
local s2 = { name = "Per2", sex = "girl" }
-- Устанавливаем новые метатаблицы для двух таблиц, одна метатаблица представляет собой значения одной таблицы
setmetatable(s1, mt)
setmetatable(s2, mt)
-- Выполняем операцию сложения
local result = s1 + s2
print(result)
-- Вывод результата Семья мальчика и девочки
```
+ :white_check_mark: `__index` метамethod #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 говорит Привет всем!")
end
}
local t1 = {}
local t2 = {}
local mt = { __index = smartMan } -- __index может быть таблицей или функцией
setmetatable(t1, mt)
setmetatable(t2, mt)
print(t1.money)
t2.say_fun()
--- Результат вывода
-- 800000
-- Tinywan говорит Привет всем!
```
+ Lua объектно-ориентированное программирование 1
+ Lua объектно-ориентированное программирование 1
+ Lua объектно-ориентированное программирование 3 Обновление в процессе...
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
}
```lua
selectionSort(list)
print(table.concat(list, ","))
```#### Контрольные конструкции
table.concat(table[, sep[, start[, end]]])
concat
является сокращением от concatenate (соединение). Функция table.concat()
объединяет все элементы массивной части указанной таблицы от позиции start
до end
, используя указанный разделитель (sep
)fruits = {"banana", "orange", "apple"}
-- Возвращает соединённую строку value = banana orange apple
print("Соединённая строка ", table.concat(fruits))
-- Указывает разделитель value = banana, orange, apple
print("Строка с указанным разделителем ", table.concat(fruits, ", "))
```+ `table.insert(table, [pos], value)`
value
в указанную позицию pos
массивной части таблицы. Параметр pos
опционален; по умолчанию вставка происходит в конец массивной части.fruits = {"banana", "orange", "apple"}
-- Вставка в конец
table.insert(fruits, "Tinywan4")
print("Элемент с индексом 4 ", fruits[4]) -- Элемент с индексом 4 Tinywan4
-- Вставка в позицию с индексом 2
table.insert(fruits, 2, 'Tinywan2')
print("Элемент с индексом 2 ", fruits[2]) -- Элемент с индексом 2 Tinywan2
print("Последний элемент ", fruits[5]) -- Последний элемент Tinywan4
table.remove(fruits)
print("После удаления последний элемент ", fruits[5]) -- После удаления последний элемент nil
```+ `table.sort(table[, comp])`
Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)
, исполните: sudo fuser -k 80/tcp
location /live {
alias /home/tinywan/HLS/;
}
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
/live/index.html
, Nginx будет искать файл /home/tinywan/HLS/index.html
на сервере.url
после location
будет добавлена к каталогу, указанному в alias
, а путь /live
после location
будет автоматически отброшен.- Похожий случай [2]:
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
:
alias
на root
location ~ ^/live/(.*)$ {
root /home/tinywan/HLS/$1;
}
curl
:
tinywan@tinywan:~/HLS$ curl http://127.0.0.1/live/txt.txt
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>openresty/1.11.2.1</center>
</body>
</html>
rewrite_log on;
):
/home/tinywan/HLS/txt.txt/live/txt.txt
alias
, является текущим каталогом.root
, является корневым каталогом.
root
внутри конфигурации location /
, а остальные пути совпадения использовать командой alias
. 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
```#### <a name="Nginx_Web3_knowledge"/> Глава 3. Начальный взгляд на архитектуру
=
строгое соответствие. Если запрос соответствует этому правилу, то поиск прекращается и данный запрос обрабатывается немедленно.~
регистрозависимое соответствие (можно использовать регулярные выражения)! ~
регистрозависимое несоответствие! ~*
регистронезависимое несоответствие^~
если этот префикс используется для обычной строки, то Nginx будет знать, что если путь соответствует, то нет необходимости проверять регулярные выражения$
соответствует окончанию входной строки. Если установлено свойство multiline объекта RegExp, то $ также соответствует '\n' или '\r'. Чтобы найти символ $ сам по себе, используйте $.( )
отмечает начало и конец подвыражения. Подвыражение можно использовать для дальнейшего использования. Чтобы найти эти символы, используйте ( и ).*
соответствует нулевому или более повторам предыдущего подвыражения. Чтобы найти символ *, используйте *.+
соответствует одному или более повторам предыдущего подвыражения.Чтобы найти символ +, используйте +.\.
соответствует любому одиночному символу, кроме символа новой строки \n. Чтобы найти символ . , используйте ..[ ]
отмечает начало выражения в квадратных скобках. Чтобы найти символ [, используйте [.\?
соответствует нулю или одному повтору предыдущего подвыражения, или указывает на неголодный ограничитель. Чтобы найти символ ? , используйте ?.\\
отмечает следующий символ как метасимвол, специальный символ, буквенный символ, обратную ссылку или восходящую последовательность. Например, 'n' соответствует букве 'n', '\n' соответствует символу новой строки, последовательность '\' соответствует '\', а '(' соответствует '('.\^
соответствует началу входной строки, за исключением случаев, когда он используется внутри выражения в квадратных скобках, где он указывает на отказ принять набор символов. Чтобы найти символ ^, используйте ^.\{
отмечает начало выражения ограничителя. Чтобы найти символ {, используйте {.\|
указывает выбор между двумя элементами. Чтобы найти символ |, используйте |.Регулярные выражения (Regular expression) для совпадения с локациями
- [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. Каталог для VOD видео 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/; }
+ Пример совпадения каталога для прямых потоков HLS (пожалуйста, протестируйте перед запуском)
1. Расширение файла: http://127.0.0.1/live/stream123/index.m3u8
location ^~ /live/ { root /home/tinywan/HLS/; }
Часто используемые глобальные переменные в 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 |
Значение заголовка Host запроса, если отсутствует — имя сервера |
$http_user_agent |
curl/7.47.0 |
Информация агента клиента |
$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 | Порт клиента |
$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 (URI в Nginx относителен)
https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md
https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md
/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/config.md
Перезапись регулярным выражением параметра uri
curl http://192.168.18.143/live/tinywan123/index.m3u8
nginx.conf
location ~* ^/live/(\w+)/(\D+). (m3u8|ts)$ {
set $num $2;
set $arg1 $1;
echo "args === ${arg1}";
echo "1==$1 2==$2 3==$3";
echo "Total_number :: $num";
echo "URI $uri";
}
args === tinywan123
1==tinywan123 2==123 3==m3u8
Total_number :: 123
URI /live/tinywan123/index.m3u8
``` \$1==tinywan123 \$2==index \$3==m3u8
Total_number :: index
URI /live/tinywan123/index.m3u8
Total_number ::
\
$1` — это строка, содержащая несколько букв или цифр (
\w+)
`$2` — это строка, содержащая несколько символов, кроме цифр (
\D+)
`$3` — это первый найденный параметр (
(m3u8|ts))
. — должен быть экранирован как
. `## 7 глава. Прокси-сервисыКонцепция прямого и обратного прокси-сервера
Прямой прокси-сервер
Обратный прокси-сервер
Логи Nginx (https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Nginx/Nginx-Web/Nginx-2-Log.md)
Балансировка нагрузки
Балансировка HTTP-нагрузки
Балансировка TCP-нагрузки
Обзор URL для proxy_pass
proxy_pass
в nginx, если после URL добавлен слеш /
, это указывает на абсолютный корневой путь, и nginx не будет проксировать часть пути, совпадающую с правилом location
. Если же слеш отсутствует, то совпавшая часть пути будет проксирована./wap/
, можно использовать следующее правило для перенаправления на определённый сервер:
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
.
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
.
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
.
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
.
location /proxy/ {
root /usr/local/nginx/html;
index index.html index.htm;
}
.
├── conf
│ ├── nginx.conf -- Конфигурационный файл Nginx
├── logs
│ ├── error.log -- Журнал ошибок Nginx
│ └── nginx.pid
├── lua
│ ├── m3u8_redis_access.lua -- Файл проверки прав доступа M3U8
│ ├── business_redis.lua -- Файл обработки бизнес-логики Redis
│ ├── http-lua-test.lua -- Пример использования Lua в Nginx
│ ├── ... -- ...
│ └── resty -- Директория с общими библиотеками Lua
│ └── redis_iresty.lua -- Вторичная обработка интерфейсов Redis
│ └── param.lua -- Библиотека фильтрации параметров
└── sbin
└── nginx
[1] Косвенное получение:
var = ngx.var
, например, если переменная$a = 9
, тоlua_a = ngx.var.a --lua_a = 9
. [2] Прямое получение:var = ngx.var.a````markdown var
, например, если вторая переменнаяlocation
равна 890, тоhttp://127.0.0.1/lua_request/123/890
, тогдаlua_2 = ngx.var[2] --lua_2 = 890
.
[1] Получение таблицы со всеми текущими заголовками запроса:
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']
.
Linux curl GET метод отправки данных:
curl -G -d "name=value&name2=value2" https://github.com/Tinywan
. Получение таблицы всех параметров URI запроса:local get_args = ngx.req.get_uri_args()
. Пример запроса:curl -G -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789
. Получение значения параметраname
с использованием метода GET в Lua:
### Получение значений параметров запроса с помощью GET
#### Получение параметра `name` через `get_args`
```lua
[01] get_args['name']
```
или
```lua
[02] ngx.req.get_uri_args()['name']
```
### Получение значений параметров запроса с помощью POST
#### Пример использования команды `curl` для отправки данных методом POST
```bash
[01] curl -d "name=value&name2=value2" https://github.com/Tinywan
```
или
```bash
[02] curl -d a=b&c=d&txt@/tmp/txt https://github.com/Tinywan
```
#### Получение параметров POST запроса
```lua
local post_args = ngx.req.get_post_args()
```
Пример запроса:
```bash
curl -d "name=Tinywan&age=24" http://127.0.0.1/lua_request/123/789
```
#### Получение значения параметра `name` с помощью POST
```lua
[01] post_args['name']
```
или
```lua
[02] ngx.req.get_post_args()['name']
```
### Другие полезные функции Lua
- Версия HTTP протокола запроса: `ngx.req.http_version()`
- Метод запроса: `ngx.req.get_method()`
- Начальный заголовок запроса: `ngx.req.raw_header()`
- Тело запроса: `ngx.req.get_body_data()`
#### [Получение информации о запросах](#)
##### [Ответы на запросы: установка статусного кода ответа, заголовков и содержимого ответа](#)
### По умолчанию путь к исполняемому файлу Luajit: `/opt/openresty/luajit/bin/luajit`. Таким образом, можно запустить Lua файл следующей командой: `luajit test.lua`.
#### Пример выполнения тестового скрипта Luajit:
```bash
tinywan@tinywan:~/Lua$ luajit test.lua
Имя мужчины — Tinywan
Имя мужчины — Phalcon
```
#### Расширение lua-resty-redis (модуль для работы с Redis в OpenResty)
- Включение библиотеки: `lua_package_path "/opt/openresty/nginx/lua/lua-resty-redis/lib/? . lua;;";`
- Реализация обратного прокси-сервера CDN с использованием Lua (тестировано успешно, готово к использованию).
``` ##### Конфигурация Nginx
```nginx
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 "";
```
```markdown
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;
}
}
```
+ [Прокси скрипт 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+локальным Redis+MySQL серверами для кэширования
+ Архитектура кластера Nginx+Lua+локальный 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+Nginx+Lua+Redis+MySQL.conf](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-redis/Nginx+Lua+Redis+MySQL.conf)
+ [Помощь](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;
}
}
``````markdown
## Прокси-сервер
```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-соединений рекомендуется включить TCP keepalive в конфигурационных директивах Nginx:
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;
}
}
}
```
``` + [Lua-скрипт сервера WebSockets 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:

#### <a name="Openresty_resty-cjson"/> Расширение `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
{"foo":"bar","some_object":{},"some_array":[]}
```
+ [Преобразование объекта Lua в строку и строк в объект Lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-cjson/cjson-str-obj.lua)#### <a name="Openresty_resty-session"/> Расширение `lua-resty-session` + Установка внешних библиотек resty в OpenResty очень проста — достаточно скопировать соответствующие файлы в директорию resty.
+ Путь к папке resty на моём сервере OpenResty: `/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`, где будет доступна вся необходимая библиотека 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('<html><body>Session started. ', '<a href="/test">Проверьте, работает ли это</a>!</body></html>')
ngx.say(session.data.name or 'Anonymous')
}
}
```
+ Вызов с помощью curl:
```bash
tinywan@tinywan:/opt/openresty/nginx/conf$ curl http://192.168.18.143/start
<html><body>Сессия началась. <a href=/test>Проверьте, работает ли это</a>!</body></html>
OpenResty Fan Tinywan Anonymous
```#### <a name="Openresty_ngx_api_auth"/> Правила доступа через Lua
+ Пример проверки прав доступа к HLS-потоку через Lua
+ Конфигурация 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';
```
```lua
add_header 'Access-Control-Allow-Headers' 'Range';
```
Типы:
```nginx
types {
application/dash+xml mpd;
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
```
Если URI заканчивается на `.m3u8`:
```nginx
if ($uri ~ \.m3u8$) {
lua_code_cache off;
access_by_lua_file /opt/openresty/nginx/lua/access.lua;
}
root /home/tinywan/HLS;
```
#### <a name="access-lua">content of the file access.lua</a>
```Lua
if ngx.req.get_uri_args()["wsSecret"] ~= "e65e6a01cf26523e206d5bb0e2a8a95a" then
return ngx.exit(403)
end
```
#### <a name="lua-resty-string">lua-resty-string extension</a>
+ Пример использования 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 update data")
return
end
local digest = md5:final()
-- ngx.say("md5",digest) --- Note: direct output will be incorrect
local str = require "resty.string"
ngx.say("md5:", str.to_hex(digest)) --- Note: string must be converted for correct output
```
#### <a name="lua-resty-http">lua-resty-http extension (HTTP client for ngx_lua)</a>
+ [Simple test: lua-http-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-http/lua-http-test.lua)
#### <a name="lua-resty-mysql">lua-resty-mysql extension</a>
+ [Simple test: lua-msyql-test.lua](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Openresty/lua-resty-mysql/lua-msyql-test.lua)#### <a name="srcache-nginx-module">srcache-nginx-module расширение ([Кэширующий модуль для nginx](https://github.com/openresty/srcache-nginx-module))</a>
+ [Применение openresty-redis-srcache кэширования](http://www.xtgxiso.com/openresty-redis-srcache-nginx-module%e7%bc%93%e5%ad%90%e7%9a%84%e5%ba%94%e7%94%a8/)
#### <a name="openresty-scanner">OpenResty сканирование глобальных переменных</a>
+ В OpenResty следует избегать использования глобальных переменных. Для этого Чунго написал Perl-инструмент, который позволяет просканировать глобальные переменные в Lua-коде OpenResty.
+ [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 и выводить результат на экран```
При необходимости использовать команды в терминале:
```bash
chmod 777 lua-releng
./lua-releng test.lua
```#### <a name="Openresty_http_status_constants"/> Константы и методы 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.nginx_lua_version # версия модуля ngx_lua
ngx.config.nginx_version # версия NGINX
ngx.worker.exiting # закрывается ли текущий рабочий процесс
ngx.worker.pid # PID текущего рабочего процесса
ngx.config.nginx_configure # опции команды ./configure во время компиляции
ngx.config.prefix # опция prefix во время компиляции
```
+ ngx_lua методы (# часто вызываются в методах ngx.location.capture и 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, которая используется для хранения переменных контекста ngx на протяжении всего жизненного цикла запроса, подробнее см.официальную документацию
ngx.location.capture() # отправляет подзапрос, подробное использование см. в официальной документации.
```capture_multi() # выполняет несколько подзапросов, подробное описание см. в официальной документации.
ngx.status # читает или записывает текущий статус ответа запроса. Должен быть вызван до отправки заголовков ответа.
ngx.header.HEADER # получает или устанавливает информацию HTTP заголовка, подробное описание см. в официальной документации.
ngx.req.set_uri() # устанавливает URI текущего запроса, подробное описание см. в официальной документации.
ngx.set_uri_args(args) # переопределяет параметры URI текущего запроса согласно аргументу args.
ngx.req.get_uri_args() # возвращает LUA TABLE с параметрами URI текущего запроса.
ngx.req.get_post_args() # возвращает LUA TABLE с параметрами POST текущего запроса.
ngx.req.get_headers() # возвращает LUA TABLE с заголовками текущего запроса.
ngx.req.set_header() # устанавливает значение поля заголовка текущего запроса. Подзапросы текущего запроса не будут затронуты.
ngx.req.read_body() # без блокировки других событий nginx синхронно читает тело запроса клиента. [Подробное описание]
ngx.req.discard_body() # явно отбрасывает тело запроса клиента.
ngx.req.get_body_data() # получает содержимое тела запроса клиента в виде строки.
ngx.req.``````markdown
get_body_file() # При получении файла через запрос, возвращает имя файла.
ngx.req.set_body_data() # Устанавливает тело запроса клиента.
ngx.req.set_body_file() # Указывает файл данных текущего запроса по имени файла.
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, но вывод после ngx.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) # Преобразует таблицу в строку URL-параметров.
ngx.decode_args(uri) # Преобразует строку URL-параметров обратно в таблицу.
ngx.encode_base64(str) # Кодирует в BASE64.
ngx.decode_base64(str) # Раскодирует из BASE64.
```
Пожалуйста, проверьте, чтобы убедиться, что все изменения выполнены корректно.```markdown
crc32_short(str) # Вычислить короткий CRC32 хеш строки
ngx.crc32_long(str) # Вычислить длинный CRC32 хеш строки
ngx.hmac_sha1(str) # Вычислить HMAC-SHA1 хеш строки
ngx.md5(str) # Вернуть 16-ричное представление MD5 хеша
ngx.md5_bin(str) # Вернуть двоичное представление MD5 хеша
ngx.today() # Вернуть текущую дату в формате yyyy-mm-dd
ngx.time() # Вернуть текущее время в виде временной метки
ngx.now() # Вернуть текущее время
ngx.update_time() # Обновить время после выполнения команды
ngx.localtime() # Вернуть текущее время в формате yyyy-mm-dd hh:ii:ss
ngx.utctime() # Вернуть UTC время в формате yyyy-mm-dd hh:ii:ss
ngx.cookie_time(sec) # Вернуть время в формате, подходящем для использования в cookies
ngx.http_time(sec) # Вернуть время в формате, подходящем для использования в HTTP заголовках
ngx.parse_http_time(str) # Разобрать время из HTTP заголовка
ngx.is_subrequest # Определить является ли запрос подзапросом (значение true или false)
ngx.re.match(subject, regex, options, ctx) # Совпадение с помощью регулярного выражения ngx.re.match, подробнее см. официальную документацию
ngx.re.gmatch(subject, regex, opt) # Глобальное совпадение с помощью регулярного выражения
ngx.re.sub(sub, reg, opt) # Совпадение и замена (неизвестно)
ngx.re.gsub() # Неизвестно
ngx.shared.DICT # ngx.shared
```
Пожалуйста, обратите внимание на то, что некоторые функции содержали лишние пробелы перед `ngx.`. Эти пробелы были удалены для правильной записи вызова функций.DICT — это таблица, содержащая все глобальные переменные общего пользования
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
значение = ngx. HTTP_CONTINUE (100) (впервые добавлено в выпуске v0. 9. 20)
значение = ngx. HTTP_SWITCHING_PROTOCOLS (101) (впервые добавлено в выпуске v0. 9. 20)
``````markdown
value = ngx. HTTP_OK (200)
value = ngx. HTTP_CREATED (201)
value = ngx. HTTP_ACCEPTED (202) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_NO_CONTENT (204) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_PARTIAL_CONTENT (206) (впервые добавлено в выпуске v0. 9. 20)
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) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_BAD_REQUEST (400)
value = ngx. HTTP_UNAUTHORIZED (401)
value = ngx. HTTP_PAYMENT_REQUIRED (402) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_FORBIDDEN (403)
value = ngx. HTTP_NOT_FOUND (404)
value = ngx. HTTP_NOT_ALLOWED (405)
value = ngx. HTTP_NOT_ACCEPTABLE (406) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_REQUEST_TIMEOUT (408) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_CONFLICT (409) (впервые добавлено в выпуске v0. 9. 20)
value = ngx. HTTP_GONE (410)
value = ngx. HTTP_UPGRADE_REQUIRED (426) (впервые добавлено в выпуске v0. 9. 20)
value = ngx.HTTP_TOO_MANY_REQUESTS (429) (впервые добавлено в выпуске v0.9.20)
value = ngx.HTTP_CLOSE (444) (впервые добавлено в выпуске v0.9.20)
value = ngx.HTTP_ILLEGAL (451) (впервые добавлено в выпуске v0.9.20)
value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
value = ngx.HTTP_BAD_GATEWAY (502) (впервые добавлено в выпуске v0.9.20)
value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
value = ngx.HTTP_GATEWAY_TIMEOUT (504) (впервые добавлено в выпуске v0.3.1rc38)
value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (впервые добавлено в выпуске v0.9.20)
value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (впервые добавлено в выпуске v0.9.20)```
Пример использования `get_string_md5.lua`:
```lua
local args = ngx.req.get_uri_args()
local salt = args.salt
if not salt then
ngx.say("BAD_REQUEST")
end
local string_hash = ngx.md5(ngx.time() .. salt)
ngx.say(string_hash)
```
```Запрос с использованием `curl` (-i параметр, вывод включает протокольные заголовки):
```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
```
Дата: Fri, 21 Apr 2017 14:27:16 GMT
Тип содержимого: application/octet-stream
Передача данных: chunked
Соединение: keep-alive
#### <a name="Openresty_ngx_api_used"/> Введение в использование 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 bk 200 OK
Сервер: openresty/1.11.2.1
Дата: Sat, 22 Apr 2017 01:22:07 GMT
Тип содержимого: application/octet-stream
Передача данных: chunked
Соединение: keep-alive
{"user_agent":"curl/7.47.0","info":"overcome.wan@gmail.com","client_id":"127.0.0.1"}
```
#### <a name="Openresty_connent_cache"/> Кэширование в OpenResty
+ Инструкция: `lua_shared_dict` + Операция с чистой памятью, доступная всем worker процессам (например, если nginx запущен с 10 worker процессами, то каждый из них будет иметь доступ к этой памяти)
+ Та же самая информация доступна всем worker процессам, поэтому достаточно хранить одну версию данных.
+ Конкурентное использование (атомарность данных)
#### <a name="Openresty_lua_resty_upstream_healthcheck"/> Использование lua-resty-upstream-healthcheck
+ Создайте файл health.txt в корневом каталоге каждого серверного пула upstream, структура директорий следующая
```javascript
├── html
│ ├── 50x.html
│ ├── index.html
│ ├── websocket001.html
│ └── websocket02.html
├── html81
│ ├── 50x.html
│ ├── health.txt
│ └── index.html
├── html82
│ ├── 50x.html
│ ├── health.txt
│```
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;
}
``````Lua
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", -- определено как "lua_shared_dict"
upstream = "tomcat", -- определено как "upstream"
type = "http",
http_req = "GET /health.txt HTTP/1.0\r\nHost: tomcat\r\n\r\n",
-- сырая HTTP-запрос для проверки
interval = 2000, -- запустить цикл проверки каждые 2 секунды
timeout = 1000, -- 1 секунда - это время ожидания сетевых операций
fall = 3, -- количество последовательных ошибок перед отключением узла
rise = 2, -- количество последовательных успехов перед включением узла
valid_statuses = {200, 302}, -- список допустимых HTTP-статусов
concurrency = 10, -- уровень параллелизма для тестовых запросов
}
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://tomcat;
}
location /server/status {
access_log off;
allow 127.0.0.1;
``````markdown
## Страница состояния
Для просмотра состояния используйте адрес: `http://127.0.0.1/server/status`

### Проблема совместной работы OpenResty с Nginx_RTMP модулем
#### Проблема с отображением состояния потока RTMP (stat.xsl)
- После изменения конфигурационного файла nginx.conf:
- Выполнение команды `nginx -s reload` не работает
- Необходимо выполнить следующие действия: убить все процессы nginx (`sudo killall nginx`) и затем запустить nginx (`./sbin/nginx`)
```### Конфигурация RTMP модуля для множества рабочих процессов
Конфигурационный файл, [официальная документация 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 и максимальное количество клиентов](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 в качестве обратного прокси-сервера, он поддерживает одно соединение с клиентом и одно соединение с сервером.
+ Количество клиентов и пользователей
Одновременно количество клиентов (клиентских соединений) может отличаться от количества пользователей. Когда один пользователь отправляет запрос через одно соединение, эти значения равны. Однако, если один пользователь отправляет несколько параллельных запросов, то количество клиентов будет равно количеству пользователей, умноженному на число параллельных соединений.
```## Redis, Lua и Nginx вместе
+ Решение проблемы ограничения контекста команды set_by_lua $sum, решение найдено
+ - [x] [API отключен в контексте set_by_lua](https://github.com/openresty/lua-nginx-module/issues/275)
+ Решение 2
+ Решение 3
## Выполнение скриптов Lua в Redis
## Основные правила синтаксиса Lua
---
+ Привет, Lua! Наш первый скрипт Redis Lua возвращает лишь одну строку, не взаимодействуя с Redis каким-либо значимым образом.
```Lua
local msg = "Привет, мир!"
return msg
```
Это очень простое, первая строка кода определяет локальную переменную `msg`, которая хранит нашу информацию, вторая строка кода указывает на то, что значение `msg` будет возвращено клиенту от сервера Redis. Сохраните этот файл как `Hello.lua`. Вы можете запустить его следующим образом:
```bash
www@iZ239kcyg8rZ:~/lua$ redis-cli EVAL "$(cat Hello.lua)" 0
"Привет, мир!"
```
Запуск этого кода выводит `"Привет, мир!"`, где `EVAL` принимает в качестве первого аргумента наш Lua-скрипт, который мы читаем из файла с помощью команды `cat`. Второй аргумент представляет количество ключей, доступных для данного скрипта. Поскольку наш простой скрипт "Приветствие" не использует никаких ключей, мы передаем `0`.
### Различие между `redis.call()` и `redis.pcall()`
* Единственным различием является поведение при возникновении ошибки при выполнении Redis-команды.
* `redis.call()` вернёт вызывающему объекту ошибку.
* `redis.pcall()` вернёт захваченную ошибку в виде таблицы Lua.
* Оба эти функции могут принимать любую 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(man:GetName()) -- Вывод: Tinywan
man:SetName("New Name")
print(man:GetName()) -- Вывод: New Name
```
```Lua
местный человек = require('человек')
print("Имя человека - " .. человек:GetName())
человек:SetName("Phalcon")
print("Имя человека - " .. человек:GetName())
```
#### <a name="Redis_Run_Lua"/> Базовое использование команд Lua в Redis+ Формат команды EVAL
+ Основной синтаксис
```
EVAL скрипт numkeys ключ [ключ ...] аргумент [аргумент ...]
```
+ Смысл
1. `скрипт` — это Lua-скрипт или файл Lua-скрипта
1. `ключи` обычно указывают на ключи, с которыми работает Lua-скрипт; эти ключи можно получить через KEYS[i]
1. `аргументы` — внешние аргументы, передаваемые 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, которое возвращает массив из четырёх элементов, каждый из которых получен из внешних аргументов. Поскольку Redis имеет встроенную Lua-виртуальную машину, он принимает этот Lua-скрипт, передаёт его Lua-виртуальной машине для выполнения. Когда Lua-виртуальная машина завершает выполнение, она возвращает результат Redis, который затем преобразует результат согласно своему протоколу и отправляет ответ клиенту через TCP.+ Принятие параметров Lua-скрипта
+ Ключи: `KEYS[i]` используется для получения внешних ключей
+ Аргументы: `ARGV[i]` используется для получения внешних аргументов
+ Пример использования
+ Выполнение простого Lua-скрипта с помощью команды Redis `EVAL`
+ Добавление тестовых данных в 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
local names = redis.call('ZRANGE', key, offset, limit)
-- Таблица infos хранит все данные о веб-ресурсах
local infos = {}
-- Проходимся по всем найденным элементам
for i=1,#names do
local ck = names[i]
-- Получаем информацию о каждом веб-ресурсе через HGETALL
local info = redis.call('HGETALL', ck)
-- Добавляем имя хоста в конец информации
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() вставляет значение value в указанную позицию pos массива table. Параметр 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`
+ **Написание данных в 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("Ошибка подключения к Redis: ", 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("Не удалось установить значение для ключа ", key, ": ", err)
return
end
ngx.say("Результат установки значения: ", ok)
local res, err = red:get(key)
if not res then
ngx.say("Ошибка получения значения из Redis: ", err)
return
end
if res == ngx.null then
ngx.say(key, " не найден.")
return
end
``` red:close()
ngx.say("Успешное получение данных Redis", json.encode({content=res}))
```
+ конфигурация nginx
```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
Результат установки значения: OK
Успешное получение данных Redis{"content":"Tinywan1227::2017-04-16 15:57:56"}
```
+ получения всех значений из списка Redis по указанному ключу с помощью Lua скрипта
```Lua
local key = KEYS[1]
local list = redis.call("lrange", key, 0, -1)
return list
```### Lua скрипт для выполнения "уникализации" множества по IDList:```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) < tonumber(nums) then
table.insert(result, 1, v)
end
end
return result
```
## <a name="githubpush"/> Отправка кода в GitHub с помощью Visual Studio Code без ввода учетных данных
Для того чтобы не вводить имя пользователя и пароль при каждом входе в систему GitHub, можно использовать следующую команду в командной строке:
```bash
git config --global credential.helper store
```
> Этот шаг добавляет в конец файла `.gitconfig` в домашней директории пользователя следующее:
```
[credential]
helper = store
```
+ Отправка кода
> Отправьте свой код (`git push`). В этот момент вас попросят ввести имя пользователя и пароль. Эти данные будут запомнены, поэтому при следующей отправке кода вам не придётся снова вводить имя пользователя и пароль! В этом случае будет создан файл `.git-credentials` в домашней директории с информацией о вашем имени пользователя и пароле.
+ Техника создания гиперссылок в Markdown
> 【1】Адрес ссылки:
```
[Решение проблемы ввода учетных данных при отправке кода на GitHub](#githubpush)
```
> 【2】Место назначения ссылки:
```
<a name="githubpush"/> Решение проблемы ввода учетных данных при отправке кода на GitHub
```
> С помощью 【1】 и 【2】 вы сможете создать идеальную гиперссылку!
## <a name="Linux_base_knowledge"/> Основные знания о Linux+ Проверка правильной работы сетевой карты
1. Проверка корректности информации системного таблицы маршрутов
1. [Подробное описание команды Linux route и примеры использования](http://www.jb51.net/LINUXjishu/152385.html)
1. Пример вывода:
```
www@ubuntu1:/var/log$ route
Ядро IP таблиц маршрутизации
Destination Gateway Genmask Flags Metric Ref Use Iface
По умолчанию 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`
+ А сегмент IP адресов `10.10.101.0` предназначен только для передачи данных между локальными хостами и не имеет доступа к внешним соединениям, поэтому внешние системы не могут подключиться к серверу через этот сегмент сети
+ Если требуется сделать сегмент `10.10.101.0` доступным для внешних подсетей, то нужно удалить маршрут по умолчанию для `122.11.11.161` и добавить маршрут по умолчанию для сегмента `10` на сетевой карте `em2`.
+ Конкретные шаги:
```
www@ubuntu1:/var/log$ route delete default
www@ubuntu1:/var/log$ route add default gw 10.10.101.1
```
+ В этом случае внешние системы смогут подключаться к серверу через `ssh www@10.10.101.2`+ Команда find
+ Поиск и удаление файлов flv старше семи дней:
+ Команда:
```bash
find ./ -mindepth 1 -maxdepth 3 -type f -name "*.flv" -mmin +10080 | xargs rm -rf
```
+ `-type f` — поиск по типу файла
+ `-mmin +10080` — файлы старше семи дней
+ `xargs` работает аналогично `exec`, например, `find ~ -type f | xargs ls -l`
+ `-r` — рекурсивное удаление всех уровней вложенных директорий
+ `-f` — принудительное удаление без запроса подтверждения
+ Поиск файлов с расширением `.p`, отредактированных за последние 30 минут:
+ `find . -name '*.p' -type f -mmin -30`
+ Поиск файлов с расширением `.phtml`, отредактированных за последние 30 минут, и вывод подробной информации с помощью `ls`:
+ `find . -name '*.phtml' -type f -mmin -30 -ls`
+ Поиск обычных файлов, отредактированных за последний день:
+ `find . -type f -mtime -1`
+ Поиск обычных файлов, отредактированных за два дня до текущего момента:
+ `find . -type f -mtime +1`
# Копатель сайта Дзен# Lua-Ngx

# Пример работы
Изменения автоматически отображаются при наборе текста.
* Соответствует спецификации [CommonMark](http://commonmark.org/)
* Отображает реальные, "нативные" элементы React DOM
* Допускает возможность экранирования или пропуска HTML (попробуйте переключить флажки выше)
* Если вы экранируете или пропускаете HTML, то `dangerouslySetInnerHTML` не используется! Ура!
## Блок HTML ниже
<blockquote>
Эта цитата будет меняться в зависимости от настроек HTML выше.
</blockquote>
## А как насчет некоторых кодов?
```js
var React = require('react');
var Markdown = require('react-markdown');
React.render(
<Markdown source="# Ваш markdown здесь" />,
document.getElementById('content')
);
```
Очень круто, правда?
## Больше информации?
Чтение информации о использовании и более подробной информации на [GitHub](//github.com/rexxars/react-markdown)
---------------
Компонент от [VaffelNinja](http://vaffel.ninja) / Espen Hovlandsdal
## <a name="Linux_base_knowledge"/> Авторское право и лицензия
Этот модуль лицензирован под лицензией BSD
Авторское право © 2017 года, Вансяobao "Tinywan".
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )