# 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 petición HTTP.

- **Recepción de la solicitud:** 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 respuesta al cliente con un `HttpServerExecutionStatus = RemoteRequestDropped`.
    - Configuración del Resolutor de Reenvío: 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 al cliente una respuesta 400 Bad Request y al contexto HTTP se le asigna el estado `HttpServerExecutionStatus = DnsUnknownHost`.
        - 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 al cliente una respuesta 503 Service Unavailable y al contexto HTTP se le asigna el estado `HttpServerExecutionStatus = ListeningHostNotReady`.
    - Vinculación del enrutador: 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 utiliza 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) (100 MB por defecto) solo si es mayor que cero.
        - Si la solicitud envía un `Content-Length` mayor que el configurado, se devuelve al cliente una respuesta 413 Payload Too Large y al contexto HTTP se le asigna el estado `HttpServerExecutionStatus = ContentTooLarge`.
    - El evento `OnHttpRequestOpen` se invoca para todos los manejadores de servidor HTTP configurados.
- **Enrutamiento de la acción:** 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 al cliente una respuesta predeterminada 404 Not Found.
    - 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 al cliente una respuesta predeterminada 405 Method Not Allowed.
    - 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 está explícitamente definido como [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 cadena de consulta apuntando a la misma ubicación pero con un `/` al final.
    - El evento `OnContextBagCreated` se invoca para todos los manejadores de servidor HTTP configurados.
    - Todas las instancias globales de [IRequestHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.IRequestHandler.md) con la bandera `BeforeResponse` se ejecutan.
        - 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 al servidor una respuesta vacía, que a su vez reenvía una respuesta según el tipo de excepción lanzada, normalmente 500 Internal Server Error.
    - 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` se ejecutan.
        - 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 al servidor una respuesta vacía, que a su vez reenvía una respuesta según el tipo de excepción lanzada, normalmente 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 al servidor una respuesta vacía, que a su vez reenvía una respuesta según el tipo de excepción lanzada, normalmente 500 Internal Server Error.
    - Todas las instancias globales de [IRequestHandler](https://docs.sisk-framework.org/api/Sisk.Core.Routing.IRequestHandler.md) con la bandera `AfterResponse` se ejecutan.
        - 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 al servidor una respuesta vacía, que a su vez reenvía una respuesta según el tipo de excepción lanzada, normalmente 500 Internal Server Error.
    - 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` se ejecutan.
        - 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 al servidor una respuesta vacía, que a su vez reenvía una respuesta según el tipo de excepción lanzada, normalmente 500 Internal Server Error.
- **Procesamiento de la respuesta:** 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 la 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 una subclase 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 la condición anterior no se cumple, 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.
    - El evento `OnHttpRequestClose` se invoca para todos los manejadores de servidor HTTP configurados.
    - Si se lanzó una excepción en el servidor, el evento `OnException` se invoca 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.
