---
title: "Introdução de APIs comuns no OpenResty - API7.ai"
description: "Este artigo irá apresentar a você o uso das APIs comuns do OpenResty para manipulação de tempo, expressões regulares e outras questões comuns."
url: "https://api7.ai/pt/learning-center/openresty/introduction-openresty-common-apis"
---

# Introdução de APIs comuns no OpenResty

API7.ai

November 4, 2022

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

Nos artigos anteriores, você se familiarizou com muitas APIs importantes do Lua no OpenResty. Hoje, vamos aprender sobre algumas outras APIs gerais, principalmente relacionadas a expressões regulares, tempo, processos, etc.

## APIs relacionadas a Expressões Regulares

Vamos começar olhando para as expressões regulares mais comumente usadas e mais importantes. No OpenResty, devemos usar o conjunto de APIs fornecido por `ngx.re.*` para lidar com a lógica relacionada a expressões regulares, em vez de usar a correspondência de padrões do Lua. Isso não é apenas por questões de desempenho, mas também porque a regularidade do Lua é autossuficiente e não é uma especificação `PCRE`, o que seria irritante para a maioria dos desenvolvedores.

Nos artigos anteriores, você já conheceu algumas das APIs `ngx.re.*`, cuja documentação é muito detalhada. Portanto, não vou listá-las novamente. Aqui, vou apresentar separadamente as duas APIs a seguir.

### `ngx.re.split`

A primeira é `ngx.re.split`. O corte de strings é uma função muito comum, e o OpenResty também fornece uma API correspondente, mas muitos desenvolvedores não conseguem encontrar essa função e acabam optando por implementá-la por conta própria.

Por quê? A API `ngx.re.split` não está no `lua-nginx-module`, mas no `lua-resty-core`; ela não está na documentação da página inicial do `lua-resty-core`, mas na documentação do diretório de terceiro nível `lua-resty-core/lib/ngx/re.md`. Como resultado, muitos desenvolvedores não têm conhecimento da existência dessa API.

Da mesma forma, APIs difíceis de descobrir incluem `ngx_resp.add_header`, `enable_privileged_agent`, etc., que mencionamos anteriormente. Então, como podemos resolver rapidamente esse problema? Além de ler a documentação da página inicial do `lua-resty-core`, você precisa ler a documentação `*.md` no diretório `lua-resty-core/lib/ngx/`.

### `lua_regex_match_limit`

Em segundo lugar, quero apresentar `lua_regex_match_limit`. Não falamos sobre os comandos NGINX fornecidos pelo OpenResty antes porque, na maioria dos casos, os valores padrão são suficientes e não há necessidade de modificá-los em tempo de execução. A exceção a isso é o comando `lua_regex_match_limit`, que está relacionado a expressões regulares.

Sabemos que se usarmos um motor de expressões regulares que é implementado com base em NFA de retrocesso, então há o risco de Retrocesso Catastrófico, onde a expressão regular retrocede demais ao corresponder, causando 100% de uso da CPU e bloqueando os serviços.

Uma vez que ocorre um retrocesso catastrófico, precisamos usar `gdb` para analisar o dump ou usar `systemtap` para analisar o ambiente online para localizá-lo. Infelizmente, detectá-lo antecipadamente não é fácil porque apenas solicitações especiais o acionam. Isso permite que os atacantes se aproveitem disso, e `ReDoS` (RegEx Denial of Service) se refere a esse tipo de ataque.

Aqui, vou apresentar como usar a seguinte linha de código no OpenResty para evitar os problemas acima de forma simples e eficaz:

`lua_regex_match_limit` é usado para limitar o número de retrocessos pelo motor de expressões regulares `PCRE`. Dessa forma, mesmo que ocorra um retrocesso catastrófico, as consequências serão limitadas a um intervalo que não causará o uso total da CPU.

```
lua_regex_match_limit 100000;
```

## APIs relacionadas a Tempo

A API de tempo mais comumente usada é `ngx.now`, que imprime o timestamp atual, como na seguinte linha de código:

```
resty -e 'ngx.say(ngx.now())'
```

