---
title: "Introducción a las APIs comunes en OpenResty - API7.ai"
description: "Este artículo te introducirá al uso de las APIs comunes de OpenResty para la manipulación del tiempo, expresiones regulares y otros problemas comunes."
url: "https://api7.ai/es/learning-center/openresty/introduction-openresty-common-apis"
---

# Introducción a las APIs comunes en OpenResty

API7.ai

November 4, 2022

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

En los artículos anteriores, te has familiarizado con muchas API importantes de Lua en OpenResty. Hoy, aprenderemos sobre algunas otras API generales, principalmente relacionadas con expresiones regulares, tiempo, procesos, etc.

## API relacionadas con Expresiones Regulares

Comencemos por ver las expresiones regulares más utilizadas y más importantes. En OpenResty, deberíamos usar el conjunto de API proporcionado por `ngx.re.*` para manejar la lógica relacionada con expresiones regulares en lugar de usar la coincidencia de patrones de Lua. Esto no solo es por razones de rendimiento, sino también porque la regularidad de Lua es autónoma y no es una especificación `PCRE`, lo que sería molesto para la mayoría de los desarrolladores.

En los artículos anteriores, ya te has encontrado con algunas de las API de `ngx.re.*`, cuya documentación es muy detallada. Por lo tanto, no las enumeraré más. Aquí, presentaré las siguientes dos API por separado.

### `ngx.re.split`

La primera es `ngx.re.split`. El corte de cadenas es una función muy común, y OpenResty también proporciona una API correspondiente, pero muchos desarrolladores no pueden encontrar tal función y tienen que elegir implementarla ellos mismos.

¿Por qué? La API `ngx.re.split` no está en `lua-nginx-module` sino en `lua-resty-core`; no está en la documentación de la página principal de `lua-resty-core` sino en la documentación del directorio de tercer nivel `lua-resty-core/lib/ngx/re.md`. Como resultado, muchos desarrolladores desconocen por completo la existencia de esta API.

De manera similar, las API difíciles de descubrir incluyen `ngx_resp.add_header`, `enable_privileged_agent`, etc., que mencionamos anteriormente. Entonces, ¿cómo resolvemos rápidamente este problema? Además de leer la documentación de la página principal de `lua-resty-core`, también necesitas leer la documentación `*.md` en el directorio `lua-resty-core/lib/ngx/`.

### `lua_regex_match_limit`

En segundo lugar, quiero presentar `lua_regex_match_limit`. No hemos hablado antes sobre los comandos de NGINX proporcionados por OpenResty porque, en la mayoría de los casos, los valores predeterminados son suficientes y no es necesario modificarlos en tiempo de ejecución. La excepción a esto es el comando `lua_regex_match_limit`, que está relacionado con expresiones regulares.

Sabemos que si usamos un motor de expresiones regulares que está implementado basado en NFA con retroceso, entonces existe el riesgo de Retroceso Catastrófico, donde la expresión regular retrocede demasiado al coincidir, causando que la CPU llegue al 100% y los servicios se bloqueen.

Una vez que ocurre un retroceso catastrófico, necesitamos usar `gdb` para analizar el volcado o usar `systemtap` para analizar el entorno en línea para localizarlo. Desafortunadamente, detectarlo de antemano no es fácil porque solo solicitudes especiales lo activarán. Esto permite que los atacantes aprovechen esto, y `ReDoS` (Denegación de Servicio por Expresiones Regulares) se refiere a este tipo de ataque.

Aquí, principalmente te presento cómo usar la siguiente línea de código en OpenResty para evitar los problemas anteriores de manera simple y efectiva:

`lua_regex_match_limit` se usa para limitar el número de retrocesos por el motor de expresiones regulares `PCRE`. De esta manera, incluso si ocurre un retroceso catastrófico, las consecuencias se limitarán a un rango que no causará que tu CPU se sature.

```
lua_regex_match_limit 100000;
```

## API relacionadas con el Tiempo

La API de tiempo más utilizada es `ngx.now`, que imprime la marca de tiempo actual, como la siguiente línea de código:

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

Como puedes ver en los resultados impresos, `ngx.now` incluye la parte fraccional, por lo que es más precisa. La API relacionada `ngx.time` solo devuelve la parte entera del valor. Las otras, `ngx.localtime`, `ngx.utctime`, `ngx.cookie_time` y `ngx.http_time`, se utilizan principalmente para devolver y procesar el tiempo en diferentes formatos. Si deseas usarlas, puedes consultar la documentación, no son difíciles de entender, por lo que no necesito hablar de ellas.

Sin embargo, vale la pena mencionar que **estas API que devuelven el tiempo actual, si no son activadas por una operación de IO de red no bloqueante, siempre devolverán el valor en caché en lugar del tiempo real actual como nos gustaría**. Mira el siguiente código de ejemplo:

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

Entre las dos llamadas a `ngx.now`, usamos la función de bloqueo de Lua para dormir durante `1` segundo, pero la marca de tiempo devuelta es la misma en ambas ocasiones, como se muestra en los resultados impresos.

Entonces, ¿qué pasa si lo reemplazamos con una función de sueño no bloqueante? Por ejemplo, el siguiente código nuevo:

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

Imprimirá una marca de tiempo diferente. Esto nos lleva a `ngx.sleep`, una función de sueño no bloqueante. Además de dormir durante una cantidad de tiempo especificada, esta función tiene otro propósito especial.

