Эта статья для практики основана на Centos8. Читателям предлагается установить OpenResty самостоятельно.
1. Внутренний звонок
Введите путь установки по умолчанию
cd /usr/local/openresty/nginx/conf
vim nginx.conf
location /sum {
# 只允许内部调用
internal;
content_by_lua_block {
local args = ngx.req.get_uri_args()
ngx.print(tonumber(args.a) + tonumber(args.b))
}
}
2. Параллельные запросы
location /multi {
content_by_lua_block {
local start_time = ngx.now()
local res1, res2 = ngx.location.capture_multi( {
{
"/sum", {
args={
a=3, b=8}}},
{
"/sum", {
args={
a=3, b=8}}}
})
ngx.say("status:", res1.status, " response:", res1.body)
ngx.say("status:", res2.status, " response:", res2.body)
ngx.say("time used:", ngx.now() - start_time)
}
}
3. Прыжок по трубопроводу
location /exec {
content_by_lua_block {
ngx.exec("/sum?a=6&b=8")
}
}
ngx.redirect — это перенаправление. Например, при доступе к baidu.com произойдет перенаправление на https://baidu.com.
Метод ngx.exec полностью отличается от ngx.redirect. Первый представляет собой чисто внутренний переход и не вносит никаких дополнительных HTTP-сигналы.
4. Получите параметры GET и POST.
location /print_param {
content_by_lua_block {
local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
ngx.say("[GET ] key:", k, " v:", v)
end
ngx.req.read_body()
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
ngx.say("[POST] key:", k, " v:", v)
end
}
}
5. Передача параметров во внутренние методы
location /test {
content_by_lua_block {
local res = ngx.location.capture(
'/print_param',
{
method = ngx.HTTP_POST,
args = ngx.encode_args({
a = 1, b = '2&'}),
body = ngx.encode_args({
c = 3, d = '4&'})
}
)
ngx.say(res.body)
}
}
6. Получите тело запроса
# 默认读取 body
lua_need_request_body on;
location /get_body_data {
content_by_lua_block {
local data = ngx.req.get_body_data()
ngx.say("hello ", data)
}
}
7. Тело выходного ответа
ngx.say и ngx.print являются асинхронными выходами.
Как корректно обработать вывод со слишком большим телом ответа?
Если тело ответа относительно небольшое, это относительно легко. Однако, если тело ответа слишком велико, API не может быть напрямую вызван для завершения вывода тела ответа. Тело ответа слишком велико. Возможны две ситуации:
① Сам выходной контент очень велик, например, большие загрузки файлов.
② Сам выходной контент состоит из различных фрагментов, а количество фрагментов огромно, например, все данные ответа представляют собой адресные данные в определенной области.
В первом случае необходимо использовать функцию кодирования CHUNKED HTTP 1.1. Используйте формат CHUNKED, чтобы разделить большое тело ответа на несколько маленьких тел ответа и отвечать запрашивающей стороне пакетно и контролируемым образом.
# 开启chunked编码
chunked_transfer_encoding on;
location /download_large_file {
content_by_lua_block {
-- ngx.var.limit_rate = 1024*1024
local file, err = io.open(ngx.config.prefix() .. "data.db","r")
if not file then
ngx.log(ngx.ERR, "open file error:", err)
ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
local data
while true do
data = file:read(1024*1024)
if nil == data then
break
end
ngx.print(data)
ngx.flush(true)
end
file:close()
}
}
Мы /usr/local/openresty/nginx
подготавливаем файл data.db в каталоге, читаем содержимое локального файла блоками (каждый раз по 1 МБ) и отвечаем в потоковом режиме.
Во втором случае на самом деле можно воспользоваться возможностями ngx.print: его входным параметром может быть один или несколько строковых параметров или табличный объект.
local table = {
"hello, ",
{
"world: ", true, " or ", false,
{
": ", nil}}
}
ngx.print(table)
выведет:
hello, world: true or false: nil
То есть, когда имеется много фрагментированных данных, нет необходимости объединять их в строку перед выводом. Его можно хранить непосредственно в таблице, использовать массив для объединения этих фрагментированных данных и напрямую вызывать ngx.print(table). Этот подход более эффективен и его легче оптимизировать.
Добро пожаловать в нишу алгоритмов общедоступных аккаунтов