Como você pode ver pelos resultados impressos, `ngx.now` inclui a parte fracionária, então é mais preciso. A API relacionada `ngx.time` retorna apenas a parte inteira do valor. As outras, `ngx.localtime`, `ngx.utctime`, `ngx.cookie_time` e `ngx.http_time`, são usadas principalmente para retornar e processar o tempo em diferentes formatos. Se você quiser usá-las, pode verificar a documentação, elas não são difíceis de entender, então não preciso falar sobre elas.

No entanto, vale a pena mencionar que **essas APIs que retornam o tempo atual, se não forem acionadas por uma operação de IO de rede não bloqueante, sempre retornarão o valor em cache, em vez do tempo real atual como gostaríamos**. Veja o seguinte código de exemplo:

```
$ resty -e 'ngx.say(ngx.now())
os.execute("sleep 1")
ngx.say(ngx.now())'
```

Entre as duas chamadas para `ngx.now`, usamos a função de bloqueio do Lua para dormir por `1` segundo, mas o timestamp retornado é o mesmo nas duas ocasiões, como mostrado pelos resultados impressos.

Então, e se substituirmos por uma função de sono não bloqueante? Por exemplo, o seguinte novo código:

```
$ resty -e 'ngx.say(ngx.now())
ngx.sleep(1)
ngx.say(ngx.now())'
```

Ele imprimirá um timestamp diferente. Isso nos leva a `ngx.sleep`, uma função de sono não bloqueante. Além de dormir por um tempo especificado, essa função tem outro propósito especial.

Por exemplo, se você tiver um código que está fazendo cálculos intensivos, o que leva muito tempo, as solicitações correspondentes a esse código continuarão ocupando recursos do worker e da CPU durante esse tempo, causando o enfileiramento de outras solicitações e a falta de resposta oportuna. Nesse momento, podemos intercalar `ngx.sleep(0)` para fazer com que esse código desista do controle, permitindo que outras solicitações também sejam processadas.

## APIs de Worker e Processo

O OpenResty fornece as APIs `ngx.worker.*` e `ngx.process.*` para obter informações sobre workers e processos. A primeira se refere aos processos worker do Nginx, enquanto a segunda se refere a todos os processos do Nginx em geral, não apenas aos processos worker, mas também ao processo master, processo privilegiado, etc.

## O problema dos valores `true` e `null`

Finalmente, vamos olhar para o problema dos valores `true` e `null`. No OpenResty, a determinação dos valores `true` e `null` tem sido um ponto muito problemático e confuso.

Vamos olhar para a definição de um valor `true` em Lua: exceto `nil` e `false`, todos são valores `true`.

Portanto, valores `true` também incluiriam `0`, `string` vazia, `table` vazia, etc.

Vamos olhar para `nil` em Lua, que significa `indefinido`. Por exemplo, se você declarar uma variável, mas não a inicializar, seu valor é `nil`.

```
$ resty -e 'local a
ngx.say(type(a))'
```

E `nil` também é um tipo de dado em Lua. Tendo entendido esses dois pontos, vamos agora olhar para os outros problemas derivados dessas duas definições.

### `ngx.null`

O primeiro problema é `ngx.null`. Como o `nil` do Lua não pode ser usado como o valor de uma `table`, o OpenResty introduz `ngx.null` como o valor `null` na tabela.

```
$ resty -e  'print(ngx.null)'
null
```

```
$ resty -e 'print(type(ngx.null))'
userdata
```

Como você pode ver pelos dois códigos acima, `ngx.null` é impresso como `null`, e seu tipo é `userdata`, então ele pode ser tratado como um valor `false`? Claro que não. O valor booleano de `ngx.null` é `true`.

```
$ resty -e 'if ngx.null then
ngx.say("true")
end'
```

Portanto, lembre-se de que apenas `nil` e `false` são valores `false`. Se você perder esse ponto, é fácil cair em armadilhas, por exemplo, ao usar `lua-resty-redis` e fazer o seguinte julgamento:

```
local res, err = red:get("dog")
if not res then
    res = res + "test"
end
```

