1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/Tinywan-lua-nginx-redis

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
README_BAK.md 120 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 08.03.2025 14:58 19f15bb

Содержание

Базовые знания о Nginx

Учебники по Nginx от agentzh (версия 2016.07.21)

  • Адрес учебников по Nginx от agentzh
  • Размышления о переменных Nginx (часть 1)
    • Переменные Nginx имеют только один тип значения — строковый.
    • "Переменная интерполяция" в Nginx
      location /test {
          set $first "hello ";
          echo "${first}world";
      }
    • Инструкция set (а также упомянутая ранее geo) выполняет двойную роль: она присваивает значение переменной, а также создает новую переменную Nginx, если таковая ещё не существует.
    • Область видимости переменной Nginx после её создания охватывает весь конфигурационный файл Nginx, даже если она используется между различными блоками сервера.
    • Жизненный цикл переменной Nginx не может пересекать границы запросов.
  • Размышления о переменных Nginx (часть 2)
    • Переходы + Внутренний переход: это перемещение внутри сервера от одного локейшена к другому во время обработки запроса.
      • Внешний переход: это "внешний переход", осуществляемый HTTP-статусами 301 и 302.
    • Конфигурационная директива rewrite модуля ngx_rewrite также может вызывать внутренние переходы.
    • Предопределённые переменные, предоставляемые ядром Nginx и его модулями.
    • Nginx автоматически преобразует все ключевые слова запроса в нижний регистр перед тем как они будут использоваться.
    • При попытке изменения некоторых только доступных переменных, таких как $arg_XXX, в некоторых версиях Nginx это может привести к аварийному завершению процесса.
  • Размышления о переменных Nginx (часть 4)
    • Директива map: используется для определения отношений между двумя переменными Nginx или функциональной зависимости.
    • Директива map может использоваться только внутри блока http.
    • Конфигурационные директивы map работают путём регистрации "получательных процедур" для переменных пользователя, а реальная операция отображения выполняется внутри этих "получательных процедур".Эти процедуры запускаются только при фактическом чтении переменной пользователем (благодаря кэшированию, они запускаются только при первой попытке чтения в течение жизни запроса), поэтому для запросов, которые вообще не используют эти переменные, никакие бесполезные вычисления не будут выполнены.
  • Беседа о переменных Nginx (часть 4)
  • 11 этапов работы Nginx
  • Ловушки и распространённые ошибки Nginx
  • Оптимизация ядра системы с высокой пропускной способностью Nginx

Redis базовые знания

PHP скрипты

Bash скрипты

Базовые знания Lua

Lua основной синтаксис

  • Удаление глобальной переменной можно присвоить её значением 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
  • Выражения

    • Если два значения имеют разные типы, то Lua считает их различными.
    • Nil равен только самому себе.
    • Логические операторы
      -- 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, ","))
```#### Контрольные конструкции

Пример простого упаковывания в Lua

Операции с таблицами

  • 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])`
    • Сортирует указанную таблицу по возрастанию

Lua модули и пакеты

  • Определение: Модуль Lua представляет собой таблицу, содержащую известные элементы, такие как переменные и функции. Таким образом, создание модуля очень просто — достаточно создать таблицу и поместить в неё необходимые константы и функции, после чего вернуть эту таблицу.

Стриминговое видео: прямое вещание и VOD

Глава 1: Начало работы

