---
title: "OpenResty es el NGINX mejorado con solicitudes y respuestas dinámicas - API7.ai"
description: "OpenResty es una versión mejorada de NGINX con capacidades para manejar solicitudes y respuestas dinámicas. Este artículo explica las APIs para manipular las solicitudes (Request) y respuestas (Response) en OpenResty, como \"ngx.req.set_method\", \"ngx.req.set_uri_args\", \"ngx.req.set_header\", entre otras."
url: "https://api7.ai/es/learning-center/openresty/handling-requests-responses-dynamically"
---

# OpenResty es el NGINX mejorado con solicitudes y respuestas dinámicas

API7.ai

October 23, 2022

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

Después de la introducción anterior, debes entender el concepto de OpenResty y cómo aprenderlo. Este artículo nos guiará sobre cómo OpenResty maneja las solicitudes y respuestas del cliente.

Aunque OpenResty es un servidor web basado en NGINX, es fundamentalmente diferente de NGINX: NGINX está impulsado por archivos de configuración estáticos, mientras que OpenResty está impulsado por la API de Lua, ofreciendo más flexibilidad y programabilidad.

Permíteme mostrarte los beneficios de la API de Lua.

## Categorías de API

Primero, necesitamos saber que la API de OpenResty se divide en las siguientes categorías principales.

- Procesamiento de solicitudes y respuestas.
- Relacionado con SSL.
- Diccionario compartido.
- Cosocket.
- Manejo de tráfico en cuatro capas.
- Proceso y worker.
- Acceso a variables y configuración de NGINX.
- Funciones generales como cadenas, tiempo, codificación, etc.

