ASGI HTTP Request and Response Message Events
The Asynchronous Server Gateway Interface (ASGI) defines how
asynchronous Python web servers and applications communicate using a
standard message-passing protocol. For HTTP transactions, the lifecycle
is managed by an initial connection scope and a sequence of predefined
inbound and outbound message events passed via receive and
send callables. This article outlines the specific message
event types that govern HTTP request ingestion and response delivery
under the ASGI specification.
The Connection Scope
Before any message events are exchanged, the ASGI server initializes
the connection by passing a scope dictionary of type
http to the application. This dictionary establishes the
context of the request and includes metadata such as:
type: Set to"http".asgi["version"]: The ASGI specification version.http_version: The HTTP protocol version (e.g.,"1.1"or"2").method: The HTTP verb in uppercase (e.g.,"GET","POST").pathandraw_path: The URL path.query_string: The URL query string as raw bytes.headers: A list of two-item iterable byte pairs representing HTTP headers.
Inbound Request Events
Once the scope is established, the application listens for incoming
data using the receive awaitable callable. The HTTP
lifecycle dictates two primary inbound message types:
1. http.request
Sent by the server to deliver the HTTP request body to the
application. If the body is large or streamed, multiple
http.request events are sent sequentially.
body(bytes, optional): A chunk of the request body. Defaults to empty bytesb"".more_body(bool, optional): Indicates whether more body chunks are expected. WhenFalse, the request body transmission is complete. Defaults toFalse.
2. http.disconnect
Sent by the server if the client closes the connection before the
response is fully generated or sent. It carries no additional payload
beyond type: "http.disconnect". Applications can listen for
this event to cancel expensive background tasks early.
Outbound Response Events
To return data to the client, the application transmits structured
dictionaries to the server using the send awaitable
callable. The lifecycle strictly requires a response to begin before
body data can be delivered.
1. http.response.start
This event must be sent first to initialize the HTTP response. Sending any other event before this raises an error.
status(int): The HTTP status code (e.g.,200,404).headers(Iterable[Tuple[bytes, bytes]], optional): A list of two-element tuples containing header names and values as bytes.trailers(bool, optional): Indicates whether HTTP trailers will follow the response body. Defaults toFalse.
2. http.response.body
Sent after http.response.start to transmit the response
payload. Multiple http.response.body events can be chained
to stream data.
body(bytes, optional): A chunk of the response body. Defaults to empty bytesb"".more_body(bool, optional): Set toTrueif further chunks will follow. When set toFalse, it signals the completion of the HTTP response.
Standard Lifecycle Execution Order
- Initialization: The server calls the application:
app(scope, receive, send). - Body Consumption: The application calls
await receive()to consume one or morehttp.requestevents untilmore_bodyisFalse. - Response Header Transmission: The application calls
await send({"type": "http.response.start", "status": ..., "headers": ...}). - Response Body Transmission: The application calls
await send({"type": "http.response.body", "body": ..., "more_body": ...})until all body chunks are sent withmore_body=False. - Termination: The application completes its execution loop, and the server closes or reuses the underlying connection.