Suppose my web app uses AJAX to issue query #1, then before a response is received from the server issues query #2. There are now two event handlers active, both awaiting replies from the server.
Suppose a response arrives from the server for query #2. How does the browser determine that this response should be given to the handler for query #2? It can't use socket info because both queries were issued over the same connection. Is there something in the HTTP/1.1 header? Or some other meta-data that helps here? I know that it works correctly based on testing, but I can't figure out what allows the browse to know how to route the server's response to the correct handler.
I have scratched my head over this question for days now, without finding the answer.
CodePudding user response:
AJAX over HTTP/1.1 must wait for a response on a given channel before issuing another request. Some web apps will use multiple channels in order to be able to issue parallel queries. In this case, it's obvious where each response should be routed since each channel is a separate TCP connection. This approach can be expensive when using SSL since establishing a connection requires a lot of work, but connections can be opened in advance and reused.
AJAX over HTTP/2 or HTTP/3 (QUIC) can use native multiplexing which allows multiple streams over a single connection, thereby avoiding the overhead of establishing multiple connections and undergoing multiple TCP and SSL handshakes. In this case, a response is paired with its request based on stream number.
CodePudding user response:
because both queries were issued over the same connection
This is where your assumption is wrong
HTTP1.1 is quite heavily socket oriented. Each HTTP request creates a new socket. By definition, the protocol considers the closing of the socket to be the end of the HTTP request.
Content-length
It is possible to signal the end of the HTTP request before the closing of the TCP socket. If the response contains the Content-length
header then the HTTP packet is exactly the number of bytes specified by that header. However, Content-length
is an optional header. Not all HTTP1.1 responses includes a Content-length
header. This header is often sent when the server is sending some static data like a jpg
or png
image or an mp4
video which the server can know the size of.
In some situations the server cannot know the content length. For example if it is responding with the output of a script. A lot of CGI scripts send data back to the browser by simply printing to stdout
and the server will take the bytes from the script's stdout
and stream it over TCP/IP to the browser. As such the server cannot know the length of the response when it sends the header.
Multipart response
It is possible for the server to send multipart response on the same socket. This technique uses the same protocol as multipart requests
(normally used for file upload by browsers) and separates the different documents in the TCP/IP stream using a pre-agreed string specified in the Content-Type
header.
However, there is no standard protocol for mapping multiple HTTP requests into a multipart response. Specifically there is no protocol for mapping multiple HTTP requests into a multipart request. A multipart request sends form data as individual documents. For example if you have a form with Name
, Age
and Gender
the multipart request will send a single HTTP request with 3 documents:
Name=My Name
and
Age=44
and
Gender=male
This is still just one HTTP request. So you may be wondering in what scenario would a multipart response be useful? Multipart response is an oldschool hack to send videos. It is what makes mjpeg streaming possible. The "video" is actually a regular <img>
tag displaying a jpg
image but the URL responds not with a regular JPEG file but with a multipart stream of many (potentially infinite) JPEG files.
Pipelining
HTTP1.1 does support sending multiple requests over a single socket. This feature is called pipelining. However, due to bugs in the implementation of some early web servers most browsers tend to avoid using HTTP1.1 pipelining. In some versions of Firefox you even need to manually enable this feature using the about:config
page. A lot of modern web frameworks don't support pipelining.
How HTTP1.1 pipelining distinguish which response belong to which request is simple: it is based on the order.
The first response is always related to the first request and the second response is always related to the second request.
If the server sends the second response first then it is a bug. It is due to this bug that most modern web browsers are very careful in using pipelining.
HTTP/2
HTTP/2 overhauls the communications protocol of HTTP by adding a multiplex stream layer below the traditional HTTP request. This stream layer is a binary protocol (kind of like TCP) and each stream has a stream id (kind of like sockets). You can think of it as a proprietary "socket" protocol sent over normal sockets. So each request and response are identified by their stream id.