Se o valor de retorno `res` for `nil`, a chamada da função falhou; se `res` for `ngx.null`, a chave `dog` não existe no redis, então o código falha se a chave `dog` não existir.

### `cdata:NULL`

O segundo problema é `cdata:NULL`. Quando você chama uma função C através da interface FFI do LuaJIT, e a função retorna um ponteiro `NULL`, então você encontrará outro tipo de valor `null`, `cdata:NULL`.

```
$ resty -e 'local ffi = require "ffi"
local cdata_null = ffi.new("void*", nil)
if cdata_null then
    ngx.say("true")
end'
```

Como `ngx.null`, `cdata:NULL` também é `true`. Mas o que é mais intrigante é que o seguinte código, que imprime `true`, significa que `cdata:NULL` é equivalente a `nil`.

```
$ resty -e 'local ffi = require "ffi"
local cdata_null = ffi.new("void*", nil)
ngx.say(cdata_null == nil)'
```

Então, como devemos lidar com `ngx.null` e `cdata:NULL`? Não é uma boa solução deixar a camada de aplicação cuidar desses problemas. É melhor fazer um wrapper de segundo nível e não deixar que o chamador saiba desses detalhes.

É melhor fazer um wrapper de segundo nível e não deixar que o chamador saiba desses detalhes.

### `cjson.null`

Finalmente, vamos olhar para os valores `null` que aparecem no `cjson`. A biblioteca `cjson` pega o `NULL` no json, decodifica-o em `lightuserdata` do Lua e usa `cjson.null` para representar.

```
$ resty -e 'local cjson = require "cjson"
local data = cjson.encode(nil)
local decode_null = cjson.decode(data)
ngx.say(decode_null == cjson.null)'
```

O `nil` do Lua se torna `cjson.null` após ser codificado e decodificado pelo JSON. Como você pode imaginar, ele é introduzido pela mesma razão que `ngx.null`, porque `nil` não pode ser usado como valor em uma `table`.

Até agora, você ficou confuso com tantos tipos de valores `null` no OpenResty? Não se preocupe. Leia esta parte algumas vezes e organize-a você mesmo, então você não ficará confuso. Claro, precisamos pensar mais no futuro sobre se funciona ao escrever algo como `if not foo then`.

## Resumo

O artigo de hoje apresentou as APIs do Lua comumente usadas no OpenResty.

Finalmente, vou deixar uma pergunta: No exemplo `ngx.now`, por que o valor de `ngx.now` não é modificado quando não há operação de `yield`? Sinta-se à vontade para compartilhar sua opinião nos comentários, e também para compartilhar este artigo para que possamos nos comunicar e melhorar juntos.

Share article link

Share

Related Posts

[![FAQ do OpenResty | Como o OpenResty é usado na prática](https://static.api7.ai/uploads/2023/02/12/jbv9M0zi_Hello%20World%20in%20OpenResty%20%283%29.png)](https://api7.ai/learning-center/openresty/faq-5)

## [FAQ do OpenResty | Como o OpenResty é usado na prática](https://api7.ai/learning-center/openresty/faq-5)

[![Parte 3: Como Construir um API Gateway de Microservices Usando OpenResty](https://static.api7.ai/uploads/2023/02/07/3XJXY9Jy_45.png)](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

## [Parte 3: Como Construir um API Gateway de Microservices Usando OpenResty](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [APIs relacionadas a Expressões Regulares](#apis-relacionadas-a-express%C3%B5es-regulares)

  - [`ngx.re.split`](#ngxresplit)
  - [`lua_regex_match_limit`](#lua_regex_match_limit)

- [APIs relacionadas a Tempo](#apis-relacionadas-a-tempo)

- [APIs de Worker e Processo](#apis-de-worker-e-processo)

- [O problema dos valores `true` e `null`](#o-problema-dos-valores-true-e-null)

  - [`ngx.null`](#ngxnull)
  - [`cdata:NULL`](#cdatanull)
  - [`cjson.null`](#cjsonnull)

- [Resumo](#resumo)