Aquí, te sugiero que también abras la documentación de la API de Lua de OpenResty y la compares con la [lista de API](https://github.com/openresty/lua-nginx-module/#nginx-api-for-lua) para ver si puedes relacionarte con esta categoría.

Las APIs de OpenResty no solo existen en el proyecto `lua-nginx-module`, sino también en el proyecto `lua-resty-core`, como `ngx.ssl`, `ngx.base64`, `ngx.errlog`, `ngx.process`, `ngx.re.split`, `ngx.resp.add_header`, `ngx.balancer`, `ngx.semaphore`, `ngx.ocsp`, y otras APIs.

Para las APIs que no están en el proyecto `lua-nginx-module`, necesitas requerirlas por separado para usarlas. Por ejemplo, si deseas usar la función de división, debes llamarla de la siguiente manera.

```
$ resty -e 'local ngx_re = require "ngx.re"
 local res, err = ngx_re.split("a,b,c,d", ",", nil, {pos = 5})
 print(res)
 '
```

Por supuesto, puede confundirte: en el proyecto `lua-nginx-module`, hay varias APIs que comienzan con `ngx.re.sub`, `ngx.re.find`, etc. ¿Por qué es que la API `ngx.re.split` es la única que necesita ser requerida antes de ser usada?

Como mencionamos en el capítulo anterior de `lua-resty-core`, las nuevas APIs de OpenResty se implementan en el repositorio `lua-resty-core` mediante FFI, por lo que inevitablemente hay una sensación de fragmentación. Espero que en el futuro se resuelva este problema fusionando los proyectos `lua-nginx-module` y `lua-resty-core`.

## Solicitud

A continuación, veamos cómo OpenResty maneja las solicitudes y respuestas del cliente. Primero, veamos la API para manejar solicitudes, pero hay más de 20 APIs que comienzan con `ngx.req`, ¿cómo empezamos?

Sabemos que los mensajes de solicitud HTTP consisten en tres partes: la línea de solicitud, el encabezado de solicitud y el cuerpo de solicitud, por lo que presentaré la API en estas tres partes.

### Línea de Solicitud

La primera es la línea de solicitud, que contiene el método de solicitud, el URI y la versión del protocolo HTTP. En NGINX, puedes obtener este valor usando una variable incorporada, mientras que en OpenResty, corresponde a la API `ngx.var.*`. Veamos dos ejemplos.

- La variable incorporada `$scheme`, que representa el nombre del protocolo en NGINX, es `http` o `https`; en OpenResty, puedes usar `ngx.var.scheme` para obtener el mismo valor.
- `$request_method` representa el método de solicitud como `GET`, `POST`, etc.; en OpenResty, puedes obtener el mismo valor mediante `ngx.var.request_method`.

Puedes visitar la documentación oficial de NGINX para obtener una lista completa de las variables incorporadas de NGINX: <http://nginx.org/en/docs/http/ngx_http_core_module.html#variables>.

Entonces, surge la pregunta: ¿por qué OpenResty proporciona una API separada para la línea de solicitud cuando puedes obtener los datos en la línea de solicitud devolviendo el valor de una variable como `ngx.var.*`?

El resultado contiene muchos factores:

- En primer lugar, no se recomienda leer repetidamente `ngx.var` debido a su rendimiento ineficiente.
- En segundo lugar, por consideración al aspecto amigable del programa, `ngx.var` devuelve una cadena, no un objeto Lua. Es difícil de manejar cuando se obtienen `args`, que pueden devolver múltiples valores.
- En tercer lugar, desde el aspecto de la flexibilidad, la mayoría de `ngx.var` es de solo lectura, y solo unas pocas variables son escribibles, como `$args` y `limit_rate`. Sin embargo, a menudo necesitamos modificar el método, el URI y los args.

Por lo tanto, OpenResty proporciona varias APIs dedicadas a manipular la línea de solicitud, que pueden reescribir la línea de solicitud para operaciones posteriores como la redirección.

Veamos cómo obtener el número de versión del protocolo HTTP a través de la API. La API de OpenResty `ngx.req.http_version` hace lo mismo que la variable `$server_protocol` de NGINX: devolver el número de versión del protocolo HTTP. Sin embargo, el valor de retorno de esta API no es una cadena, sino en formato numérico, cuyos valores posibles son `2.0`, `1.0`, `1.1` y `0.9`. Se devuelve `nil` si el resultado está fuera del rango de estos valores.

Veamos el método de obtener la solicitud en la línea de solicitud. Como se mencionó, el papel y el valor de retorno de `ngx.req.get_method` y las variables `$request_method` de NGINX son los mismos: en formato de cadena.

Sin embargo, el formato de parámetro del método de solicitud HTTP actual `ngx.req.set_method` no es una cadena, sino constantes numéricas incorporadas. Por ejemplo, el siguiente código reescribe el método de solicitud a POST.

```
ngx.req.set_method(ngx.HTTP_POST)
```

Para verificar que la constante incorporada `ngx.HTTP_POST` es realmente un número y no una cadena, puedes imprimir su valor y ver si la salida es 8.

```
resty -e 'print(ngx.HTTP_POST)'
```

De esta manera, el valor de retorno del método `get` es una cadena, mientras que el valor de entrada del método `set` es un número. Está bien cuando el método `set` pasa un valor confuso porque la API puede fallar y reportar un error `500`. Sin embargo, en la siguiente lógica de juicio:

```
if (ngx.req.get_method() == ngx.HTTP_POST) then
    -- hacer algo
 end
```

Este tipo de código funciona bien, no reporta errores y es difícil de encontrar incluso durante las revisiones de código. Yo cometí un error similar antes y todavía lo recuerdo: ya había pasado por dos rondas de revisiones de código y casos de prueba incompletos para intentar cubrirlo. Finalmente, una anomalía en el entorno en línea me llevó al problema.

No hay una forma práctica de resolver tal problema excepto ser más cuidadoso o agregar otra capa de encapsulación. Cuando diseñas tu API de negocio, también puedes considerar y mantener el formato de parámetro consistente de los métodos `get` y `set`, incluso si necesitas sacrificar algo de rendimiento.

Además, entre los métodos para reescribir la línea de solicitud, hay dos APIs, `ngx.req.set_uri` y `ngx.req.set_uri_args`, que se pueden usar para reescribir el URI y los args. Veamos esta configuración de NGINX.

```
rewrite ^ /foo?a=3? break;
```

Entonces, ¿cómo podemos resolverlo con la API equivalente de Lua? La respuesta son las siguientes dos líneas de código.

```
ngx.req.set_uri_args("a=3")
ngx.req.set_uri("/foo")
```

Si has leído la documentación oficial, encontrarás que `ngx.req.set_uri` tiene un segundo parámetro: `jump`, que es "false" por defecto. Si lo configuras como "true", es igual a configurar la bandera del comando `rewrite` a `last` en lugar de `break` en el ejemplo anterior.

Sin embargo, no me gusta mucho la configuración de la bandera del comando `rewrite` porque es ilegible y poco reconocible, y mucho menos intuitiva y mantenible que el código.

### Encabezado de Solicitud

Como sabemos, los encabezados de solicitud HTTP están en formato `key : value`, por ejemplo:

```
  Accept: text/css,*/*;q=0.1
  Accept-Encoding: gzip, deflate, br
```

En OpenResty, puedes usar `ngx.req.get_headers` para analizar y obtener los encabezados de solicitud, y el tipo de valor de retorno es una tabla.

```
local h, err = ngx.req.get_headers()
  if err == "truncated" then
      -- uno puede elegir ignorar o rechazar la solicitud actual aquí
  end
  for k, v in pairs(h) do
      ...
  end
```

Por defecto, devuelve los primeros 100 encabezados. Si el número excede 100, reportará un error `truncated`, dejando que el desarrollador decida cómo manejarlo. Puedes preguntarte por qué se toma de esta manera, lo cual mencionaré más adelante en la sección sobre vulnerabilidades de seguridad.

Sin embargo, debemos tener en cuenta que OpenResty no proporciona una API específica para obtener un encabezado de solicitud especificado, lo que significa que no hay una forma como `ngx.req.header['host']`. Si tienes tal necesidad, debes confiar en la variable de NGINX `$http_xxx` para lograrlo. Luego, en OpenResty, puedes obtenerlo mediante `ngx.var.http_xxx`.

Ahora veamos cómo deberíamos reescribir y eliminar el encabezado de solicitud. Las APIs para ambas operaciones son bastante intuitivas:

```
ngx.req.set_header("Content-Type", "text/css")
ngx.req.clear_header("Content-Type")
```

Por supuesto, la documentación oficial también menciona otros métodos para eliminar el encabezado de solicitud, como establecer el valor del título en `nil`, etc. Sin embargo, todavía recomiendo usar `clear_header` para hacerlo de manera uniforme para la claridad del código.

### Cuerpo de Solicitud

Finalmente, veamos el cuerpo de la solicitud. Por razones de rendimiento, OpenResty no lee activamente el cuerpo de la solicitud a menos que habilites la directiva `lua_need_request_body` en `nginx.conf`. Además, para cuerpos de solicitud más grandes, OpenResty guarda el contenido en un archivo temporal en el disco, por lo que el proceso completo de leer el cuerpo de la solicitud se ve así.

```
ngx.req.read_body()
local data = ngx.req.get_body_data()
if not data then
    local tmp_file = ngx.req.get_body_file()
     -- io.open(tmp_file)
     -- ...
 end
```

Este código tiene una operación de bloqueo de IO para leer el archivo del disco. Debes ajustar la configuración de `client_body_buffer_size` (16 KB por defecto en sistemas de 64 bits) para minimizar las operaciones de bloqueo; también puedes configurar `client_body_buffer_size` y `client_max_body_size` para que sean iguales y manejarlos completamente en memoria, dependiendo del tamaño de tu memoria y el número de solicitudes concurrentes que manejes.

Además, el cuerpo de la solicitud se puede reescribir. Las dos APIs `ngx.req.set_body_data` y `ngx.req.set_body_file` aceptan una cadena y un archivo local del disco como parámetros de entrada para realizar la reescritura del cuerpo de la solicitud. Sin embargo, este tipo de operación es poco común, y puedes consultar la documentación para obtener más detalles.

## Respuesta

Después de procesar la solicitud, necesitamos enviar una respuesta al cliente. Al igual que el mensaje de solicitud, el mensaje de respuesta también consta de varias partes: la línea de estado, el encabezado de respuesta y el cuerpo de respuesta. Presentaré las APIs correspondientes según estas tres partes.

### Línea de Estado

Lo principal que nos preocupa en la línea de estado es el código de estado. Por defecto, el código de estado HTTP devuelto es 200, que es la constante `ngx.HTTP_OK` incorporada en OpenResty. Pero en el mundo del código, siempre es el código el que maneja los casos más excepcionales.

Si detectas el mensaje de solicitud y descubres que es una solicitud maliciosa, entonces necesitas terminar la solicitud:

```
ngx.exit(ngx.HTTP_BAD_REQUEST)
```

Sin embargo, hay una constante particular en los códigos de estado HTTP de OpenResty: `ngx.OK`. En la situación de `ngx.exit(ngx.OK)`, la solicitud sale de la fase de procesamiento actual y pasa a la siguiente etapa en lugar de regresar directamente al cliente.

Por supuesto, también puedes elegir no salir y simplemente reescribir el código de estado usando `ngx.status`, como se escribe a continuación.

```
ngx.status = ngx.HTTP_FORBIDDEN
```

Puedes buscarlos en la [documentación](https://github.com/openresty/lua-nginx-module/#http-status-constants) si deseas saber más sobre las constantes de códigos de estado.

### Encabezado de Respuesta

En cuanto al encabezado de respuesta, hay dos formas en que puedes configurarlo. La primera es la más simple.

```
ngx.header.content_type = 'text/plain'
ngx.header["X-My-Header"] = 'blah blah'
ngx.header["X-My-Header"] = nil -- eliminar
```

Aquí, `ngx.header` contiene la información del encabezado de respuesta, que se puede leer, modificar y eliminar.

La segunda forma de configurar el encabezado de respuesta es `ngx_resp.add_header`, del repositorio `lua-resty-core`, que agrega un mensaje de encabezado, llamado con:

```
local ngx_resp = require "ngx.resp"
ngx_resp.add_header("Foo", "bar")
```

La diferencia con el primer método es que `add_header` no sobrescribe un campo existente del mismo nombre.

### Cuerpo de Respuesta

Finalmente, veamos el cuerpo de la respuesta. En OpenResty, puedes usar `ngx.say` y `ngx.print` para enviar el cuerpo de la respuesta.

```
ngx.say('hello, world')
```

La funcionalidad de las dos APIs es idéntica, la única diferencia es que `ngx.say` tiene un salto de línea al final.

Para evitar la ineficiencia de la concatenación de cadenas, `ngx.say / ngx.print` admite cadenas y formatos de matriz como parámetros.

```
$ resty -e 'ngx.say({"hello", ", ", "world"})'
 hello, world
```

Este método omite la concatenación de cadenas a nivel de Lua y deja que las funciones de C lo manejen.

## Resumen

Repasemos el contenido de hoy. Presentamos las APIs de OpenResty asociadas con los mensajes de solicitud y respuesta. Como puedes ver, la API de OpenResty es más flexible y poderosa que la directiva de NGINX.

En consecuencia, ¿es suficiente la API de Lua proporcionada por OpenResty para satisfacer tus necesidades cuando manejas solicitudes HTTP? Por favor, deja tus comentarios y comparte este artículo con tus colegas y amigos 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

- [Categorías de API](#categor%C3%ADas-de-api)

- [Solicitud](#solicitud)

  - [Línea de Solicitud](#l%C3%ADnea-de-solicitud)
  - [Encabezado de Solicitud](#encabezado-de-solicitud)
  - [Cuerpo de Solicitud](#cuerpo-de-solicitud)

- [Respuesta](#respuesta)

  - [Línea de Estado](#l%C3%ADnea-de-estado)
  - [Encabezado de Respuesta](#encabezado-de-respuesta)
  - [Cuerpo de Respuesta](#cuerpo-de-respuesta)

- [Resumen](#resumen)
