
HTTP stands for Hypertext Transfer Protocol, which is the protocol for transferring hypertext. There is a plethora of information available online about the HTTP protocol, but most of it lists the specific regulations of the HTTP protocol, with few discussing the reasons behind its design. Today, I will attempt to analyze the main characteristics of the HTTP protocol from the perspective of problem-solving, hoping to help everyone quickly understand the HTTP protocol.
HTTP is a protocol for transmitting data over the network. We do not want data to be lost or corrupted during transmission. Therefore, HTTP uses TCP as its underlying network protocol, as TCP is a reliable transport layer protocol.
After establishing a TCP connection, both parties immediately encounter a new problem: what data should the server send to the client? Therefore, the client must send the content it wants to the server after the connection is established, which is known as a “request,” or an HTTP Request. This establishes the fundamental design of the HTTP protocol, which is a request-response protocol led by the client.
The client immediately sends a “request” to the server. However, the content received by the server may not be exactly the same as what the client sent. Wait, isn’t TCP a reliable transport protocol? How can the received data be different? This involves the issue of data segmentation. For example, if the client sends “abcdef,” the underlying TCP protocol may transmit “abc” and “def” in two parts, or it may be split into several transmissions. Regardless of how many times it is split, the order is fixed and completely consistent with the order sent by the client. The server may receive multiple segments of data, so it needs to “gather” the received data and wait until all of the client’s data is received before it can see the complete picture of the client’s “request.”
So when is it considered that all data has been received? This is a fundamental issue in TCP communication. There are two schools of thought to solve this problem: length-based streams and delimiter-based streams.
A length-based stream means that before actually sending data, the length of the data is sent first. The server reads the length information first and then gathers the subsequent data based on that length. But won’t the server encounter segmentation issues when reading the length? Actually, it won’t, because TCP only segments relatively long data. The earlier example of “abcdef” being split into two segments is an extreme case that is unlikely to occur. Therefore, as long as the length data sent first is not too long, the server can receive it all at once. Even if segmentation does occur, such length-based protocols will specify the length of the length data itself. For example, if two bytes are used to represent the length, the range of data length is 0-65535. The server can first receive two bytes and then receive the subsequent content based on the data length.
The biggest advantage of length-based streams is their simplicity and high memory efficiency, as the server does not need to allocate a lot of memory in advance. However, the drawbacks are also prominent; the range of lengths is not flexible enough. If we specify the length field as two bytes, we cannot transmit data longer than 64k. But if we specify the length field as eight bytes, it will waste space when transmitting shorter data. How to set the optimal length field can be referenced in my other article.
Moreover, the extensibility of length-based streams is also relatively poor. If we want to transmit other information besides length, such as data type or version number, we need to predefine the lengths of these data. Once the length is set, it is difficult to expand later. The most typical length-based protocol is the IP packet. Interested friends can take a look at how the IP protocol specifies data length.
In light of the shortcomings of length-based streams, people have developed delimiter-based streams. Simply put, a special delimiter is used to indicate the end of the data. The classic example is the C language string, which uses \0 to indicate the end. Servers using this stream type must continuously receive data from the client until a specific delimiter is received, indicating that the complete “request” has been received.
Since there is no need to specify the length of the data in advance, delimiter-based streams solve the inflexibility of length-based streams. Protocols using delimiter streams can accept data of any length. However, this comes at a cost. Because the length is not fixed, the server must allocate relatively large memory or dynamically allocate memory multiple times, which can lead to significant resource consumption. Malicious users may construct very long data to fill the server’s memory.
However, the HTTP protocol has adopted this stream type, using \r\n as the delimiter. Here, \r represents a carriage return, which moves the printer head back to the leftmost position. \n represents a newline, which moves the paper up one line to prepare for printing new characters. In ancient times, computers did not use modern LCD screens but used teleprinters to “display” content, so it was necessary to transmit both \r and \n characters. Now that these have been phased out, theoretically, \n alone can suffice, as Nginx supports using only \n.
Therefore, a simple HTTP request looks like this:
GET /mypage.html\r\n
Here, GET is a personified way of asking what the server has. This also marks the beginning of the semantic design of HTTP (the so-called semantic design means that ordinary people can understand it). Following that is a space, and then the file path. Finally, there is the delimiter \r\n. Because it ends with \r\n, the above data is also called the request line.
After the client establishes a connection with the server, it immediately sends the above data. The server starts parsing after receiving \r\n, extracting /mypage.html, then finding the corresponding file and sending the file content back to the client.
At this point, the client has received the file content sent by the server, which is called a “response.” However, the client immediately faces the same problem as the server: how to determine that it has received the complete content of mypage.html? Should the server send a delimiter \r\n at the end? It cannot! Because the content of mypage.html may itself contain \r\n. If the client still uses \r\n as the end marker, it may lose data.
To address this, Tim Berners-Lee (the father of the HTTP protocol) adopted a simpler method—closing the connection. This means that the server must actively close the TCP connection after the transmission is complete, so the client clearly knows that all content has been transmitted.
This is the original HTTP protocol, released around 1990. This era’s HTTP protocol is now referred to as HTTP/0.9, mainly to distinguish it from the later standardized versions 1.x. Thus, the era of the World Wide Web began.
After the release of HTTP/0.9, it gained widespread use. However, its functionality was too simple, so many browsers extended it. The main extended features include:
- Adding version information
- Adding extended header information
- Adding return status information
Adding version information is to facilitate mutual recognition between clients and servers, enabling the activation of extended features. The request line after adding looks like this:
GET /mypage.html HTTP/1.0\r\n
Adding extended header information is to convey more extended information. For example, different browsers will mark their identity in the request. To facilitate the subsequent addition of various extended information, the HTTP protocol continues to use the concept of “lines” and delimiters.
First, consistent with the request line, each extended information occupies a line, separated by a colon, and ending with \r\n, for example:
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)\r\n
Secondly, this information can have multiple lines. So how does the server determine how many lines there are? This still requires the use of the delimiter \r\n. The HTTP protocol uses an empty line to indicate that all subsequent extended information has ended. Therefore, the complete request is:
GET /mypage.html HTTP/1.0\r\n
Host: taoshu.in\r\n
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)\r\n
\r\n
The server first receives a line, extracts the file path, and then extracts the extended information line by line based on \r\n. If an empty line is received, it indicates that the extended information has been completely received. This extended information is also called header information, and various features of the subsequent HTTP protocol are based on it.
HTTP/0.9 directly transmitted file content upon receiving a request. However, in some scenarios, it is necessary to return other information, such as when a file does not exist, so people added return status information. In addition, the extended HTTP protocol also supports the server returning multiple header information before sending data. A typical extended response is:
200 OK\r\n
Date: Tue, 15 Nov 1994 08:12:32 GMT\r\n
Server: CERN/3.0 libwww/2.17\r\n
Content-Type: image/gif\r\n
\r\n
(image content)
The server first sends a line of data 200 OK\r\n. Here, 200 is the status code indicating success. The following OK is the semantic part for human understanding. This line is also called the status code line. Following that is the extended information, which is in the same format as in the request, with one line per entry, ending with an empty line. Finally, the file content is sent.
With the header information, the extensibility of the HTTP protocol skyrocketed. People continuously added various features to the HTTP protocol.
HTTP/0.9 could only transmit plain text files. With the addition of headers, we can transmit more descriptive information, such as the type, length, and last modified time of the file. This descriptive information for transmitted data is also called Entity Header, while the data itself is called Entity.
Common Entity Headers include:
- Content-Type: Content type
- Content-Length: Content length
- Content-Encoding: Data encoding
Content-Type indicates the data type, for example, the type of gif is image/gif. The values for the type are ultimately standardized as Multipurpose Internet Mail Extensions (MIME).
Content-Length indicates the data length. However, as mentioned earlier, HTTP/0.9 servers do not need to return the file length; they can simply close the TCP connection after transmission. Why then define length information?
There are two issues here. The first is supporting content uploads in requests, and the second is connection optimization.
HTTP/0.9 only had one GET request. Clearly, downloading alone is not enough. People gradually introduced HEAD and POST requests to submit data to the server. Once data is submitted, simply using delimiters is insufficient, as the submitted data may itself contain delimiters. Therefore, it is necessary to specify the length of the data in advance. This length is specified using the Content-Length header.
The other issue is connection optimization. In fact, the history of the development of the HTTP protocol is largely a history of optimizing transmission performance.
HTTP/0.9 created a TCP connection for each request, and after reading, the connection would be closed. If only one file is downloaded at a time, this is not a problem. However, as HTML pages began to support embedded images and other content, a single page might require multiple images. Thus, when a browser opens an HTML page, it needs to initiate multiple HTTP requests, each time repeatedly establishing and closing TCP connections. This not only wastes server resources but also slows down page loading speed.
Therefore, people sought ways to reuse the underlying TCP connection. Simply put, the server does not actively close the connection after content transmission. However, if the connection is not closed, the client will not know when the response content has been completely transmitted. Therefore, it is necessary to specify the length of the data in advance. Since the HTTP protocol already has a header mechanism, adding Content-Length is the most natural solution.
There is also a compatibility issue. If the client does not support TCP connection reuse, the server will keep the connection open, and the client will keep waiting. Therefore, the feature of reusing TCP connections cannot be enabled by default; it should be determined by the client. This leads to the introduction of the Connection: Keep-Alive header. If the client specifies Keep-Alive in the request, the server will not actively close the TCP connection.
In addition to reusing TCP connections, another area worth optimizing in HTTP/0.9 is data compression. During that era, network speeds were slow, and compressing data before transmission could significantly reduce transmission time. The server cannot compress arbitrarily, as some clients may not support it. Therefore, the Accept-Encoding header was introduced, with possible values such as compress or gzip. After receiving this request, the server would compress the content. Since browsers may support multiple compression algorithms, the browser needs to choose one that it also supports to compress the data, which is the purpose of the Content-Encoding header.
Whether it is the previous Connection or the later Accept-Encoding, to ensure compatibility with different clients, the HTTP protocol negotiates whether to use extended features by adding new headers. This negotiation is led by the client, and the server needs to cooperate based on the client’s request.
People introduced the following Entity Headers:
- Last-Modified: Last modified time
- Expires: Expiration time
If the file does not change often, the server can send the last modified time to the browser through Last-Modified. If the browser supports it, it can include this time in the next request for that resource, adding the following header:
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT\r\n
The server will compare this with the current modification time of the file, and if it has not changed, it will directly return 304:
304 Not Modified\r\n
This is called a conditional request and can significantly reduce unnecessary network transmission.
Even so, the client still has to initiate an HTTP request to get the 304 response, which incurs network transmission and server overhead. To further optimize, HTTP introduced the Expires header, which indicates a future expiration time. Before this time, the browser can safely use the local cached copy without needing to download from the server. This way, even conditional requests do not need to be initiated.
However, the Expires feature has a side effect: once a file is delivered, it cannot be modified before it expires.
From around 1991 to 1995, various browser vendors gradually implemented the above features. However, different browsers and server software supported different features, leading to various compatibility issues. Therefore, in 1996, the IETF released RFC1945. RFC1945 can only be said to summarize the current best practices, not a recommended standard. However, people still refer to it as HTTP/1.0.
Less than a year later, in 1997, the IETF released RFC2068, which is the famous HTTP/1.1 protocol specification.
HTTP/1.1 is a refinement and extension of HTTP/1.0. The core changes include:
- Default TCP connection reuse is enabled; clients no longer need to send Connection: Keep-Alive
- The so-called pipeline feature is added to further optimize transmission efficiency
- Support for chunked transfer encoding
- Extended cache control
- Content negotiation, including language, transfer encoding, type, etc.
- Establish multiple HTTP sites on the same IP
The so-called pipeline feature is a further optimization of the HTTP protocol’s transmission efficiency, but it ultimately failed.
The HTTP protocol is a request-response protocol. The client sends a request and then waits for the server to return content. Although there were optimization mechanisms such as TCP connection reuse, content compression, and conditional requests in the HTTP/1.0 era, the client must wait for the server to return content before initiating a new request. In other words, the client cannot initiate multiple requests in parallel on a single connection. Therefore, the HTTP/1.1 pipeline stipulates that the client can sequentially initiate multiple HTTP requests and then wait for the server to return results. The server must return the corresponding response content in the order of the requests.
c s c s
| req1 | | req1 |
|------->| |------->|
| resp1 | | req2 |
|<-------| |------->|
| req2 | | req3 |
|------->| |------->|
| resp2 | | resp1 |
|<-------| |<-------|
| req3 | | resp2 |
|------->| |<-------|
| resp3 | | resp3 |
|<-------| |<-------|
without pipeline with pipeline
Although the server can process multiple requests concurrently when it receives them, the optimization brought by this concurrency is limited, and the pipeline feature did not reduce actual network transmission. Almost no software implemented the pipeline feature, so this optimization design ended in failure.
Chunked encoding is a very successful optimization, mainly solving the situation where the server dynamically generates response content.
HTTP/1.0 could only use Content-Length to specify content length, and it required sending the header before sending the body. This required determining the content length before transmitting. For static files, this is not a problem. However, if loading an HTML page dynamically rendered by PHP, it becomes problematic, as the HTML is generated dynamically, and the content length cannot be determined in advance. If the original method is used, the content must be generated and saved to a temporary file before being sent to the client, which is clearly inefficient.
To solve this problem, HTTP/1.1 introduced chunked encoding. Simply put, it returns to the previous length-based stream, sending data in segments to the client, with each segment preceded by length information:
HTTP/1.1 200 OK\r\n
Content-Type: text/plain\r\n
Transfer-Encoding: chunked\r\n
7\r\n
Mozilla\r\n
9\r\n
Developer\r\n
7\r\n
Network\r\n
0\r\n
\r\n
Transfer-Encoding is specified as chunked. The subsequent data is also transmitted line by line. One line for length, one line for data. The end is indicated by a length of zero, followed by an empty line. This way, the server does not need to determine the response content length in advance, allowing PHP to render and send content simultaneously. This feature was used to implement message pushing in the era before WebSocket became popular. You can search for Comet or HTTP long polling for more information.
HTTP/1.1 defined caching more finely, introducing Cache-Control extended information. This part is quite complex, as it affects not only the browser’s caching behavior but also the behavior of CDN nodes. Some CDN vendors may also extend the semantics of standard caching directives. Due to space limitations, I will not elaborate on this here.
However, HTTP/1.1 expanded conditional requests, which I can mention. The operating system automatically records the modification time of files, and reading this time is very convenient, but Last-Modified cannot cover all situations. Sometimes we need to programmatically generate certain files, and their modification times may change periodically, but the content may not change. Therefore, using Last-Modified alone may still result in unnecessary network transmission. Thus, the HTTP protocol introduced a new header, Etag.
The Etag’s semantics are to calculate a value based on the file content, which only generates a new Etag when the content is modified. Each time the client requests, it brings back the previous Etag, adding the following header:
If-None-Match: "c3piozzzz"\r\n
The server will compare the Etag, and only when changes occur will it return the new file content.
During that time, the network was very unstable, and disconnections were common. Imagine the experience of downloading a file up to 99% and then losing the connection. To reduce unnecessary data transmission, people quickly added the “resume download” feature to the HTTP protocol. In fact, resume download is viewed from the client’s perspective. From a protocol perspective, the required feature is to transmit data based on a specified range. This means that if the original file is 100 bytes, the client can specify to download only the last 10 bytes:
Content-Range: bytes 91-100/100\r\n Here, 91-100 indicates the range to be downloaded, and the 100 indicates the total length of the file. If the server supports it, it will return:
HTTP/1.1 206 Partial content\r\n
Date: Wed, 15 Nov 1995 06:25:24 GMT\r\n
Last-modified: Wed, 15 Nov 1995 04:58:08 GMT\r\n
Content-Range: bytes 91-100/100\r\n
Content-Length: 10\r\n
Content-Type: image/gif\r\n
\r\n
(image data)
This feature can be used not only for resuming downloads but also for parallel download acceleration. The client can start multiple threads, establish multiple TCP connections, and each thread downloads a portion, finally stitching the content together. It’s that simple.
Additionally, HTTP/1.1 requires clients to send the Host header in requests. This contains the domain name corresponding to the current request. After receiving the request, the server determines what content to return based on the domain name in the Host header and the path in the request line. This enables the establishment of different domain websites on the same IP, known as virtual hosting. This greatly reduces the cost of building websites and plays a crucial role in the development of the web ecosystem.
In addition to extending the original functions of HTTP/1.0, HTTP/1.1 also introduced connection upgrade functionality. In fact, this feature is not used much later, but there is a heavyweight protocol, WebSocket, that uses it, so it must be mentioned.
Connection upgrade means switching the current TCP connection used for HTTP sessions to another protocol. For example, with WebSocket:
GET /chat HTTP/1.1
Host: taoshu.in
Upgrade: websocket
Connection: Upgrade
Here, the Connection is set to Upgrade, indicating a desire to switch protocols. The Upgrade: websocket indicates a switch to the WebSocket protocol. Before switching, this is still a normal HTTP request. The server can perform various authentication and other HTTP actions on this request. If the server accepts the user’s request, it will return:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
From this point on, both parties can no longer send HTTP protocol data on this TCP connection, as the protocol has switched to WebSocket.
From 1999 until the release of HTTP/2 in 2015, the HTTP protocol underwent 15 years without major changes. Meanwhile, the internet flourished, transitioning from Web 1.0 to Web 2.0, from PC internet to mobile internet, and from plain HTTP to encrypted HTTPS. Throughout this process, the HTTP protocol played a central role. This indirectly indicates that the HTTP protocol is a highly extensible protocol.
However, HTTP/1.1 was designed in the 1990s. After 2010, with the rise of mobile internet, the industry sought further optimizations for HTTP issues. What other issues could be optimized? There are several main aspects:
- The protocol uses a text format, resulting in low transmission and parsing efficiency
- Header information cannot be compressed, but in reality, the header size is not small (e.g., cookies)
- Cannot concurrently request resources on a single TCP connection (pipeline failed)
- The server cannot actively send content to the client
The text format is actually a major feature of HTTP. When debugging, we can directly use telnet to connect to the server and visually see the server’s return results. However, a design that is friendly to humans is certainly not friendly to machines. The HTTP protocol uses \r\n as delimiters, which limits the number of header information, inevitably leading to the need for dynamic memory allocation during parsing. Additionally, it requires converting numbers, dates, and other information into corresponding binary formats, all of which incur extra parsing costs.
HTTP/1.x supports compressing data content and uses header information to store compression algorithms. Therefore, the same algorithm cannot be used to compress header information. Alternative methods must be found.
Since HTTP/1.1’s pipeline has already failed, it cannot fully reuse TCP connections. The HTTP protocol has always been designed as a request-response model, and the server cannot actively push content to the client.
To solve these issues, Google, leveraging its two powerful tools, YouTube and Chrome, introduced the SPDY protocol. This protocol has two characteristics:
- Compatible with HTTP semantics
- Uses binary format for data transmission
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+
Figure 1: Frame Layout
Each frame’s first three bytes represent the data length, followed by one byte for type, and another byte for some extended flags. Then there are four bytes for the stream ID, followed by the actual data. This indicates that the HTTP protocol has shifted from delimiter streams to length streams.
On the same TCP connection, data frames can be sent alternately, no longer constrained by the request-response model. This means that the server can also actively send messages to the client. The header and data parts of the same request can also be sent separately, no longer requiring the header to be sent first and then the body. Because of the interleaved transmission of data frames, the data within the same session needs to be associated, so SPDY adds a stream ID to each frame. In other words, SPDY virtually creates multiple streams on a single TCP connection, and each stream behaves like a separate TCP connection. Different HTTP requests and response data can be transmitted concurrently using their own streams without interference, thus solving the first, third, and fourth issues mentioned above.
The second issue is more complicated. However, the solution is also simple. HTTP/1.x header information is in K-V format and is all strings. The K-V pairs rarely change. For example, whenever someone accesses my blog, regardless of how many requests there are, the Host: taoshu.in must be sent. For such unchanging data, we can maintain a mapping table on both ends, assigning a number to each Key and Value. Thus, subsequent requests only need to send the Key and Value numbers, achieving compression. Looking at just the Host may not seem like much progress, but think about your cookies, which contain login session information. Repeatedly sending them wastes a significant amount of bandwidth. Therefore, compressing header information brings remarkable optimization.
Since Google controls the largest market share with its Chrome browser and also controls content services like Google/YouTube, developing the next-generation HTTP protocol became a relatively easy task. SPDY was released in 2012, and it was eventually standardized by the IETF, leading to the release of RFC7540 in 2015.
With the development of society, privacy protection has become an important issue of concern. To protect user information, the industry has been promoting the popularization of HTTP + TLS, i.e., HTTPS. HTTPS services use port 443. As mentioned earlier, HTTP/2 uses binary encoding, which is not compatible with HTTP/1.x. However, clients will not upgrade to HTTP/2 overnight. So how can both HTTP protocols be supported on a single port? This is where the ALPN extension of the TLS protocol comes into play. Simply put, when the client initiates a TLS session, it will include the application layer protocols it supports, such as http/1.1 and h2, through the ALPN extension. The server will return the application layer protocols it supports to the client. This way, both parties can determine which protocol to use in the TLS session.
It is clear that there is a problem here; establishing an HTTP/3 session still requires first using HTTP/2. This is not scientific 🔬 and will introduce additional delays. Therefore, mainstream browsers do not support this.
After the release of HTTP/2, the entire industry actively migrated to the new protocol. However, practice has shown that HTTP/2 is not as good as expected. Why? Because for the same domain, browsers default to opening only one connection, and all requests use a single TCP connection for sending and receiving. Although different requests use different streams, the underlying connection is only one. If the network experiences jitter, regardless of which request’s data needs to be retransmitted, other requests’ data must wait. This is known as the Head of Line blocking problem. HTTP/2 not only did not optimize this but was even worse than HTTP/1.x. In the HTTP/1.x era, browsers were aware that HTTP could not reuse connections, so they would create multiple TCP connections for the same domain. Different requests might be distributed across different connections, which mitigated the impact of network jitter compared to using a single connection.
Another issue with HTTP/2 is its complexity. For example, it supports the server actively pushing resources (such as CSS files) to the browser, which means the client must wait for network transmission when loading. However, this feature is very complex, and its effectiveness is limited; ultimately, even Chrome itself abandoned support for this feature. This functionality was replaced by the HTTP 103 Early Hints status code, which can be referenced in RFC8297.
When one plan fails, another is devised. Google’s engineers tackled the Head of Line blocking problem head-on. This time, they targeted the root cause: the TCP protocol. Since TCP is a reliable transport protocol, data must be sent and received in order, and it must be confirmed before sending. If the underlying connection uses TCP, the Head of Line blocking problem cannot be solved. Therefore, they designed the QUIC protocol based on UDP.
In simple terms, QUIC is a message-oriented transport protocol (TCP is a stream-oriented transport protocol). QUIC also has the concept of streams, allowing multiple streams within a session. Data for different streams is sent and received using UDP, without interference. Like TCP, data must be confirmed after being sent. Then, QUIC maps its frames to HTTP/2 frames, ultimately forming the HTTP/3 protocol, which is RFC9114.
So does QUIC have problems? Yes, but they are mostly not design issues.
The first problem is that operators may throttle UDP traffic, and many firewalls may block QUIC traffic. This is due to the previous limited use of UDP communication. As the technology of HTTP/3 becomes more widespread, these issues will gradually improve.
The second problem is the startup latency of HTTP/3. Since HTTP/3 uses UDP communication, it is not compatible with HTTP/1.x and HTTP/2, so browsers cannot determine whether the server supports HTTP/3.
The current mainstream approach is for websites to support both HTTP/2 and HTTP/3. The browser first accesses the server through a TCP connection. In the first response, the server returns a special header:
Alt-Svc: h3=":4430"; ma=3600
This means that HTTP/3 services are provided on UDP port 4430, and this information is valid for 3600 seconds. The browser can then use QUIC to connect to port 4430.
It is evident that there is a problem here; establishing an HTTP/3 session still requires first using HTTP/2. This is not scientific and will introduce additional delays. Therefore, people began to think of other methods, which is the DNS SVCB/HTTPS record.
DNS SVCB/HTTPS is simply a special DNS record that exposes the previous Alt-Svc information. Before the browser accesses the website, it first queries through DNS to see if HTTP/3 is supported and the corresponding UDP port, and then it can directly initiate an HTTP/3 session. This way, it does not rely on the TCP connection at all. For more information on DNS SVCB/HTTPS records, please refer to my dedicated article.
By the way, HTTP/3 can work on any UDP port by default, unlike HTTPS, which defaults to port 443. If operators block port 443, they cannot provide external services. Once HTTP/3 becomes popular, everyone can use their broadband to set up websites 😄. For specific methods, please refer to my article.
Alright, after writing nearly ten thousand words, I believe I have basically clarified the development context of the HTTP protocol. Due to space limitations, I could not discuss the technical details of HTTP/2 and HTTP/3 in depth, which is a regret. I will leave this as a topic for later. I hope this article helps you better understand the HTTP protocol.
Link: https://taoshu.in/net/http.html
(Copyright belongs to the original author, please delete if infringed)

--完--
读到这里说明你喜欢本公众号的文章,欢迎 置顶(标星)本公众号 架构师指南,这样就可以第一时间获取推送了~
在本公众号 架构师指南,后台回复:架构师,领取2T学习资料 !
推荐阅读
1. 后端架构师技术大全(69个点)
2. 架构师如何设计权限系统?
3. 我怎么才能成为一个架构师 ?
4. 架构师从0搭建一套订单系统!