# Ciclo de vida de la solicitud

Source: https://docs.sisk-framework.org/es/docs/advanced/request-lifecycle.html

A continuación se explica todo el ciclo de vida de una solicitud mediante un ejemplo de una solicitud HTTP.

- **Receiving the request:** cada solicitud crea un contexto HTTP entre la propia solicitud y la respuesta que se entregará al cliente. Este contexto proviene del listener incorporado en Sisk, que puede ser el [HttpListener](https://learn.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=net-9.0), [Kestrel](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-9.0), o [Cadente](https://blog.sisk-framework.org/posts/2025-01-29-cadente-experiment/).
    - Validación de solicitud externa: la validación de [HttpServerConfiguration.RemoteRequestsAction](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.RemoteRequestsAction.md) se valida para la solicitud.
        - Si la solicitud es externa y la propiedad es `Drop`, la conexión se cierra sin una respuesta al cliente con un `HttpServerExecutionStatus = RemoteRequestDropped`.
    - Configuración del Forwarding Resolver: si se configura un [ForwardingResolver](https://docs.sisk-framework.org/es/docs/advanced/forwarding-resolvers.md), se llamará al método [OnResolveRequestHost](https://docs.sisk-framework.org/api/Sisk.Core.Http.ForwardingResolver.OnResolveRequestHost.md) en el host original de la solicitud.
    - Coincidencia DNS: con el host resuelto y con más de un [ListeningHost](https://docs.sisk-framework.org/api/Sisk.Core.Http.ListeningHost.md) configurado, el servidor buscará el host correspondiente para la solicitud.
        - Si no coincide ningún ListeningHost, se devuelve una respuesta 400 Bad Request al cliente y un estado `HttpServerExecutionStatus = DnsUnknownHost` al contexto HTTP.
        - Si coincide un ListeningHost, pero su [Router](https://docs.sisk-framework.org/api/Sisk.Core.Http.ListeningHost.Router.md) aún no está inicializado, se devuelve una respuesta 503 Service Unavailable al cliente y un estado `HttpServerExecutionStatus = ListeningHostNotReady` al contexto HTTP.
    - Vinculación del router: el router del ListeningHost correspondiente se asocia con el servidor HTTP recibido.
        - Si el router ya está asociado a otro servidor HTTP, lo cual no está permitido porque el router usa activamente los recursos de configuración del servidor, se lanza una `InvalidOperationException`. Esto solo ocurre durante la inicialización del servidor HTTP, no durante la creación del contexto HTTP.
    - Predefinición de encabezados:
        - Predefine el encabezado `X-Request-Id` en la respuesta si está configurado para hacerlo.
        - Predefine el encabezado `X-Powered-By` en la respuesta si está configurado para hacerlo.
    - Validación del tamaño del contenido: valida si el contenido de la solicitud es menor que [HttpServerConfiguration.MaximumContentLength](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.MaximumContentLength.md) solo si es mayor que cero.
        - Si la solicitud envía un `Content-Length` mayor que el configurado, se devuelve una respuesta 413 Payload Too Large al cliente y un estado `HttpServerExecutionStatus = ContentTooLarge` al contexto HTTP.
    - Se invoca el evento `OnHttpRequestOpen` para todos los manejadores de servidor HTTP configurados.
- **Routing the action:** el servidor invoca el router para la solicitud recibida.
    - Si el router no encuentra una ruta que coincida con la solicitud:
        - Si la propiedad [Router.NotFoundErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.NotFoundErrorHandler.md) está configurada, se invoca la acción y la respuesta de la acción se reenvía al cliente HTTP.
        - Si la propiedad anterior es nula, se devuelve una respuesta predeterminada 404 Not Found al cliente.
    - Si el router encuentra una ruta coincidente, pero el método de la ruta no coincide con el método de la solicitud:
        - Si la propiedad [Router.MethodNotAllowedErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.MethodNotAllowedErrorHandler.md) está configurada, se invoca la acción y la respuesta de la acción se reenvía al cliente HTTP.
        - Si la propiedad anterior es nula, se devuelve una respuesta predeterminada 405 Method Not Allowed al cliente.
    - Si la solicitud es del método `OPTIONS`:
        - El router devuelve una respuesta 200 Ok al cliente solo si ninguna ruta coincide con el método de la solicitud (el método de la ruta no es explícitamente [RouteMethod.Options](https://docs.sisk-framework.org/api/Sisk.Core.Routing.RouteMethod.md)).
    - Si la propiedad [HttpServerConfiguration.ForceTrailingSlash](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ForceTrailingSlash.md) está habilitada, la ruta coincidente no es una expresión regular, la ruta de la solicitud no termina con `/`, y el método de la solicitud es `GET`:
        - Se devuelve al cliente una respuesta HTTP 307 Temporary Redirect con el encabezado `Location` que contiene la ruta y la consulta a la misma ubicación con un `/` al final.
    - Se invoca el evento `OnContextBagCreated` para todos los manejadores de servidor HTTP configurados.
    - Se ejecutan todas las instancias globales de [IRequestHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.IRequestHandler.md) con la bandera `BeforeResponse`.
        - Si algún manejador devuelve una respuesta no nula, esa respuesta se reenvía al cliente HTTP y el contexto se cierra.
        - Si se lanza un error en este paso y [HttpServerConfiguration.ThrowExceptions](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ThrowExceptions.md) está deshabilitado:
            - Si la propiedad [Router.CallbackErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.CallbackErrorHandler.md) está habilitada, se invoca y la respuesta resultante se devuelve al cliente.
            - Si la propiedad anterior no está definida, se devuelve una respuesta vacía al servidor, que reenvía una respuesta según el tipo de excepción lanzada, que normalmente es 500 Internal Server Error.
    - Se ejecutan todas las instancias de [IRequestHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.IRequestHandler.md) definidas en la ruta y con la bandera `BeforeResponse`.
        - Si algún manejador devuelve una respuesta no nula, esa respuesta se reenvía al cliente HTTP y el contexto se cierra.
        - Si se lanza un error en este paso y [HttpServerConfiguration.ThrowExceptions](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ThrowExceptions.md) está deshabilitado:
            - Si la propiedad [Router.CallbackErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.CallbackErrorHandler.md) está habilitada, se invoca y la respuesta resultante se devuelve al cliente.
            - Si la propiedad anterior no está definida, se devuelve una respuesta vacía al servidor, que reenvía una respuesta según el tipo de excepción lanzada, que normalmente es 500 Internal Server Error.
    - Se invoca la acción del router y se transforma en una respuesta HTTP.
        - Si se lanza un error en este paso y [HttpServerConfiguration.ThrowExceptions](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ThrowExceptions.md) está deshabilitado:
            - Si la propiedad [Router.CallbackErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.CallbackErrorHandler.md) está habilitada, se invoca y la respuesta resultante se devuelve al cliente.
            - Si la propiedad anterior no está definida, se devuelve una respuesta vacía al servidor, que reenvía una respuesta según el tipo de excepción lanzada, que normalmente es 500 Internal Server Error.
    - Se ejecutan todas las instancias globales de [IRequestHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.IRequestHandler.md) con la bandera `AfterResponse`.
        - Si algún manejador devuelve una respuesta no nula, la respuesta del manejador reemplaza la respuesta anterior y se reenvía inmediatamente al cliente HTTP.
        - Si se lanza un error en este paso y [HttpServerConfiguration.ThrowExceptions](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ThrowExceptions.md) está deshabilitado:
            - Si la propiedad [Router.CallbackErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.CallbackErrorHandler.md) está habilitada, se invoca y la respuesta resultante se devuelve al cliente.
            - Si la propiedad anterior no está definida, se devuelve una respuesta vacía al servidor, que reenvía una respuesta según el tipo de excepción lanzada, que normalmente es 500 Internal Server Error.
    - Se ejecutan todas las instancias de [IRequestHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.IRequestHandler.md) definidas en la ruta y con la bandera `AfterResponse`.
        - Si algún manejador devuelve una respuesta no nula, la respuesta del manejador reemplaza la respuesta anterior y se reenvía inmediatamente al cliente HTTP.
        - Si se lanza un error en este paso y [HttpServerConfiguration.ThrowExceptions](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ThrowExceptions.md) está deshabilitado:
            - Si la propiedad [Router.CallbackErrorHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.Router.CallbackErrorHandler.md) está habilitada, se invoca y la respuesta resultante se devuelve al cliente.
            - Si la propiedad anterior no está definida, se devuelve una respuesta vacía al servidor, que reenvía una respuesta según el tipo de excepción lanzada, que normalmente es 500 Internal Server Error.
- **Processing the response:** con la respuesta lista, el servidor la prepara para enviarla al cliente.
    - Los encabezados de la política Cross-Origin Resource Sharing (CORS) se definen en la respuesta según lo configurado en el actual [ListeningHost.CrossOriginResourceSharingPolicy](https://docs.sisk-framework.org/api/Sisk.Core.Http.ListeningHost.CrossOriginResourceSharingPolicy.md).
    - El código de estado y los encabezados de la respuesta se envían al cliente.
    - El contenido de la respuesta se envía al cliente:
        - Si el contenido de la respuesta es descendiente de [ByteArrayContent](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.bytearraycontent), los bytes de la respuesta se copian directamente al flujo de salida de la respuesta.
        - Si no se cumple la condición anterior, la respuesta se serializa a un flujo y se copia al flujo de salida de la respuesta.
    - Los flujos se cierran y el contenido de la respuesta se descarta.
    - Si [HttpServerConfiguration.DisposeDisposableContextValues](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.DisposeDisposableContextValues.md) está habilitado, todos los objetos definidos en el contexto de la solicitud que heredan de [IDisposable](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) se descartan.
    - Se invoca el evento `OnHttpRequestClose` para todos los manejadores de servidor HTTP configurados.
    - Si se lanzó una excepción en el servidor, se invoca el evento `OnException` para todos los manejadores de servidor HTTP configurados.
    - Si la ruta permite el registro de accesos y [HttpServerConfiguration.AccessLogsStream](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.AccessLogsStream.md) no es nulo, se escribe una línea de registro en la salida de logs.
    - Si la ruta permite el registro de errores, hay una excepción, y [HttpServerConfiguration.ErrorsLogsStream](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.ErrorsLogsStream.md) no es nulo, se escribe una línea de registro en la salida de logs de errores.
    - Si el servidor está esperando una solicitud a través de [HttpServer.WaitNext](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServer.WaitNext.md), el mutex se libera y el contexto queda disponible para el usuario.