Por ejemplo, si tienes un fragmento de código que está haciendo cálculos intensivos, lo que lleva mucho tiempo, las solicitudes correspondientes a este fragmento de código seguirán ocupando recursos de worker y CPU durante este tiempo, causando que otras solicitudes se acumulen y no obtengan una respuesta oportuna. En este punto, podemos intercalar `ngx.sleep(0)` para que este código ceda el control y otras solicitudes también puedan ser procesadas.

## API de Worker y Proceso

OpenResty proporciona las API `ngx.worker.*` y `ngx.process.*` para obtener información sobre workers y procesos. El primero se relaciona con los procesos worker de Nginx, mientras que el segundo se refiere a todos los procesos de Nginx en general, no solo los procesos worker, sino también el proceso maestro, el proceso privilegiado, etc.

## El problema de los valores `true` y `null`

Finalmente, veamos el problema de los valores `true` y `null`. En OpenResty, la determinación de los valores `true` y `null` ha sido un punto muy problemático y confuso.

Veamos la definición de un valor `true` en Lua: excepto `nil` y `false`, todos son valores `true`.

Por lo tanto, los valores `true` también incluirían `0`, cadena vacía, tabla vacía, etc.

Veamos `nil` en Lua, que significa `indefinido`. Por ejemplo, si declaras una variable pero no la has inicializado, su valor es `nil`.

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

Y `nil` también es un tipo de dato en Lua. Habiendo entendido estos dos puntos, ahora veamos los otros problemas derivados de estas dos definiciones.

### `ngx.null`

El primer problema es `ngx.null`. Debido a que el `nil` de Lua no puede usarse como el valor de una `tabla`, OpenResty introduce `ngx.null` como el valor `null` en la tabla.

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

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

Como puedes ver en los dos fragmentos de código anteriores, `ngx.null` se imprime como `null`, y su tipo es `userdata`, entonces, ¿puede tratarse como un valor `false`? Por supuesto que no. El valor booleano de `ngx.null` es `true`.

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

Por lo tanto, recuerda que solo `nil` y `false` son valores `false`. Si pasas por alto este punto, es fácil caer en trampas, por ejemplo, cuando usas `lua-resty-redis` y haces el siguiente juicio:

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

Si el valor de retorno `res` es `nil`, la llamada a la función ha fallado; si `res` es `ngx.null`, la clave `dog` no existe en redis, entonces el código falla si la clave `dog` no existe.

### `cdata:NULL`

El segundo problema es `cdata:NULL`. Cuando llamas a una función C a través de la interfaz FFI de LuaJIT, y la función devuelve un puntero `NULL`, entonces te encontrarás con otro 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'
```

Al igual que `ngx.null`, `cdata:NULL` también es `true`. Pero lo más desconcertante es que el siguiente código, que imprime `true`, significa que `cdata:NULL` es equivalente a `nil`.

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

Entonces, ¿cómo deberíamos manejar `ngx.null` y `cdata:NULL`? No es una buena solución dejar que la capa de aplicación se preocupe por estos problemas. Es mejor hacer un envoltorio de segundo nivel y no dejar que el llamador conozca estos detalles.

Es mejor hacer un envoltorio de segundo nivel y no dejar que el llamador conozca estos detalles.

### `cjson.null`

Finalmente, veamos los valores `null` que aparecen en `cjson`. La biblioteca `cjson` toma el `NULL` en json, lo decodifica en `lightuserdata` de Lua y usa `cjson.null` para representarlo.

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

El `nil` de Lua se convierte en `cjson.null` después de ser codificado y decodificado por JSON. Como puedes imaginar, se introduce por la misma razón que `ngx.null`, porque `nil` no puede usarse como un valor en una `tabla`.

Hasta ahora, ¿te has confundido con tantos tipos de valores `null` en OpenResty? No te preocupes. Lee esta parte varias veces y ordénala tú mismo, entonces no te confundirás. Por supuesto, necesitamos pensar más en el futuro sobre si funciona cuando escribimos algo como `if not foo then`.

## Resumen

El artículo de hoy te presenta las API de Lua comúnmente utilizadas en OpenResty.

Finalmente, te dejo una pregunta: En el ejemplo de `ngx.now`, ¿por qué el valor de `ngx.now` no se modifica cuando no hay una operación de `yield`? Bienvenido a compartir tu opinión en los comentarios, y también te invito a compartir este artículo para que podamos comunicarnos y mejorar juntos.

Share article link

Share

Related Posts

[![Preguntas frecuentes de OpenResty | Cómo se utiliza OpenResty en la práctica](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)

## [Preguntas frecuentes de OpenResty | Cómo se utiliza OpenResty en la práctica](https://api7.ai/learning-center/openresty/faq-5)

[![Parte 3: Cómo construir una API Gateway para Microservicios 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: Cómo construir una API Gateway para Microservicios usando OpenResty](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [API relacionadas con Expresiones Regulares](#api-relacionadas-con-expresiones-regulares)

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

- [API relacionadas con el Tiempo](#api-relacionadas-con-el-tiempo)

- [API de Worker y Proceso](#api-de-worker-y-proceso)

- [El problema de los valores `true` y `null`](#el-problema-de-los-valores-true-y-null)

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

- [Resumen](#resumen)