Глава 2: Установка и развертывание

  • Ошибки при запуске: Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use), исполните: sudo fuser -k 80/tcp
  • Настройка виртуальных хостов на основе домена и IP
  • Полная и стандартная конфигурация с примерами
  • Настройка и разделение лог-файлов
  • Применение 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. При запросе curl /live/index.html, Nginx будет искать файл /home/tinywan/HLS/index.html на сервере.
      2. Запрошенная часть 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-лог: rewrite_log on;):
        /home/tinywan/HLS/txt.txt/live/txt.txt
      • Основные различия:
        1. Каталог, указанный в alias, является текущим каталогом.
        2. Каталог, указанный в root, является корневым каталогом.
          1. Обычно рекомендуют использовать команду root внутри конфигурации location /, а остальные пути совпадения использовать командой alias.
    • Случай [3]:
      • Конфигурационная информация:
         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. Начальный взгляд на архитектуру
  • Тест 1#### Глава 4. Продвинутые конфигурации
  • Базовый синтаксис: location [=||*|^~] /uri/ { ... }
    1. = строгое соответствие. Если запрос соответствует этому правилу, то поиск прекращается и данный запрос обрабатывается немедленно.
    2. ~ регистрозависимое соответствие (можно использовать регулярные выражения)
    3. ! ~ регистрозависимое несоответствие
    4. ! ~* регистронезависимое несоответствие
    5. ^~ если этот префикс используется для обычной строки, то Nginx будет знать, что если путь соответствует, то нет необходимости проверять регулярные выражения
  • Справочник Perl регулярных выражений
  • Краткий список специальных символов, требующих экранирования в регулярных выражениях
    • [1] $ соответствует окончанию входной строки. Если установлено свойство multiline объекта RegExp, то $ также соответствует '\n' или '\r'. Чтобы найти символ $ сам по себе, используйте $.
    • [2] ( ) отмечает начало и конец подвыражения. Подвыражение можно использовать для дальнейшего использования. Чтобы найти эти символы, используйте ( и ).
    • [3] * соответствует нулевому или более повторам предыдущего подвыражения. Чтобы найти символ *, используйте *.
    • [4] + соответствует одному или более повторам предыдущего подвыражения.Чтобы найти символ +, используйте +.
    • [5] \. соответствует любому одиночному символу, кроме символа новой строки \n. Чтобы найти символ . , используйте ..
    • [6] [ ] отмечает начало выражения в квадратных скобках. Чтобы найти символ [, используйте [.
    • [7] \? соответствует нулю или одному повтору предыдущего подвыражения, или указывает на неголодный ограничитель. Чтобы найти символ ? , используйте ?.
    • [8] \\ отмечает следующий символ как метасимвол, специальный символ, буквенный символ, обратную ссылку или восходящую последовательность. Например, 'n' соответствует букве 'n', '\n' соответствует символу новой строки, последовательность '\' соответствует '\', а '(' соответствует '('.
    • [9] \^ соответствует началу входной строки, за исключением случаев, когда он используется внутри выражения в квадратных скобках, где он указывает на отказ принять набор символов. Чтобы найти символ ^, используйте ^.
    • [10] \{ отмечает начало выражения ограничителя. Чтобы найти символ {, используйте {.
    • [11] \| указывает выбор между двумя элементами. Чтобы найти символ |, используйте |.

Регулярные выражения (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/; }

Глава 5. Gzip сжатие

  • Тест 1

Глава 6. Возможность 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 Значение заголовка 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 относителен)

      • 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
  • Перезапись регулярным выражением параметра uri

    1. Пример запроса: curl http://192.168.18.143/live/tinywan123/index.m3u8
    2. Конфигурационный файл 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";
      }
    3. Результат вывода
         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 ::
    4. \$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;
      }

8 глава Кэширование механизмы

  • Тест 1

9 глава Начальный взгляд на Nginx 1

  • Тест 1

10 глава Начальный взгляд на Nginx 1

  • Тест 1

PHP скрипт выполнение Redis + PHP скрипт выполняющий функцию подписки Redis для прослушивания событий истечения ключей, возвращает обратный вызов, API принимает данное событие (источник)

  • Однострочный текст 1

Основы OpenResty

  • Информация по установке
  • По умолчанию конфигурационная информация
  • Начало работы
    • Общее расположение директорий Nginx и Lua
      .
      ├── 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
    • Сводка параметров
      • Lua скрипт принимает переменные 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.

      • Lua скрипт принимает заголовки HTTP:

        [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'].

      • Lua скрипт получает параметры URI запроса:

        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
    + ![Nginx+Lua+локальный Redis+MySQL](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Images/Nginx%2BLua%2BLocal_Redis%2BMysql.png)
    + [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:

      ![](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Images/websocket_lua01.png)

#### <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`

![Markdown](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Images/Openresty_lua-resty-upstream-healthcheck.png)

### Проблема совместной работы 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`
        
# Копатель сайта Дзен![Markdown](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Images/github_good1.png)# Lua-Ngx
![Markdown](https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Images/Nginx-Phase.png)
# Пример работы

Изменения автоматически отображаются при наборе текста.

* Соответствует спецификации [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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/Tinywan-lua-nginx-redis.git
git@api.gitlife.ru:oschina-mirror/Tinywan-lua-nginx-redis.git
oschina-mirror
Tinywan-lua-nginx-redis
Tinywan-lua-nginx-redis
master