<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hasan Safwan</title>
    <description>The latest articles on DEV Community by Hasan Safwan (@hasansafwan).</description>
    <link>https://dev.to/hasansafwan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3110022%2F40791f86-db1f-4d24-8e9b-5bd96788e53c.png</url>
      <title>DEV Community: Hasan Safwan</title>
      <link>https://dev.to/hasansafwan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hasansafwan"/>
    <language>en</language>
    <item>
      <title>GROUP BY vs Window Functions in SQL Server — A Practical Guide to SQL Mastery</title>
      <dc:creator>Hasan Safwan</dc:creator>
      <pubDate>Tue, 08 Jul 2025 11:54:05 +0000</pubDate>
      <link>https://dev.to/hasansafwan/group-by-vs-window-functions-in-sql-server-a-practical-guide-to-sql-mastery-4ine</link>
      <guid>https://dev.to/hasansafwan/group-by-vs-window-functions-in-sql-server-a-practical-guide-to-sql-mastery-4ine</guid>
      <description>&lt;h3&gt;
  
  
  GROUP BY vs Window Functions in SQL Server — A Practical Guide to SQL Mastery
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1w5tvdcxdr9eykrzxgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1w5tvdcxdr9eykrzxgq.png" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SQL isn’t just about retrieving data — it’s about generating insight. Whether you’re optimizing reports, powering dashboards, or performing in-depth analysis, two of your most essential tools are GROUP BY and Window Functions.&lt;/p&gt;

&lt;p&gt;At a glance, they may seem interchangeable. In practice, they serve distinct purposes — one reduces and summarizes your data, the other enriches it without losing detail.&lt;/p&gt;

&lt;p&gt;As a developer or data professional aiming for mastery, understanding &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; to use each is crucial. This guide walks you through that decision-making process using practical SQL Server examples. You’ll see not only how they work, but how to apply them together to solve real-world problems cleanly and efficiently.&lt;/p&gt;

&lt;p&gt;Let’s get hands-on — and make these advanced concepts part of your everyday SQL toolbox.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 The Fundamental Difference: A Mental Model
&lt;/h3&gt;

&lt;h4&gt;
  
  
  GROUP BY ➝ “Collapse Your Data”
&lt;/h4&gt;

&lt;p&gt;GROUP BY &lt;strong&gt;reduces&lt;/strong&gt; your data, combining multiple rows into single summary rows. Think of it as &lt;strong&gt;data compression&lt;/strong&gt;  — you’re deliberately reducing the granularity of your dataset to obtain aggregated insights.&lt;/p&gt;

&lt;h4&gt;
  
  
  Window Functions ➝ “Preserve Your Data”
&lt;/h4&gt;

&lt;p&gt;Window Functions &lt;strong&gt;retain all rows&lt;/strong&gt; while adding calculated values based on related rows. Think of them as &lt;strong&gt;augmenting&lt;/strong&gt; your dataset with additional context — the original detail remains intact.&lt;/p&gt;

&lt;p&gt;This distinction is crucial for understanding when to use each approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 GROUP BY: The Data Aggregator
&lt;/h3&gt;

&lt;p&gt;GROUP BY has been part of SQL since its early days, serving as the primary means of aggregating data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Syntax:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    column1,
    column2,
    AGGREGATE_FUNCTION(column3)
FROM
    table_name
GROUP BY
    column1, column2;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key Characteristics:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reduces Row Count&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creates Summaries&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Requires Aggregates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limitations on Output&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  📈 Window Functions: The Row-Preserving Calculator
&lt;/h3&gt;

&lt;p&gt;Window Functions perform calculations across sets of rows related to the current row without collapsing the data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Syntax:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    column1,
    column2,
    WINDOW_FUNCTION() OVER (
        PARTITION BY column1
        ORDER BY column2
    ) AS window_result
FROM
    table_name;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key Characteristics:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Preserves All Rows&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contextual Calculations&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible Comparisons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diverse Function Types&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🧪 Learning by Doing: A Comprehensive Example
&lt;/h3&gt;

&lt;p&gt;Let’s analyze sales data from an e-commerce platform with multiple product categories and regions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample Data:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE sales (
    sale_id INT PRIMARY KEY,
    sale_date DATE,
    product_category VARCHAR(50),
    region VARCHAR(50),
    sales_amount DECIMAL(10,2)
);

INSERT INTO sales VALUES
(1, '2023-01-05', 'Electronics', 'North', 1200.00),
(2, '2023-01-10', 'Furniture', 'South', 3500.00),
(3, '2023-01-12', 'Electronics', 'East', 800.00),
(4, '2023-01-15', 'Clothing', 'West', 450.00),
(5, '2023-01-20', 'Electronics', 'North', 1500.00),
(6, '2023-01-22', 'Clothing', 'East', 650.00),
(7, '2023-01-25', 'Furniture', 'West', 4200.00),
(8, '2023-01-28', 'Electronics', 'South', 950.00),
(9, '2023-01-30', 'Clothing', 'North', 550.00),
(10, '2023-02-05', 'Electronics', 'East', 1100.00);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧠 Scenario 1: Analyzing Category Totals
&lt;/h3&gt;

&lt;h4&gt;
  
  
  GROUP BY:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    product_category,
    SUM(sales_amount) AS total_sales
FROM
    sales
GROUP BY
    product_category
ORDER BY
    total_sales DESC;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Result:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;product_category | total_sales
----------------+------------
Furniture | 7700.00
Electronics | 5550.00
Clothing | 1650.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Window Function:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    sale_id,
    sale_date,
    product_category,
    region,
    sales_amount,
    SUM(sales_amount) OVER (PARTITION BY product_category) AS category_total
FROM
    sales
ORDER BY
    product_category, sale_id;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Result:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sale_id | sale_date | product_category | region | sales_amount | category_total
--------+------------+------------------+--------+--------------+---------------
4 | 2023-01-15 | Clothing | West | 450.00 | 1650.00
6 | 2023-01-22 | Clothing | East | 650.00 | 1650.00
9 | 2023-01-30 | Clothing | North | 550.00 | 1650.00
1 | 2023-01-05 | Electronics | North | 1200.00 | 5550.00
3 | 2023-01-12 | Electronics | East | 800.00 | 5550.00
5 | 2023-01-20 | Electronics | North | 1500.00 | 5550.00
8 | 2023-01-28 | Electronics | South | 950.00 | 5550.00
10 | 2023-02-05 | Electronics | East | 1100.00 | 5550.00
2 | 2023-01-10 | Furniture | South | 3500.00 | 7700.00
7 | 2023-01-25 | Furniture | West | 4200.00 | 7700.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⏱ Scenario 2: Calculating Running Totals
&lt;/h3&gt;

&lt;h4&gt;
  
  
  GROUP BY (with limitations):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH dated_totals AS (
    SELECT
        sale_date,
        product_category,
        SUM(sales_amount) AS daily_total
    FROM
        sales
    GROUP BY
        sale_date, product_category
)
SELECT
    d1.sale_date,
    d1.product_category,
    d1.daily_total,
    SUM(d2.daily_total) AS running_total
FROM
    dated_totals d1
JOIN
    dated_totals d2 ON d2.product_category = d1.product_category
                    AND d2.sale_date &amp;lt;= d1.sale_date
GROUP BY
    d1.sale_date, d1.product_category, d1.daily_total
ORDER BY
    d1.product_category, d1.sale_date;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Window Function:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    sale_id,
    sale_date,
    product_category,
    sales_amount,
    SUM(sales_amount) OVER (
        PARTITION BY product_category
        ORDER BY sale_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total
FROM
    sales
ORDER BY
    product_category, sale_date;

sale_id | sale_date | product_category | sales_amount | running_total
--------+------------+------------------+--------------+--------------
4 | 2023-01-15 | Clothing | 450.00 | 450.00
6 | 2023-01-22 | Clothing | 650.00 | 1100.00
9 | 2023-01-30 | Clothing | 550.00 | 1650.00
1 | 2023-01-05 | Electronics | 1200.00 | 1200.00
3 | 2023-01-12 | Electronics | 800.00 | 2000.00
5 | 2023-01-20 | Electronics | 1500.00 | 3500.00
8 | 2023-01-28 | Electronics | 950.00 | 4450.00
10 | 2023-02-05 | Electronics | 1100.00 | 5550.00
2 | 2023-01-10 | Furniture | 3500.00 | 3500.00
7 | 2023-01-25 | Furniture | 4200.00 | 7700.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  📉 Scenario 3: Comparing Performance Against Category Averages
&lt;/h4&gt;

&lt;h4&gt;
  
  
  GROUP BY with JOIN:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    s.sale_id,
    s.product_category,
    s.sales_amount,
    cat_avg.avg_amount,
    s.sales_amount - cat_avg.avg_amount AS diff_from_avg
FROM
    sales s
JOIN (
    SELECT
        product_category,
        AVG(sales_amount) AS avg_amount
    FROM
        sales
    GROUP BY
        product_category
) cat_avg ON s.product_category = cat_avg.product_category
ORDER BY
    s.product_category, s.sale_id;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Window Function:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    sale_id,
    product_category,
    sales_amount,
    AVG(sales_amount) OVER (PARTITION BY product_category) AS category_avg,
    sales_amount - AVG(sales_amount) OVER (PARTITION BY product_category) AS diff_from_avg
FROM
    sales
ORDER BY
    product_category, sale_id;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Result:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sale_id | product_category | sales_amount | category_avg | diff_from_avg
--------+------------------+--------------+--------------+--------------
4 | Clothing | 450.00 | 550.00 | -100.00
6 | Clothing | 650.00 | 550.00 | 100.00
9 | Clothing | 550.00 | 550.00 | 0.00
1 | Electronics | 1200.00 | 1110.00 | 90.00
3 | Electronics | 800.00 | 1110.00 | -310.00
5 | Electronics | 1500.00 | 1110.00 | 390.00
8 | Electronics | 950.00 | 1110.00 | -160.00
10 | Electronics | 1100.00 | 1110.00 | -10.00
2 | Furniture | 3500.00 | 3850.00 | -350.00
7 | Furniture | 4200.00 | 3850.00 | 350.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🥇 Scenario 4: Ranking Sales Within Categories
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;GROUP BY with Derived Table (complex):&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH sales_with_rownum AS (
    SELECT
        s.*,
        (SELECT COUNT(*)
         FROM sales s2
         WHERE s2.product_category = s.product_category
           AND s2.sales_amount &amp;gt;= s.sales_amount) AS rank_value
    FROM
        sales s
)
SELECT
    sale_id,
    product_category,
    sales_amount,
    rank_value
FROM
    sales_with_rownum
ORDER BY
    product_category, rank_value;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Window Function:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    sale_id,
    product_category,
    sales_amount,
    RANK() OVER (
        PARTITION BY product_category
        ORDER BY sales_amount DESC
    ) AS sales_rank
FROM
    sales
ORDER BY
    product_category, sales_rank;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Result:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sale_id | product_category | sales_amount | sales_rank
--------+------------------+--------------+-----------
6 | Clothing | 650.00 | 1
9 | Clothing | 550.00 | 2
4 | Clothing | 450.00 | 3
5 | Electronics | 1500.00 | 1
1 | Electronics | 1200.00 | 2
10 | Electronics | 1100.00 | 3
8 | Electronics | 950.00 | 4
3 | Electronics | 800.00 | 5
7 | Furniture | 4200.00 | 1
2 | Furniture | 3500.00 | 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📆 Scenario 5: Category Performance by Month with Trend Analysis
&lt;/h3&gt;

&lt;h4&gt;
  
  
  GROUP BY + Window Functions:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH monthly_category_sales AS (
    SELECT
        DATETRUNC(month, sale_date) AS month,
        product_category,
        SUM(sales_amount) AS monthly_sales
    FROM
        sales
    GROUP BY
        DATETRUNC(month, sale_date), product_category
)
SELECT
    month,
    product_category,
    monthly_sales,
    LAG(monthly_sales) OVER (
        PARTITION BY product_category
        ORDER BY month
    ) AS previous_month_sales,
    monthly_sales - LAG(monthly_sales) OVER (
        PARTITION BY product_category
        ORDER BY month
    ) AS month_over_month_change,
    RANK() OVER (
        PARTITION BY month
        ORDER BY monthly_sales DESC
    ) AS category_rank_in_month
FROM
    monthly_category_sales
ORDER BY
    month, category_rank_in_month;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧭 Making the Right Choice: When to Use Each Approach
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Use GROUP BY when:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You need summary statistics&lt;/li&gt;
&lt;li&gt;You want to reduce result set size&lt;/li&gt;
&lt;li&gt;You’re consolidating data for reports or charts&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Use Window Functions when:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You want row-level insight + aggregate context&lt;/li&gt;
&lt;li&gt;You’re calculating rankings, running totals, differences&lt;/li&gt;
&lt;li&gt;You want to avoid complex JOINs or subqueries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;💡 Think: GROUP BY = Collapse | Window = Preserve + Enrich&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 SQL Server Performance Considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GROUP BY&lt;/strong&gt; benefits from columnstore indexes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Window Functions&lt;/strong&gt; may use more memory — check execution plans&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;identical PARTITION/ORDER clauses&lt;/strong&gt; to optimize multiple window calcs&lt;/li&gt;
&lt;li&gt;Consider indexed views for frequent GROUP BY queries&lt;/li&gt;
&lt;li&gt;SQL Server shares computations between window functions with same clauses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🆚 Quick Reference: GROUP BY vs Window Functions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Use Case | GROUP BY | Window Functions |
|-----------------------------------|--------------------|--------------------------|
| Collapse data | ✅ | ❌ |
| Preserve row-level detail | ❌ | ✅ |
| Running totals / moving averages | ❌ (complex) | ✅ (simple) |
| Ranking within groups | ❌ (manual) | ✅ (built-in) |
| Filtering aggregates | ✅ (via HAVING) | ❌ |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Conclusion
&lt;/h3&gt;

&lt;p&gt;GROUP BY &lt;strong&gt;collapses&lt;/strong&gt; your data for summaries. Window Functions &lt;strong&gt;enhance&lt;/strong&gt; your data without losing detail.&lt;/p&gt;

&lt;p&gt;Master both. Combine them when needed. And you’ll unlock advanced, elegant, performant SQL.&lt;/p&gt;

&lt;p&gt;Happy querying! 🎯&lt;/p&gt;

</description>
      <category>sqlserver</category>
      <category>dataengineering</category>
      <category>techleadership</category>
      <category>sql</category>
    </item>
    <item>
      <title>Understanding HTTP Request Headers: Classification, Behavior, and How Servers React</title>
      <dc:creator>Hasan Safwan</dc:creator>
      <pubDate>Wed, 21 May 2025 06:57:24 +0000</pubDate>
      <link>https://dev.to/hasansafwan/understanding-http-request-headers-classification-behavior-and-how-servers-react-h71</link>
      <guid>https://dev.to/hasansafwan/understanding-http-request-headers-classification-behavior-and-how-servers-react-h71</guid>
      <description>&lt;h4&gt;
  
  
  &lt;em&gt;Demystifying HTTP for Web Developers — Part 3&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxvmo9mqpdyjcjl08glv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxvmo9mqpdyjcjl08glv.png" width="700" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP Headers: The Real Drivers of Behavior
&lt;/h3&gt;

&lt;p&gt;In Part 2 of this series, we dissected the structure of an HTTP request — from the request line to headers and message body. We saw how a minimal request could be valid, but real-world HTTP traffic rarely resembles those minimal forms. In practice, requests are filled with headers that instruct servers, inform intermediaries, and enable negotiation.&lt;/p&gt;

&lt;p&gt;Request headers are not mere accessories. They are the instruments through which clients express identity, context, preference, and security credentials. They control everything from whether a server compresses a response to whether the request is authorized. Without headers, HTTP cannot fulfill its role as a stateless, flexible, and interoperable protocol.&lt;/p&gt;

&lt;p&gt;In this article, we shift our focus from structure to semantics. We’ll analyze headers from three angles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RFC-defined syntax and classification&lt;/li&gt;
&lt;li&gt;Real client behavior using Postman&lt;/li&gt;
&lt;li&gt;Real server behavior using ASP.NET Core MVC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not just to understand what headers exist — but to see how they influence behavior and how a modern web framework processes them in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are HTTP Headers?
&lt;/h3&gt;

&lt;p&gt;HTTP headers are textual metadata fields included in request and response messages. Each header is a key-value pair, defined in the format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;field-name: token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure is formally defined in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-5.1" rel="noopener noreferrer"&gt;RFC 9110 §5.1&lt;/a&gt;. Field names are case-insensitive, and whitespace around the colon is ignored. Values can be simple strings or structured lists, depending on the header.&lt;/p&gt;

&lt;p&gt;Header field semantics are defined individually across the specification, depending on their purpose. There is no dedicated section in RFC 9110 for general request header semantics; instead, each header is defined in context. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-accept" rel="noopener noreferrer"&gt;Accept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-accept-encoding" rel="noopener noreferrer"&gt;Accept-Encoding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-authorization" rel="noopener noreferrer"&gt;Authorization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-user-agent" rel="noopener noreferrer"&gt;User-Agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-content-type" rel="noopener noreferrer"&gt;Content-Type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-content-length" rel="noopener noreferrer"&gt;Content-Length&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Headers are placed between the request line and the optional body. They are terminated by a blank line (CRLF) that signals the start of the body. In ASP.NET Core, headers are accessible via the Request.Headers dictionary, which automatically handles normalization and case insensitivity.&lt;/p&gt;

&lt;p&gt;Here is an example of a request as seen in Postman’s “Console” tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/home HTTP/1.1
User-Agent: PostmanRuntime/7.43.0
Accept: */*
Postman-Token: 865051eb-6af4-4900-b82c-a96172193517
Host: localhost:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F707n9d353khrf8emclan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F707n9d353khrf8emclan.png" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ASP.NET Core allows you to inspect them directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpGet]
[Route("Inspect")
public IActionResult Inspect()
{
    var userAgent = Request.Headers["User-Agent"].ToString();
    var accept = Request.Headers["Accept"].ToString();
    var correlationId = Request.Headers["X-Correlation-ID"].FirstOrDefault();

    return Ok(new
    {
        UserAgent = userAgent,
        Accept = accept,
        CorrelationId = correlationId
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyukgt0bpfjw6i2g0fxme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyukgt0bpfjw6i2g0fxme.png" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Header Classification and Behavior
&lt;/h3&gt;

&lt;p&gt;To reason about headers systematically, it’s useful to classify them based on their function and scope.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. General Headers
&lt;/h4&gt;

&lt;p&gt;These apply to both requests and responses, and often relate to message handling rather than payload semantics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache-Control: controls caching behavior&lt;/li&gt;
&lt;li&gt;Connection: indicates connection persistence (e.g., keep-alive)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Request Headers
&lt;/h4&gt;

&lt;p&gt;Used only in client-to-server communication. These inform the server about the client’s capabilities, preferences, or context.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accept: indicates preferred response formats&lt;/li&gt;
&lt;li&gt;Accept-Encoding: lists supported compression algorithms&lt;/li&gt;
&lt;li&gt;User-Agent: identifies client software&lt;/li&gt;
&lt;li&gt;Authorization: supplies credentials (e.g., Bearer tokens)&lt;/li&gt;
&lt;li&gt;Referer, Origin: supply context for cross-origin requests&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Entity Headers
&lt;/h4&gt;

&lt;p&gt;These describe the content of the message body.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content-Type: media type of the payload&lt;/li&gt;
&lt;li&gt;Content-Length: size in bytes&lt;/li&gt;
&lt;li&gt;Content-Encoding: compression applied to the body&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4. Custom Headers
&lt;/h4&gt;

&lt;p&gt;These are not defined by the core specification but widely used in real-world applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;X-Correlation-ID: used to trace requests across distributed systems&lt;/li&gt;
&lt;li&gt;X-Requested-With: often used in AJAX requests to differentiate browser types&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Observing Header Behavior in ASP.NET Core MVC
&lt;/h3&gt;

&lt;p&gt;Let’s now see how headers affect behavior using Postman and how ASP.NET Core interprets them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Accept Header and Format Negotiation
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; A client sends Accept: application/json expecting a JSON response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postman Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/home HTTP/1.1
Accept: application/json
User-Agent: PostmanRuntime/7.43.0
Postman-Token: 012874d8-ddcd-4f65-9e36-6abd3f97a722
Host: localhost:5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbqujhfscx0ret8s56dk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbqujhfscx0ret8s56dk.png" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5c865jyot9j17esej1l7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5c865jyot9j17esej1l7.png" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Core Behavior:&lt;/strong&gt; By default, ASP.NET Core uses registered output formatters to serialize the response. JSON is the default. If you request text/html, ASP.NET Core may still return JSON unless strict negotiation is enabled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without strict negotiation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm090r315k1udqxee7hmn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm090r315k1udqxee7hmn.png" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With strict negotation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddControllers(options =&amp;gt;
{
    options.ReturnHttpNotAcceptable = true;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrk55xy4m46bj8erlb8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrk55xy4m46bj8erlb8y.png" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this option enabled, unsupported formats will result in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;406 Not Acceptable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24ppcvwj5toe9w1qtvoq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24ppcvwj5toe9w1qtvoq.png" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Content-Type and Model Binding
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; A POST request includes JSON data but does not specify Content-Type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postman Body:&lt;/strong&gt; Raw → JSON&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "email": "user@example.com",
    "password": "123"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Missing Header:&lt;/strong&gt; Content-Type: application/json&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Core Behavior:&lt;/strong&gt; Model binding fails. The action may receive a null model or return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;415 Unsupported Media Type
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaalpbxqpqheuvc8fbct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaalpbxqpqheuvc8fbct.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Model binding depends on Content-Type matching a registered input formatter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Authorization Header
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; A client sends an access token using Authorization: Bearer .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postman Setup:&lt;/strong&gt; Use the “Authorization” tab → Bearer Token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Core Behavior:&lt;/strong&gt; If JWT authentication is configured, [Authorize] attributes will automatically enforce security. No manual parsing of headers is required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Authorize]
[HttpGet("secure")]
public IActionResult SecureEndpoint() =&amp;gt; Ok("Access granted.");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invalid or missing tokens return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;401 Unauthorized
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Accept-Encoding and Compression
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; The client requests compressed content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Header:&lt;/strong&gt; Accept-Encoding: gzip&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Core Setup:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddResponseCompression();
app.UseResponseCompression();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ASP.NET Core automatically compresses responses if the client supports it. You’ll see Content-Encoding: gzip in the response headers and reduced payload size.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9oo98xuzv093kcedz1ly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9oo98xuzv093kcedz1ly.png" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  X-Correlation-ID and Middleware Handling
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; You want to enforce that a custom header is present on all requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Middleware Implementation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class CorrelationIdMiddleware
{
    public async Task Invoke(HttpContext context, RequestDelegate next)
    {
        if (!context.Request.Headers.ContainsKey("X-Correlation-ID"))
        {
            context.Response.StatusCode = 400;
            await context.Response.WriteAsync("Missing X-Correlation-ID");
            return;
        }

        await next(context);
    }
}

public class CorrelationIdMiddleware
{
    public async Task Invoke(HttpContext context, RequestDelegate next)
    {
        if (!context.Request.Headers.ContainsKey("X-Correlation-ID"))
        {
            context.Response.StatusCode = 400;
            await context.Response.WriteAsync("Missing X-Correlation-ID");
            return;
        }

        await next(context);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is commonly used for enforcing traceability in distributed environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Pitfalls and Clarifications
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accept is not enforced by default.&lt;/strong&gt; ASP.NET Core responds with the best available formatter unless explicitly configured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content-Type must match the request body.&lt;/strong&gt; Otherwise, model binding fails silently or throws a 415.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom headers are not validated.&lt;/strong&gt; You must implement your own enforcement logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some headers can be duplicated (e.g., Accept). Others cannot (e.g., Content-Length).&lt;/strong&gt; Duplicate Content-Length can result in request rejection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case insensitivity is handled for you.&lt;/strong&gt; Request.Headers["accept"] and Request.Headers["Accept"] return the same result.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;HTTP request headers are not ornamental — they are essential. They determine how content is negotiated, how credentials are passed, how bodies are interpreted, and how APIs are secured. In ASP.NET Core, headers are not only accessible but also actionable through middleware, model binding, and authentication frameworks.&lt;/p&gt;

&lt;p&gt;By learning how to inspect and react to headers with precision, you move from merely calling endpoints to truly mastering the protocol beneath your applications.&lt;/p&gt;

&lt;p&gt;In Part 4, we’ll shift to the body of the request — exploring payloads, semantics, media types, and how to handle them securely and effectively in modern APIs.&lt;/p&gt;

</description>
      <category>backenddevelopment</category>
      <category>webdev</category>
      <category>techleadership</category>
      <category>postman</category>
    </item>
    <item>
      <title>OUTPUT Clause — Log, Sync, and Debug Like a Pro</title>
      <dc:creator>Hasan Safwan</dc:creator>
      <pubDate>Tue, 20 May 2025 11:54:39 +0000</pubDate>
      <link>https://dev.to/hasansafwan/output-clause-log-sync-and-debug-like-a-pro-58hj</link>
      <guid>https://dev.to/hasansafwan/output-clause-log-sync-and-debug-like-a-pro-58hj</guid>
      <description>&lt;h3&gt;
  
  
  OUTPUT Clause — Log, Sync, and Debug Like a Pro
&lt;/h3&gt;

&lt;h4&gt;
  
  
  From auditing to syncing to debugging: how to use SQL Server’s OUTPUT clause the right way.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhs96lkaupeaq5xz78h2a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhs96lkaupeaq5xz78h2a.png" alt="Article Title About SQL OUTPUT Clause" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re building reliable data systems in SQL Server, understanding the OUTPUT clause isn't optional—it's essential.&lt;/p&gt;

&lt;p&gt;This feature allows you to capture the exact rows affected by INSERT, UPDATE, DELETE, or MERGE statements in real time. Whether you're logging changes, syncing rows between tables, or debugging multi-row operations, the OUTPUT clause offers a clean, consistent way to work with the data your statements are modifying.&lt;/p&gt;

&lt;p&gt;In this article, you’ll learn how to use OUTPUT effectively through real-world examples. Each section includes a complete, self-contained SQL script to help you build practical skills that scale—from small updates to high-volume transactional systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Understanding inserted and deleted: Virtual Tables in Action
&lt;/h3&gt;

&lt;p&gt;The OUTPUT clause relies on two special &lt;strong&gt;virtual tables&lt;/strong&gt; to expose the rows being modified by your SQL operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;inserted&lt;/strong&gt; : Contains the new values being inserted, or the &lt;em&gt;after&lt;/em&gt; state of a row in an UPDATE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;deleted&lt;/strong&gt; : Contains the old values being deleted, or the &lt;em&gt;before&lt;/em&gt; state of a row in an UPDATE.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are &lt;strong&gt;temporary, in-memory tables&lt;/strong&gt;  — available only within the scope of a DML operation. Think of them as snapshots of the data you're changing.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧪 Examples
&lt;/h4&gt;

&lt;h4&gt;
  
  
  On INSERT
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO Products (Name, Price)
OUTPUT inserted.Name, inserted.Price
VALUES ('USB Cable', 9.99);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ inserted holds the row that was just added.&lt;/p&gt;

&lt;h4&gt;
  
  
  On DELETE
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELETE FROM Products
OUTPUT deleted.Name, deleted.Price
WHERE Price &amp;gt; 1000;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ deleted shows the row &lt;em&gt;before&lt;/em&gt; it’s removed.&lt;/p&gt;

&lt;h4&gt;
  
  
  On UPDATE
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UPDATE Products
SET Price = Price * 1.1
OUTPUT deleted.Price AS OldPrice, inserted.Price AS NewPrice;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Combines both: deleted for the old value, inserted for the new.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 Use Case #1 — Logging Updates with Old and New Values
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🚀 Goal
&lt;/h4&gt;

&lt;p&gt;Track exactly what changed in your UPDATE statements by capturing the old and new values— &lt;strong&gt;without triggers&lt;/strong&gt; , &lt;strong&gt;without extra queries&lt;/strong&gt; , and all within the same transaction.&lt;/p&gt;

&lt;h4&gt;
  
  
  📦 Scenario
&lt;/h4&gt;

&lt;p&gt;You have an Orders table. When the order status changes, you want to log both the old and new values into a dedicated OrderAudit table. This allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debug state changes&lt;/li&gt;
&lt;li&gt;Generate audit trails&lt;/li&gt;
&lt;li&gt;Monitor workflow transitions (e.g., from &lt;em&gt;Processing&lt;/em&gt; to &lt;em&gt;Shipped&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧱️ Setup: Create the Tables
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Main table
CREATE TABLE Orders (
    OrderID INT PRIMARY KEY IDENTITY(1,1),
    CustomerName NVARCHAR(100),
    Status NVARCHAR(50),
    OrderDate DATE
);

-- Insert sample data
INSERT INTO Orders (CustomerName, Status, OrderDate)
VALUES
    ('Alice', 'Processing', '2024-11-01'),
    ('Bob', 'Processing', '2024-11-03'),
    ('Charlie', 'Shipped', '2024-11-05');

-- Audit log table
CREATE TABLE OrderAudit (
    AuditID INT PRIMARY KEY IDENTITY(1,1),
    OrderID INT,
    OldStatus NVARCHAR(50),
    NewStatus NVARCHAR(50),
    ChangedAt DATETIME DEFAULT GETDATE()
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ⚙️ Operation: Update + Log with OUTPUT
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Update orders and log status change
UPDATE Orders
SET Status = 'Shipped'
OUTPUT
    deleted.OrderID,
    deleted.Status AS OldStatus,
    inserted.Status AS NewStatus,
    GETDATE() AS ChangedAt
INTO OrderAudit (OrderID, OldStatus, NewStatus, ChangedAt)
WHERE Status = 'Processing';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✅ Result
&lt;/h4&gt;

&lt;p&gt;After running the script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orders with status Processing will be updated to Shipped&lt;/li&gt;
&lt;li&gt;OrderAudit will contain a row for each updated order, including the before-and-after values&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧠 Why This Matters
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;No triggers or temp tables needed&lt;/li&gt;
&lt;li&gt;Everything is captured &lt;em&gt;in the same transaction&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Works just as well for a single row as for hundreds&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔍 Use Case #2 — Capturing Identity Values on INSERT
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🚀 Goal
&lt;/h4&gt;

&lt;p&gt;Capture the identity values generated during an INSERT statement—especially for bulk inserts—without relying on SCOPE_IDENTITY() or separate queries.&lt;/p&gt;

&lt;h4&gt;
  
  
  📦 Scenario
&lt;/h4&gt;

&lt;p&gt;You need to insert new users into a table with an IDENTITY column and then process or store their generated IDs. This is a common requirement in syncing systems, queueing, or auditing workflows.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧱️ Setup: Create the Table
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Users table with IDENTITY column
CREATE TABLE Users (
    UserID INT IDENTITY(1,1) PRIMARY KEY,
    Username NVARCHAR(100),
    Email NVARCHAR(255)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ⚙️ Operation: Insert + Capture Identity
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Insert new users and capture generated UserIDs
INSERT INTO Users (Username, Email)
OUTPUT inserted.UserID, inserted.Username, inserted.Email
VALUES 
    ('alice', 'alice@example.com'),
    ('bob', 'bob@example.com');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✅ Result
&lt;/h4&gt;

&lt;p&gt;This will insert two new users into the Users table and return the corresponding UserID, Username, and Email for each one.&lt;/p&gt;

&lt;p&gt;Unlike SCOPE_IDENTITY(), which only returns the last inserted identity value, the OUTPUT clause works seamlessly with multiple rows.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧠 Why This Matters
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Works for &lt;strong&gt;multi-row inserts&lt;/strong&gt; , not just one&lt;/li&gt;
&lt;li&gt;No race conditions or separate queries needed&lt;/li&gt;
&lt;li&gt;Eliminates the need for temp tables or additional logic to track inserted IDs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔍 Use Case #3 — Backing Up Deleted Records with OUTPUT INTO
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🚀 Goal
&lt;/h4&gt;

&lt;p&gt;Safely back up the data you are about to delete by writing it into a separate archival table — before the delete takes effect.&lt;/p&gt;

&lt;h4&gt;
  
  
  📦 Scenario
&lt;/h4&gt;

&lt;p&gt;You want to remove inactive customers from your main table, but store a copy of their data for historical or audit purposes.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧱️ Setup: Create the Tables
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Customers table
CREATE TABLE Customers (
    CustomerID INT PRIMARY KEY IDENTITY(1,1),
    Name NVARCHAR(100),
    Email NVARCHAR(255),
    IsInactive BIT
);

-- Sample data
INSERT INTO Customers (Name, Email, IsInactive)
VALUES
    ('Alice', 'alice@example.com', 1),
    ('Bob', 'bob@example.com', 0),
    ('Charlie', 'charlie@example.com', 1);

-- Archive table
CREATE TABLE DeletedCustomersBackup (
    CustomerID INT,
    Name NVARCHAR(100),
    Email NVARCHAR(255),
    DeletedAt DATETIME DEFAULT GETDATE()
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ⚙️ Operation: Delete + Backup with OUTPUT INTO
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Delete and back up rows in one atomic step
DELETE FROM Customers
OUTPUT 
    deleted.CustomerID, 
    deleted.Name, 
    deleted.Email, 
    GETDATE()
INTO DeletedCustomersBackup (CustomerID, Name, Email, DeletedAt)
WHERE IsInactive = 1;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✅ Result
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Inactive customers are removed from the Customers table&lt;/li&gt;
&lt;li&gt;Their data is copied into DeletedCustomersBackup with a timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧠 Why This Matters
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates the need for a separate SELECT before DELETE&lt;/li&gt;
&lt;li&gt;Guarantees no data loss or mismatch due to timing&lt;/li&gt;
&lt;li&gt;Makes rollback or archiving strategies easier to implement&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔍 Use Case #4 — Syncing Inserted Data to Another Table
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🚀 Goal
&lt;/h4&gt;

&lt;p&gt;Automatically copy inserted data into a separate table for downstream processing or replication.&lt;/p&gt;

&lt;h4&gt;
  
  
  📦 Scenario
&lt;/h4&gt;

&lt;p&gt;You insert new users into a production table and want to queue them for synchronization by inserting their IDs into a UserSyncQueue table.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧱️ Setup: Create the Tables
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Base users table
CREATE TABLE UsersForSync (
    UserID INT IDENTITY(1,1) PRIMARY KEY,
    Username NVARCHAR(100),
    Email NVARCHAR(255)
);

-- Sync queue table
CREATE TABLE UserSyncQueue (
    UserID INT,
    SyncStatus NVARCHAR(20) DEFAULT 'Pending'
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ⚙️ Operation: Insert + Sync ID into Queue
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Insert users and enqueue for sync
INSERT INTO UsersForSync (Username, Email)
OUTPUT inserted.UserID
INTO UserSyncQueue (UserID)
VALUES
    ('dave', 'dave@example.com'),
    ('emma', 'emma@example.com');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✅ Result
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Two new users are inserted into UsersForSync&lt;/li&gt;
&lt;li&gt;Their UserIDs are automatically copied into UserSyncQueue with a default status of Pending&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧠 Why This Matters
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Keeps sync queues accurate and up-to-date&lt;/li&gt;
&lt;li&gt;Avoids post-insert lookups or application logic&lt;/li&gt;
&lt;li&gt;Ensures atomicity between insert and sync registration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔍 Use Case #5 — Verifying DML Impact Safely with CTAS + OUTPUT
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🚀 Goal
&lt;/h4&gt;

&lt;p&gt;Use the OUTPUT clause to verify what your DML statements are doing by executing them safely against a test copy of your table.&lt;/p&gt;

&lt;h4&gt;
  
  
  📦 Scenario
&lt;/h4&gt;

&lt;p&gt;You need to debug a complex UPDATE logic but want to be absolutely sure it affects the correct rows before applying it in production.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧱️ Setup: Create the Test Table
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Original table
CREATE TABLE Inventory (
    ItemID INT PRIMARY KEY IDENTITY(1,1),
    ItemName NVARCHAR(100),
    Stock INT
);

-- Sample data
INSERT INTO Inventory (ItemName, Stock)
VALUES 
    ('USB Cable', 10),
    ('Webcam', 5),
    ('Laptop Stand', 3);

-- Test copy of the table
SELECT * INTO Inventory_Test FROM Inventory;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ⚙️ Operation: Debug the Update Logic
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Use OUTPUT to verify what will change
UPDATE Inventory_Test
SET Stock = Stock + 5
OUTPUT 
    inserted.ItemName,
    deleted.Stock AS OldStock,
    inserted.Stock AS NewStock
WHERE Stock &amp;lt; 10;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✅ Result
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Inventory_Test is updated, but the original Inventory remains untouched&lt;/li&gt;
&lt;li&gt;You get full visibility of what the update affects&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧠 Why This Matters
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Provides a &lt;strong&gt;safe debug sandbox&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Lets you observe and validate row-level changes&lt;/li&gt;
&lt;li&gt;Avoids the risk of corrupting production data while testing logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📊 Conclusion
&lt;/h3&gt;

&lt;p&gt;The OUTPUT clause is one of SQL Server's most flexible tools for capturing row-level data during DML operations. Whether you're auditing changes, syncing systems, backing up deletions, or validating logic during development, OUTPUT offers a powerful, declarative way to observe and act on data as it's being modified.&lt;/p&gt;

&lt;p&gt;By using inserted and deleted pseudo-tables, and pairing the OUTPUT clause with patterns like CTAS, you can write more predictable, traceable, and maintainable SQL code that scales from development through to production.&lt;/p&gt;

&lt;p&gt;Next time you write an INSERT, UPDATE, or DELETE, ask yourself: &lt;em&gt;"What just happened here?"&lt;/em&gt; With the OUTPUT clause, you’ll know exactly what changed—and why.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>backenddevelopment</category>
      <category>sql</category>
      <category>sqlserver</category>
    </item>
    <item>
      <title>Dissecting the HTTP Request — Line by Line</title>
      <dc:creator>Hasan Safwan</dc:creator>
      <pubDate>Tue, 06 May 2025 20:17:17 +0000</pubDate>
      <link>https://dev.to/hasansafwan/dissecting-the-http-request-line-by-line-39cn</link>
      <guid>https://dev.to/hasansafwan/dissecting-the-http-request-line-by-line-39cn</guid>
      <description>&lt;h3&gt;
  
  
  Dissecting the HTTP Request — Line by Line
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Demystifying HTTP for Web Developers, Part 2
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F700%2F0%2AYJCsi8BQLdSUj1UY" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F700%2F0%2AYJCsi8BQLdSUj1UY" alt="Illustration of a developer opening a glowing box labeled ‘HTTP’, revealing HTTP concepts like GET, POST, Cache-Control, and Content-Type — representing the idea of demystifying HTTP" width="700" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Every Byte Matters
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://dev.to/hasansafwan/demystifying-http-for-web-developers-part-1-3269"&gt;Part 1 of this series&lt;/a&gt;, we traced the full journey of an HTTP request — from typing a URL in the browser, through DNS resolution and TCP handshakes, all the way to receiving the server’s response. But understanding the &lt;em&gt;path&lt;/em&gt; a request travels is only half the story. To truly master HTTP, we now need to dissect the &lt;strong&gt;payload&lt;/strong&gt; that actually moves across the wire: the HTTP request itself.&lt;/p&gt;

&lt;p&gt;Every interaction between a web client and a server begins with a carefully structured message — the request. It may look simple on the surface, but every line, header, and byte in that request carries meaning. If you’re building serious web applications, APIs, or even debugging flaky integrations, you can’t afford to treat the request as a black box.&lt;/p&gt;

&lt;p&gt;In this article, we’ll break down the HTTP request line by line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What makes a valid request?&lt;/li&gt;
&lt;li&gt;What parts are required, optional, or misunderstood?&lt;/li&gt;
&lt;li&gt;How do headers affect server behavior?&lt;/li&gt;
&lt;li&gt;And how can you inspect or even construct requests manually?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll explore both theory and hands-on examples using tools like curl, Wireshark, and even manual HTTP requests typed in PuTTY — because nothing builds real understanding like observing how servers respond to raw protocol input.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By the end, you’ll be able to read and write HTTP requests like a network engineer — and debug them like one too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s peel it apart.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Simplest Request That Works
&lt;/h3&gt;

&lt;p&gt;Before diving into advanced use cases, let’s first understand the &lt;strong&gt;bare minimum structure of a valid HTTP/1.1 request&lt;/strong&gt;  — one that any compliant server will accept and respond to.&lt;/p&gt;

&lt;h4&gt;
  
  
  General Syntax of an HTTP Request
&lt;/h4&gt;

&lt;p&gt;According to &lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#section-2" rel="noopener noreferrer"&gt;RFC 9112 §2&lt;/a&gt;, the syntax of a client request message in HTTP/1.1 is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Request Line&amp;gt;
&amp;lt;Header Fields&amp;gt;
&amp;lt;CRLF&amp;gt;
&amp;lt;Optional Message Body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s look at the most minimal real-world example that fits this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET / HTTP/1.1
Host: example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though it has only two lines, this message fully complies with the HTTP/1.1 protocol.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Request Line
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET / HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line contains three elements, separated by single spaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt; : GET
→ Tells the server what action the client wants to perform.
→ GET means “retrieve this resource without modifying anything.”
→ Defined in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-get" rel="noopener noreferrer"&gt;RFC 9110 §9.3.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Target&lt;/strong&gt; : /
→ The path to the desired resource on the server.
→ The simplest form is a relative path, but it can also be a full URI in proxy contexts.
→ See &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-7.1" rel="noopener noreferrer"&gt;RFC 9110 §7.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Version&lt;/strong&gt; : HTTP/1.1
→ Indicates the HTTP protocol version used for this message.
→ Syntax defined in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#section-2.3" rel="noopener noreferrer"&gt;RFC 9112 §2.3&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this line is malformed — missing spaces, an invalid method, or no version — the server will typically respond with 400 Bad Request.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Header Fields
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host: example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the only &lt;strong&gt;mandatory&lt;/strong&gt; header in HTTP/1.1. It tells the server which hostname the client is trying to reach — something older versions of HTTP couldn’t do.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;What Are Headers?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;HTTP headers are key-value pairs that provide &lt;strong&gt;metadata&lt;/strong&gt; about a request or response. They influence everything from content format to caching behavior to security. While we’ll explore headers in depth in the next article, for now just know that headers are how clients &lt;strong&gt;communicate intent and context&lt;/strong&gt; to servers.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why the Host Header Matters
&lt;/h4&gt;

&lt;p&gt;HTTP/1.1 introduced the concept of &lt;strong&gt;virtual hosting&lt;/strong&gt; , where a single server (and IP address) can serve multiple domains. The Host header is how the client specifies &lt;em&gt;which&lt;/em&gt; domain it wants.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A client MUST send a Host header field in all HTTP/1.1 request messages.”&lt;br&gt;&lt;br&gt;
 — &lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#section-3.2" rel="noopener noreferrer"&gt;RFC 9112 §3.2&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without this header, the server will reject the request — typically with a 400 status code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why Host Is Not Required in HTTP/2 and HTTP/3
&lt;/h4&gt;

&lt;p&gt;In HTTP/2 and HTTP/3, requests are not sent as raw text but as &lt;strong&gt;structured binary frames&lt;/strong&gt;. Instead of the Host header, the protocol uses a pseudo-header called :authority to represent the intended host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:method: GET
:scheme: https
:authority: example.com
:path: /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is required per &lt;a href="https://datatracker.ietf.org/doc/html/rfc9113#section-8.3.1" rel="noopener noreferrer"&gt;RFC 9113 §8.3.1&lt;/a&gt; for HTTP/2 and similarly in HTTP/3. Many clients still send the traditional Host header as well for backward compatibility, but it's no longer required by the protocol.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP/1.1&lt;/strong&gt; requires Host.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP/2 and 3&lt;/strong&gt; use :authority instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Both identify which virtual host the request is for.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3. Blank Line (CRLF)
&lt;/h4&gt;

&lt;p&gt;Even when no body is present, the end of the header section &lt;strong&gt;must&lt;/strong&gt; be marked by an empty line (i.e., just \r\n).&lt;/p&gt;

&lt;p&gt;This is mandated by &lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#section-2.2" rel="noopener noreferrer"&gt;RFC 9112 §2.2&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A request message containing a non-empty header section MUST include at least one blank line (CRLF) separating the header fields from the body.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In manual testing tools like Telnet or PuTTY, forgetting this blank line will cause the server to hang — it’s still waiting for the end of the headers.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Optional Body
&lt;/h4&gt;

&lt;p&gt;This request has no body — and that’s perfectly valid. In fact, bodies are uncommon for GET requests.&lt;/p&gt;

&lt;p&gt;As explained in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-get" rel="noopener noreferrer"&gt;RFC 9110 §9.3.1&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Content received in a GET request has no generally defined semantics, cannot alter the meaning or target of the request, and might lead some implementations to reject the request and close the connection…”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In contrast, POST, PUT, and PATCH requests often include bodies — which we’ll explore later in this article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Checkpoint
&lt;/h4&gt;

&lt;p&gt;This tiny two-line message:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is fully RFC-compliant.&lt;/li&gt;
&lt;li&gt;Works in practice with most HTTP servers.&lt;/li&gt;
&lt;li&gt;Serves as the perfect foundation for understanding and manually crafting HTTP requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next, we’ll enrich this structure with real-world headers like&lt;/strong&gt;  &lt;strong&gt;User-Agent and&lt;/strong&gt;  &lt;strong&gt;Accept, and see how they affect server behavior.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Real-World Headers
&lt;/h3&gt;

&lt;p&gt;The minimal request we discussed earlier — consisting of a GET line and a Host header — is technically valid and sufficient to elicit a server response. But in practice, most HTTP clients send additional headers that provide &lt;strong&gt;important context&lt;/strong&gt; to the server: who the client is, what kind of content it prefers, and how the connection should behave.&lt;/p&gt;

&lt;p&gt;Let’s look at a more realistic example of a request generated by a typical command-line HTTP client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET / HTTP/1.1
Host: example.com
User-Agent: curl/8.5.0
Accept: */*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these headers is defined in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110" rel="noopener noreferrer"&gt;RFC 9110&lt;/a&gt;, which governs HTTP semantics. While we’ll cover headers in depth in a dedicated future article, let’s walk through just enough to understand their presence and function in a typical request.&lt;/p&gt;

&lt;h4&gt;
  
  
  User-Agent: Identifying the Client
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-Agent: curl/8.5.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The User-Agent header identifies the software making the request — typically a browser, mobile app, or command-line tool.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-user-agent" rel="noopener noreferrer"&gt;RFC 9110 §10.1.5&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A user agent &lt;strong&gt;SHOULD&lt;/strong&gt; send a User-Agent header field in each request.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In IETF language, &lt;strong&gt;SHOULD&lt;/strong&gt; (as defined in RFC 2119) means this is a &lt;strong&gt;recommended&lt;/strong&gt; but not strictly required behavior. That’s why our earlier minimal example — which omitted User-Agent entirely — still worked. A compliant HTTP/1.1 server &lt;strong&gt;must not&lt;/strong&gt; reject a request just because this header is missing.&lt;/p&gt;

&lt;p&gt;However, in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Servers use User-Agent for analytics, feature detection, content negotiation, or filtering.&lt;/li&gt;
&lt;li&gt;Many web apps serve different versions of a site based on it.&lt;/li&gt;
&lt;li&gt;It’s one of the most spoofed headers on the Internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Including it is common, but not mandatory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Accept: Declaring Content Preferences
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Accept: */*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Accept header tells the server which media types the client is willing to handle in the response.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-accept" rel="noopener noreferrer"&gt;RFC 9110 §12.5.1&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The “Accept” header field can be used by user agents to specify their preferences regarding response media types.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This example (*/*) means “I’ll accept any content type,” which is the default behavior for curl unless overridden. More specific values might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;text/html — for browsers expecting HTML&lt;/li&gt;
&lt;li&gt;application/json — for APIs&lt;/li&gt;
&lt;li&gt;image/webp,image/apng,*/* — a typical browser value with preference ordering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Accept header enables &lt;strong&gt;content negotiation&lt;/strong&gt; , allowing the server to select the best available representation of the resource.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other Common Headers (Mentioned, Not Expanded)
&lt;/h4&gt;

&lt;p&gt;While our example only includes two headers, real HTTP clients often send more. For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection: keep-alive — whether the connection should be reused (&lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#appendix-C.2.2" rel="noopener noreferrer"&gt;RFC 9112 Appendix-C.2.2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Accept-Encoding: gzip, deflate, br — what compression formats are supported (&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-accept-encoding" rel="noopener noreferrer"&gt;RFC 9110 §12.5.3&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Referer — the address of the referring page (&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-referer" rel="noopener noreferrer"&gt;RFC 9110 §10.1.3&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These will be explored in a dedicated deep dive.&lt;/p&gt;

&lt;h4&gt;
  
  
  Headers Are Extensible by Design
&lt;/h4&gt;

&lt;p&gt;It’s worth noting that HTTP headers are designed to be extensible.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-16.3" rel="noopener noreferrer"&gt;RFC 9110 §16.3&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“HTTP’s most widely used extensibility point is the definition of new header and trailer fields.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This allows clients and servers to evolve independently. New headers can be added without breaking existing implementations — a key feature of HTTP’s long-term viability.&lt;/p&gt;

&lt;h4&gt;
  
  
  Checkpoint
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;While only the Host header is strictly required in HTTP/1.1, most real-world requests include headers like User-Agent and Accept.&lt;/li&gt;
&lt;li&gt;These headers are not mandatory, but they are highly recommended — and expected by many servers and APIs.&lt;/li&gt;
&lt;li&gt;HTTP headers provide metadata that shapes the request-response cycle, enabling things like compression, negotiation, and identity.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;We’ll dedicate an upcoming article to HTTP request headers in depth — including classifications, security concerns, and practical usage patterns.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Next, let’s move beyond headers and look at requests that include a message body — essential for operations like form submissions and API updates.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Requests with a Body: POST and Beyond
&lt;/h3&gt;

&lt;p&gt;So far, we’ve examined GET requests, which retrieve resources without sending a message body. But many practical scenarios — logging in, submitting a form, or updating a record — require sending data &lt;strong&gt;to&lt;/strong&gt; the server. That’s where methods like POST come into play.&lt;/p&gt;

&lt;p&gt;Let’s look at a complete HTTP/1.1 request with a JSON payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /login HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 48

{"email":"user@example.com","password":"secret"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a valid and fully compliant request message. Let’s examine each part.&lt;/p&gt;

&lt;h4&gt;
  
  
  Request Method: POST
&lt;/h4&gt;

&lt;p&gt;Defined in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-post" rel="noopener noreferrer"&gt;RFC 9110 §9.3.3&lt;/a&gt;, the POST method tells the server to &lt;strong&gt;process the data included in the request body&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The POST method requests that the &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#target.resource" rel="noopener noreferrer"&gt;target resource&lt;/a&gt; process the representation enclosed in the request according to the resource’s own specific semantics.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Typical use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submitting forms&lt;/li&gt;
&lt;li&gt;Sending JSON to APIs&lt;/li&gt;
&lt;li&gt;Uploading files&lt;/li&gt;
&lt;li&gt;Executing custom commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;POST is &lt;strong&gt;not idempotent&lt;/strong&gt;  — repeating the same request may produce different results.&lt;/p&gt;

&lt;p&gt;Other body-supporting methods include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PUT — replaces an existing resource (&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-put" rel="noopener noreferrer"&gt;RFC §9.3.4&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;PATCH — partial updates (&lt;a href="https://datatracker.ietf.org/doc/html/rfc5789" rel="noopener noreferrer"&gt;RFC 5789&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;DELETE — removes a resource; body is allowed but not defined (&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-delete" rel="noopener noreferrer"&gt;RFC §9.3.5&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Content-Type: Declaring the Body Format
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Content-Type: application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This header specifies the &lt;strong&gt;media type&lt;/strong&gt; of the request body, allowing the server to interpret it correctly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The Content-Type header field indicates the media type of the associated representation.” — &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-8.3" rel="noopener noreferrer"&gt;RFC 9110 §8.3&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, the body is JSON. Other common types include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application/x-www-form-urlencoded — for HTML form submissions&lt;/li&gt;
&lt;li&gt;multipart/form-data — for file uploads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If omitted, the server might guess or reject the request, increasing the risk of failure or misinterpretation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Content-Length: Specifying the Body Size
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Content-Length: 48
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This header tells the server &lt;strong&gt;exactly how many bytes&lt;/strong&gt; to read from the message body.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A user agent that sends a request that contains a message body &lt;strong&gt;MUST&lt;/strong&gt; send either a valid &lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#body.content-length" rel="noopener noreferrer"&gt;Content-Length&lt;/a&gt; header field or use the chunked transfer coding.” — &lt;a href="https://datatracker.ietf.org/doc/html/rfc9112#section-6.3" rel="noopener noreferrer"&gt;RFC 9112 §6.3&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s validate the value. The body is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"email":"user@example.com","password":"secret"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly &lt;strong&gt;48 bytes&lt;/strong&gt; , calculated as follows (UTF-8, 1 byte per character):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;{ → 1&lt;/li&gt;
&lt;li&gt;"email" → 7&lt;/li&gt;
&lt;li&gt;: → 1&lt;/li&gt;
&lt;li&gt;"&lt;a href="mailto:user@example.com"&gt;user@example.com&lt;/a&gt;" → 18&lt;/li&gt;
&lt;li&gt;, → 1&lt;/li&gt;
&lt;li&gt;"password" → 10&lt;/li&gt;
&lt;li&gt;: → 1&lt;/li&gt;
&lt;li&gt;"secret" → 8&lt;/li&gt;
&lt;li&gt;} → 1
= &lt;strong&gt;48 bytes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the Content-Length is incorrect — even by one byte — the server might hang, truncate the body, or return a 400 Bad Request.&lt;/p&gt;

&lt;h4&gt;
  
  
  Message Body: Transmitting the Payload
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"email":"user@example.com","password":"secret"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bytes after the header section are the &lt;strong&gt;content&lt;/strong&gt; of the message — in this example, a JSON object with login credentials. HTTP treats that content as an opaque octet stream: it merely moves the bytes. How those bytes are interpreted is left to the application and is signalled by fields such as Content‑Type.&lt;/p&gt;

&lt;p&gt;(See &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-6.4" rel="noopener noreferrer"&gt;RFC 9110 § 6.4&lt;/a&gt; and &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-6.4.1" rel="noopener noreferrer"&gt;§ 6.4.1 “Content Semantics”&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can&lt;/strong&gt;  &lt;strong&gt;GET Have a Body?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Technically yes, but it’s discouraged.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Although request message framing is independent of the method used, content received in a GET request has no generally defined semantics” — &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#name-get" rel="noopener noreferrer"&gt;RFC 9110 §9.3.1&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While the protocol doesn’t prohibit it, using a body with GET is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-standard&lt;/li&gt;
&lt;li&gt;Poorly supported across implementations&lt;/li&gt;
&lt;li&gt;Likely to cause inconsistent behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use POST, PUT, or PATCH when sending data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Checkpoint
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request bodies are used with methods like POST, PUT, and PATCH to send data to the server.&lt;/li&gt;
&lt;li&gt;The body must be accompanied by a valid Content-Type and a correctly calculated Content-Length.&lt;/li&gt;
&lt;li&gt;HTTP does not define the semantics of the body — it merely delivers the bytes.&lt;/li&gt;
&lt;li&gt;GET requests may include a body, but its usage is undefined and widely discouraged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next, we’ll shift gears and construct real HTTP requests manually — using nothing but a terminal — to observe how servers behave when fed raw protocol input, one line at a time.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructing HTTP Requests Manually (curl and PuTTY with Wireshark)
&lt;/h3&gt;

&lt;p&gt;At this point, we understand the structure of HTTP requests, and we’ve dissected both header-only and body-carrying examples. Now it’s time to make it real.&lt;/p&gt;

&lt;p&gt;In this section, we’ll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Send actual HTTP requests&lt;/strong&gt; using curl and PuTTY&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capture the network traffic&lt;/strong&gt; using Wireshark&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze the raw bytes&lt;/strong&gt; being transmitted on the wire&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding HTTP isn’t complete until you’ve seen how the request looks &lt;strong&gt;from the network’s point of view&lt;/strong&gt;  — and verified that it aligns with your mental model.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Inspecting curl Requests with Wireshark
&lt;/h4&gt;

&lt;p&gt;curl is a trusted command-line HTTP client available on most systems. It allows us to craft and send HTTP requests in a reproducible and scriptable way.&lt;/p&gt;

&lt;p&gt;We’ll start with a basic request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v http://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What to Expect:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A GET / request using HTTP/1.1&lt;/li&gt;
&lt;li&gt;A Host header&lt;/li&gt;
&lt;li&gt;Typical default headers like User-Agent: curl/x.x.x and Accept: */*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Instructions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start Wireshark&lt;/strong&gt; and begin capturing on the active network interface (e.g., Ethernet or Wi-Fi).&lt;/li&gt;
&lt;li&gt;Open a terminal and run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v http://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fol7ijyuqpj93xk2kxc47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fol7ijyuqpj93xk2kxc47.png" alt="curl command that sends a GET request to http://example.com" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Wireshark, apply this display filter to isolate the traffic:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http &amp;amp;&amp;amp; ip.addr == 96.7.128.175
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Use the IP address shown in your terminal if different.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftry85eakgdb5oknvjewe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftry85eakgdb5oknvjewe.png" alt="Wireshark image that filters HTTP traffic" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inspect the request and response. Expand the “Hypertext Transfer Protocol” section in the Wireshark packet to view:
 — Method, path, and version
 — Headers (including Host, User-Agent, Accept)
 — The response from the server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw67943ubrpgywocadd4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw67943ubrpgywocadd4i.png" alt="Wireshark image shows the HTTP section" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Manually Typing Raw Requests in PuTTY (Raw Mode)
&lt;/h4&gt;

&lt;p&gt;To go even deeper, we’ll use &lt;strong&gt;PuTTY in Raw mode&lt;/strong&gt; to manually construct an HTTP request by typing it line by line — just as a client would send it over TCP.&lt;/p&gt;

&lt;p&gt;This approach demonstrates the true text-based nature of HTTP/1.1.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Security Warning: Only Download PuTTY from the Official Site&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are many fake or modified versions of PuTTY circulating online. Some are bundled with &lt;strong&gt;malware&lt;/strong&gt; , &lt;strong&gt;keyloggers&lt;/strong&gt; , or &lt;strong&gt;remote access trojans&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always download PuTTY &lt;strong&gt;only&lt;/strong&gt; from its official site:&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html" rel="noopener noreferrer"&gt;https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the original distribution maintained by its author, Simon Tatham. If you’re unsure, verify the SHA256 checksum of the executable before running it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preparing the Environment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start Wireshark&lt;/strong&gt; (if not already running) and begin capturing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Launch Terminal&lt;/strong&gt; to issue a ping request to get the ip address (easier to filter and follow than typing example.com)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58okopf4jij7ad7tijxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58okopf4jij7ad7tijxp.png" alt="Terminal image that shows a ping request to example.com" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Launch PuTTY&lt;/strong&gt; :
 — In the &lt;em&gt;Session&lt;/em&gt; panel, set &lt;strong&gt;Connection type&lt;/strong&gt; to Raw.
 — For &lt;strong&gt;Host Name&lt;/strong&gt; , enter: 23.192.228.80
 — For &lt;strong&gt;Port&lt;/strong&gt; , enter: 80&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez56y2rgjcpe4h27asrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez56y2rgjcpe4h27asrz.png" alt="PuTTY image that shows how to open a raw connection" width="800" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Open&lt;/strong&gt;. A terminal window appears. Now you’re connected directly to the server on TCP port 80 — but nothing has been sent yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw75eeqow4qp7kw3xp17a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw75eeqow4qp7kw3xp17a.png" alt="Wireshark image shows a TCP 3-way handshake" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manually Type the Request&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type the following &lt;strong&gt;exactly&lt;/strong&gt; (note the required blank line at the end):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET / HTTP/1.1
Host: example.com

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Hit Enter twice after the last line to signal the end of headers.)&lt;/p&gt;

&lt;p&gt;You should see the raw HTTP response come back — headers and HTML — directly in the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7y1jvncfdx5z2dq7eie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7y1jvncfdx5z2dq7eie.png" alt="PuTTY image showing a successful request" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyzing the Traffic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Wireshark:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter by destination IP:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip.addr == 23.192.228.80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Locate the TCP stream used by PuTTY.&lt;/li&gt;
&lt;li&gt;Follow the TCP stream (Right-click → Follow → TCP Stream).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F842j6tc5kzc5mkahfev9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F842j6tc5kzc5mkahfev9.png" alt="Wireshark image that shows how to open TCP Stream" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’ll see &lt;strong&gt;exactly&lt;/strong&gt; what you typed sent on the wire, and what came back from the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgwr3dh4idregn3bf8gm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgwr3dh4idregn3bf8gm.png" alt="Wireshark image that shows a TCP Stream" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This reinforces the core principle of HTTP/1.1: everything — request line, headers, even the blank line — is transmitted as plain ASCII over TCP.&lt;/p&gt;

&lt;h4&gt;
  
  
  Checkpoint
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Tools like curl send complete, standards-compliant requests automatically.&lt;/li&gt;
&lt;li&gt;With PuTTY, you handcraft the entire HTTP message — seeing exactly what the server sees.&lt;/li&gt;
&lt;li&gt;Wireshark validates every byte, confirming your understanding of how HTTP works at the network level.&lt;/li&gt;
&lt;li&gt;Always be cautious with tool downloads — especially security-sensitive software like PuTTY.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In the next section, we’ll wrap up and preview what’s coming in Part 3 — a deep dive into HTTP request headers — exploring how they’re classified, what they control, and how to use them effectively. After that, we’ll focus exclusively on HTTP request bodies and payload formats used in modern web APIs and applications.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap-up
&lt;/h3&gt;

&lt;p&gt;In this article, we dissected the structure of an HTTP request — not just theoretically, but line by line, byte by byte, and across real network traffic.&lt;/p&gt;

&lt;p&gt;We began with the &lt;strong&gt;minimal valid request&lt;/strong&gt; , explained each required component according to IETF standards, and gradually layered in real-world headers like User-Agent and Accept. We explored the anatomy of a request with a &lt;strong&gt;message body&lt;/strong&gt; , understanding how Content-Type and Content-Length govern payload semantics and integrity.&lt;/p&gt;

&lt;p&gt;Finally, we moved from concept to execution — crafting and observing real HTTP requests using curl, &lt;strong&gt;manually typing them in PuTTY&lt;/strong&gt; , and validating the results in Wireshark. We treated HTTP not as an abstraction, but as a protocol we can reason about, inspect, and master.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If Part 1 showed you how a request travels across the Internet, Part 2 showed you &lt;strong&gt;what that request actually contains&lt;/strong&gt;  — and why every line matters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What’s Next
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;Part 3&lt;/strong&gt; , we’ll zoom into a critical component of every request: the  &lt;strong&gt;headers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We’ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How headers are classified (general, request-specific, entity, and extension)&lt;/li&gt;
&lt;li&gt;Header parsing and duplication rules&lt;/li&gt;
&lt;li&gt;Case sensitivity and normalization&lt;/li&gt;
&lt;li&gt;Real-world usage, abuse, and security implications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following that, we’ll explore &lt;strong&gt;HTTP request bodies and payload semantics&lt;/strong&gt; in depth — including application/json, form encodings, and multipart payloads — with practical examples and pitfalls.&lt;/p&gt;

&lt;p&gt;This series is about building lasting, protocol-level understanding — and we’re just getting started.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>networking</category>
      <category>backenddevelopment</category>
      <category>techleadership</category>
    </item>
    <item>
      <title>Demystifying HTTP for Web Developers — Part 1</title>
      <dc:creator>Hasan Safwan</dc:creator>
      <pubDate>Fri, 02 May 2025 13:33:14 +0000</pubDate>
      <link>https://dev.to/hasansafwan/demystifying-http-for-web-developers-part-1-3269</link>
      <guid>https://dev.to/hasansafwan/demystifying-http-for-web-developers-part-1-3269</guid>
      <description>&lt;h4&gt;
  
  
  What is HTTP and How a Request Travels Across the Web
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jq13re1mz7hi99obzv6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jq13re1mz7hi99obzv6.webp" alt="Illustration of a developer opening a glowing box labeled 'HTTP', revealing HTTP concepts like GET, POST, Cache-Control, and Content-Type – representing the idea of demystifying HTTP" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Published&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 1&lt;/strong&gt; – &lt;em&gt;What Is HTTP and How a Request Travels Across the Web&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 2&lt;/strong&gt; - &lt;a href="https://dev.to/hasansafwan/dissecting-the-http-request-line-by-line-39cn"&gt;&lt;em&gt;Dissecting the HTTP Request — Line by Line&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 3&lt;/strong&gt; – &lt;a href="https://dev.to/hasansafwan/understanding-http-request-headers-classification-behavior-and-how-servers-react-h71"&gt;&lt;em&gt;Understanding HTTP Request Headers: Classification, Behavior, and How Servers React&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In Progress&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 4&lt;/strong&gt; – &lt;em&gt;Exploring the HTTP Request Body: Payloads, Semantics, and Real-World Pitfalls&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 5&lt;/strong&gt; – &lt;em&gt;Dissecting the HTTP Response — Line by Line&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 6&lt;/strong&gt; – &lt;em&gt;Understanding HTTP Response Headers: Caching, Security, and Behavior in Practice&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 7&lt;/strong&gt; – &lt;em&gt;Exploring the HTTP Response Body: Streaming, Compression, and Delivery Semantics&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Planned Advanced Topics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;How HTTP Keep-Alive Really Works: Persistent Connections and Latency&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;From Redirects to Chains: Understanding HTTP Redirection in Depth&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Demystifying HTTPS: TLS, Certificates, and the Encrypted HTTP Layer&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Understanding HTTP Authentication: Basic, Bearer, and Beyond&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The Hidden Risks of HTTP Headers: Leaks, Injection, and Misuse&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Chunked Transfer Encoding: Streaming HTTP with Precision&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP Compression Demystified: gzip, br, and Content-Encoding&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP/1.1 vs HTTP/2 vs HTTP/3: A Practical Developer’s Comparison&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;What Every Developer Should Know About Reverse Proxies and HTTP&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Understanding HTTP Matters
&lt;/h3&gt;

&lt;p&gt;HTTP is the foundation of everything we build and interact with on the web — whether it’s a static website, a complex Single Page Application (SPA), a RESTful API, or a modern mobile app.&lt;/p&gt;

&lt;p&gt;Every user action that triggers data exchange — from submitting a login form to loading an image — ultimately depends on HTTP.&lt;/p&gt;

&lt;p&gt;Despite this, many developers treat HTTP as a black box: something that “just works” behind the scenes. While abstraction is useful, serious web developers must move beyond it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding how HTTP actually operates — from how requests are structured, to how connections are established, to how responses are transmitted — is essential for building high-quality, secure, and performant applications.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A deep knowledge of HTTP enables developers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design better client-server interactions.&lt;/li&gt;
&lt;li&gt;Optimize application performance at the protocol level.&lt;/li&gt;
&lt;li&gt;Troubleshoot complex network bugs confidently.&lt;/li&gt;
&lt;li&gt;Understand and prevent vulnerabilities like man-in-the-middle attacks.&lt;/li&gt;
&lt;li&gt;Make better architectural decisions, especially around APIs, authentication flows, caching, and content delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this series, &lt;em&gt;Demystifying HTTP for Web Developers&lt;/em&gt;, we’ll go beyond theory —  &lt;strong&gt;proving every concept through real-world observation&lt;/strong&gt; using tools like Chrome DevTools and Wireshark.&lt;/p&gt;

&lt;p&gt;We will anchor each explanation to the true technical foundations — official RFC standards — ensuring you’re learning real, industry-grade knowledge, not approximations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this first part, we’ll start from the very beginning:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a protocol, really?&lt;/li&gt;
&lt;li&gt;Who defines the rules for Internet communication?&lt;/li&gt;
&lt;li&gt;How is HTTP structured, and where does it fit in the larger networking architecture?&lt;/li&gt;
&lt;li&gt;What happens when you issue a simple HTTP request, from typing a URL to receiving a response?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you’ll not only understand HTTP better — you’ll have a precise mental model of how data travels across the Internet, and you’ll see it all in action through real-world inspection.&lt;/p&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Protocol?
&lt;/h3&gt;

&lt;p&gt;Before we can understand HTTP, we must first understand a more fundamental concept: &lt;strong&gt;What exactly is a protocol in networking?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A protocol is a formal set of rules that define how two or more systems communicate and exchange information over a network.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These rules cover critical aspects such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How a communication session is initiated.&lt;/li&gt;
&lt;li&gt;How data is structured and formatted.&lt;/li&gt;
&lt;li&gt;How each side acknowledges receipt of data.&lt;/li&gt;
&lt;li&gt;How errors are detected and handled.&lt;/li&gt;
&lt;li&gt;When and how communication sessions are terminated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, a protocol is like a language — but more strict, complete with grammar, sequence, and expectations. Two systems can successfully communicate only if they both strictly follow the same protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Analogy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine two people — one speaks only German, the other only Japanese. Without a shared language, communication would fail. Similarly, computers and applications must share a common protocol to exchange meaningful data.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Protocols in Networking&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Many protocols exist, each serving a specific role. For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy20gssqpv32d0x8dk8b4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy20gssqpv32d0x8dk8b4.png" alt="Table listing protocols and their purposes: TCP ensures reliable delivery, IP routes packets, TLS encrypts and authenticates, and HTTP defines message exchange between clients and servers" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each protocol operates at a specific &lt;strong&gt;layer&lt;/strong&gt; of the networking architecture, building on the services of the protocols below it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzl1nq1tul0iiuv1fu2oz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzl1nq1tul0iiuv1fu2oz.png" alt="Diagram of the networking stack: Application Layer (HTTP) on top, followed by Transport Layer (TCP or QUIC), Internet Layer (IP), and Link Layer (Ethernet/WiFi)" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each protocol operates at a different layer to achieve seamless communication.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Traditional HTTP (HTTP/1.1, HTTP/2) relies on TCP to deliver its messages.&lt;br&gt;&lt;br&gt;
Newer HTTP versions (HTTP/3) operate over QUIC, a protocol built on top of UDP.&lt;/p&gt;
&lt;h4&gt;
  
  
  Why Protocols Matter
&lt;/h4&gt;

&lt;p&gt;Without strict adherence to protocols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browsers wouldn’t understand web servers.&lt;/li&gt;
&lt;li&gt;Emails couldn’t be reliably sent.&lt;/li&gt;
&lt;li&gt;Secure transactions wouldn’t be possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Protocols ensure that systems developed by different organizations — across different devices, operating systems, and networks — can interoperate reliably.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the case of HTTP, understanding its protocol rules allows developers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correctly interpret how web communication works.&lt;/li&gt;
&lt;li&gt;Spot and fix performance bottlenecks.&lt;/li&gt;
&lt;li&gt;Diagnose unexpected network errors.&lt;/li&gt;
&lt;li&gt;Build standards-compliant clients and servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next, let’s explore who actually defines these protocols — and how Internet standards like HTTP are created and maintained.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Who Defines Protocols — and What is an RFC?
&lt;/h3&gt;

&lt;p&gt;Now that we understand protocols are essential for communication, the next question is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who creates these protocols?&lt;br&gt;&lt;br&gt;
And how are they standardized across the entire Internet?&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Key Organizations Behind Internet Standards
&lt;/h4&gt;

&lt;p&gt;Two major organizations are responsible for developing and maintaining the technical standards that power the Internet and the Web:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3t1ovahhpwpcy4x2qyy8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3t1ovahhpwpcy4x2qyy8.png" alt="Table listing two web standard organizations: IETF defines core Internet protocols like TCP, IP, and HTTP; W3C develops web technologies like HTML, CSS, and parts of web application architecture" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furc0des1s5a6zabij367.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furc0des1s5a6zabij367.png" alt="Diagram showing the relationship between IETF and W3C: IETF defines protocols like TCP/IP or HTTP, which flow into W3C standards like HTML, CSS, and Web APIs" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;IETF defines communication standards; W3C defines web application standards.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  The IETF — Shaping the Internet’s Communication
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Internet Engineering Task Force (IETF)&lt;/strong&gt; is the primary body that defines how systems on the Internet communicate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is an open standards organization — meaning engineers, researchers, and practitioners worldwide can contribute.&lt;/li&gt;
&lt;li&gt;Its work is organized into specialized &lt;strong&gt;Working Groups&lt;/strong&gt; , such as the HTTP Working Group, Security Groups, and Transport Groups.&lt;/li&gt;
&lt;li&gt;The goal of the IETF is &lt;strong&gt;not to control&lt;/strong&gt; the Internet, but to &lt;strong&gt;guide its growth based on technical merit and consensus&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mission Statement:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The mission of the IETF is to make the Internet work better by producing high-quality, relevant technical documents that influence the way people design, use, and manage the Internet.” — &lt;a href="https://datatracker.ietf.org/doc/html/rfc3935#section-1" rel="noopener noreferrer"&gt;IETF Mission Statement&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  The W3C — Standardizing the Web
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;World Wide Web Consortium (W3C)&lt;/strong&gt; focuses specifically on the &lt;strong&gt;technologies of the Web&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It develops standards like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;DOM specifications&lt;/li&gt;
&lt;li&gt;Web accessibility standards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The W3C’s mission is to ensure the Web remains &lt;strong&gt;accessible, interoperable, and evolves&lt;/strong&gt; as technologies change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IETF&lt;/strong&gt; → Defines protocols that move data across networks (HTTP, TCP, TLS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W3C&lt;/strong&gt; → Defines how web pages and applications are structured and behave (HTML, CSS).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Early versions of HTTP (HTTP/1.0 and HTTP/1.1) were co-developed by both the W3C and the IETF. Today, the &lt;strong&gt;IETF’s HTTP Working Group&lt;/strong&gt; is the main authority on HTTP specifications.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is an RFC?
&lt;/h3&gt;

&lt;p&gt;You’ve likely seen references to “RFCs” in technical documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RFC&lt;/strong&gt; stands for &lt;strong&gt;Request for Comments&lt;/strong&gt;  — but despite the casual name, an RFC is a &lt;strong&gt;formal, peer-reviewed, and highly authoritative document&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;RFCs define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protocol specifications (e.g., TCP, IP, HTTP)&lt;/li&gt;
&lt;li&gt;Best Current Practices (BCPs)&lt;/li&gt;
&lt;li&gt;Architectural guidelines&lt;/li&gt;
&lt;li&gt;Research and experimental proposals&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Key Facts About RFCs:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;RFCs are &lt;strong&gt;sequentially numbered documents&lt;/strong&gt; , starting from &lt;strong&gt;RFC 1&lt;/strong&gt; (published in 1969).&lt;/li&gt;
&lt;li&gt;Some RFCs define &lt;strong&gt;official Internet standards&lt;/strong&gt; , while others share research or best practices.&lt;/li&gt;
&lt;li&gt;RFCs are managed by the &lt;strong&gt;RFC Editor&lt;/strong&gt; , operating under the guidance of the IETF and related organizations.&lt;/li&gt;
&lt;li&gt;They are &lt;strong&gt;freely available&lt;/strong&gt; and intended to be &lt;strong&gt;stable, citable references&lt;/strong&gt; for engineers worldwide.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  RFCs Relevant to HTTP
&lt;/h4&gt;

&lt;p&gt;When this series refers to how HTTP works, it anchors explanations in &lt;strong&gt;the actual RFCs&lt;/strong&gt;  — not vague approximations.&lt;/p&gt;

&lt;p&gt;Some important RFCs for modern HTTP:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufd27xf8i5jpq0h05qtl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufd27xf8i5jpq0h05qtl.png" alt="Table listing RFCs and their purposes: RFC 9110 defines HTTP semantics; RFC 9112 defines HTTP/1.1 format; RFC 9113 defines HTTP/2; RFC 9114 defines HTTP/3 over QUIC" width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Protocols ensure reliable communication across the Internet.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;IETF&lt;/strong&gt; and &lt;strong&gt;W3C&lt;/strong&gt; are the primary organizations maintaining Internet and Web standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RFCs&lt;/strong&gt; are formal, peer-reviewed documents defining protocols like HTTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next, let’s see exactly where HTTP fits inside the Internet’s layered architecture — and how different protocols build on each other to make web communication possible.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Networking Layers — Where HTTP Fits
&lt;/h3&gt;

&lt;p&gt;Developers often hear that HTTP is an “Application Layer” protocol — but what does that really mean?&lt;/p&gt;

&lt;p&gt;To fully understand HTTP’s role, we must explore the &lt;strong&gt;layered architecture&lt;/strong&gt; of Internet communication — a fundamental concept that powers everything from simple web pages to massive cloud systems.&lt;/p&gt;
&lt;h4&gt;
  
  
  The Layered Architecture of Network Communication
&lt;/h4&gt;

&lt;p&gt;Internet communication is organized into &lt;strong&gt;layers&lt;/strong&gt; , each responsible for a specific set of tasks.&lt;/p&gt;

&lt;p&gt;Each layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provides services to the layer above it&lt;/strong&gt; (e.g., reliable delivery).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relies on services from the layer below it&lt;/strong&gt; (e.g., packet routing).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This modular design makes the Internet &lt;strong&gt;scalable, interoperable, and resilient&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Two models explain these layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4oss2auqd8tdrmd4mx4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4oss2auqd8tdrmd4mx4r.png" alt="Table comparing models: TCP/IP Model is the practical architecture of the real-world Internet; OSI Model is a more detailed theoretical model used for teaching and understanding" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In practice, the TCP/IP model is what truly matters for web development.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  The TCP/IP Networking Model
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;TCP/IP model&lt;/strong&gt; organizes communication into the following four layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nkf8xm7ggnzlfzvymx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nkf8xm7ggnzlfzvymx0.png" alt="Table showing networking layers with responsibilities and example protocols: Application Layer handles software communication (e.g., HTTP, SMTP); Transport Layer ensures data transfer (e.g., TCP, UDP); Internet Layer routes data (e.g., IP); Link Layer manages hardware connections (e.g., Ethernet, Wi-Fi)" width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9op4c39s1luuqe61f241.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9op4c39s1luuqe61f241.png" alt="Stack diagram showing protocol layers from top to bottom: HTTP, TCP or QUIC, IP, and Ethernet/Wi-Fi" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;HTTP relies on lower layers like TCP and IP to successfully transmit messages over the network.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Where HTTP Fits in the Stack
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;HTTP operates at the Application Layer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It defines &lt;strong&gt;how web clients (browsers, apps) and servers (APIs, web servers)&lt;/strong&gt; communicate by sending structured requests and responses.&lt;/p&gt;

&lt;p&gt;However, HTTP &lt;strong&gt;depends on lower layers&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cbr02cb9m5wmiavyzmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cbr02cb9m5wmiavyzmm.png" alt="Table showing networking layers and their roles in HTTP communication: Transport Layer (TCP/QUIC) ensures reliable or optimized delivery; Internet Layer (IP) routes packets; Link Layer (Ethernet/Wi-Fi) handles physical transmission" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HTTP itself does &lt;em&gt;not&lt;/em&gt; handle packet delivery, error correction, retransmissions, or routing. Those tasks are delegated to TCP, QUIC, and IP beneath it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This layered separation allows each protocol to &lt;strong&gt;specialize and evolve independently&lt;/strong&gt; , leading to faster innovation and better overall Internet performance.&lt;/p&gt;
&lt;h3&gt;
  
  
  What About the OSI Model?
&lt;/h3&gt;

&lt;p&gt;You might have also heard of the &lt;strong&gt;OSI Model&lt;/strong&gt;  — the “7-layer model” taught in networking classes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Application&lt;/li&gt;
&lt;li&gt;Presentation&lt;/li&gt;
&lt;li&gt;Session&lt;/li&gt;
&lt;li&gt;Transport&lt;/li&gt;
&lt;li&gt;Network&lt;/li&gt;
&lt;li&gt;Data Link&lt;/li&gt;
&lt;li&gt;Physical&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While it’s great for conceptual understanding, &lt;strong&gt;the Internet in practice follows the simpler TCP/IP model.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For developers, thinking in terms of TCP/IP — Application, Transport, Internet, Link — is &lt;strong&gt;more practical and accurate&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Network communication is organized into structured layers.&lt;/li&gt;
&lt;li&gt;HTTP operates at the &lt;strong&gt;Application Layer&lt;/strong&gt; , defining the structure of client-server communication.&lt;/li&gt;
&lt;li&gt;HTTP &lt;strong&gt;relies on Transport (TCP/QUIC)&lt;/strong&gt;, &lt;strong&gt;Internet (IP)&lt;/strong&gt;, and &lt;strong&gt;Link Layer (Ethernet/Wi-Fi)&lt;/strong&gt; protocols to deliver messages across networks.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;TCP/IP model&lt;/strong&gt; is the real-world architecture of the Internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next, let’s dive deeper into HTTP itself: what it is, why it matters, and how its design choices like statelessness shape web development.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Deep Dive — What is HTTP?
&lt;/h3&gt;

&lt;p&gt;Now that we understand protocols and where HTTP fits in the networking architecture, let’s focus specifically on &lt;strong&gt;HTTP itself&lt;/strong&gt;  — the protocol that powers almost everything we do on the Web.&lt;/p&gt;
&lt;h3&gt;
  
  
  Definition and Purpose
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;HTTP&lt;/strong&gt; stands for &lt;strong&gt;HyperText Transfer Protocol&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Originally designed to transfer hypertext documents (documents containing links to other documents), HTTP today is used for a wide variety of content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML pages&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Video streams&lt;/li&gt;
&lt;li&gt;API calls (JSON, XML, etc.)&lt;/li&gt;
&lt;li&gt;WebSockets negotiation&lt;/li&gt;
&lt;li&gt;And more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;HTTP governs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How a client formulates a request.&lt;/li&gt;
&lt;li&gt;How a server formulates a response.&lt;/li&gt;
&lt;li&gt;How metadata (content types, encodings, caching instructions) is exchanged.&lt;/li&gt;
&lt;li&gt;How errors and status information are communicated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;current formal definition&lt;/strong&gt; of HTTP semantics is found in &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110" rel="noopener noreferrer"&gt;&lt;strong&gt;RFC 9110&lt;/strong&gt;&lt;/a&gt;, which standardizes HTTP across &lt;strong&gt;HTTP/1.1&lt;/strong&gt; , &lt;strong&gt;HTTP/2&lt;/strong&gt; , and  &lt;strong&gt;HTTP/3&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Core Characteristics of HTTP
&lt;/h3&gt;

&lt;p&gt;HTTP has several key design principles that profoundly influence how the web behaves:&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Statelessness
&lt;/h4&gt;

&lt;p&gt;HTTP is inherently &lt;strong&gt;stateless&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each HTTP request is independent.&lt;br&gt;&lt;br&gt;
The protocol itself does not retain any memory of previous requests or interactions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;The server treats every request as isolated.&lt;/li&gt;
&lt;li&gt;If persistent state is needed (e.g., user login sessions), it must be implemented at the &lt;strong&gt;application layer&lt;/strong&gt; using mechanisms like:
 — Cookies
 — Authentication tokens
 — Server-side sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc9110#section-3.3" rel="noopener noreferrer"&gt;&lt;strong&gt;RFC 9110 §3.3&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;“HTTP is defined as a stateless protocol, meaning that each request message’s semantics can be understood in isolation…”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  2. Client-Server Architecture
&lt;/h4&gt;

&lt;p&gt;HTTP clearly defines roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt; : Initiates requests (browsers, mobile apps, API consumers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt; : Listens for requests and sends back structured responses (web servers, APIs).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server &lt;strong&gt;does not&lt;/strong&gt; initiate communication — the client drives the entire interaction.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Textual and Extensible
&lt;/h4&gt;

&lt;p&gt;HTTP messages (at least in HTTP/1.x) are primarily &lt;strong&gt;text-based&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy for humans to read and debug.&lt;/li&gt;
&lt;li&gt;Easy to extend — new headers, new methods, and new status codes can be introduced without breaking older clients or servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though &lt;strong&gt;HTTP/2&lt;/strong&gt; and &lt;strong&gt;HTTP/3&lt;/strong&gt; use &lt;strong&gt;binary framing&lt;/strong&gt; for better performance, the &lt;strong&gt;underlying HTTP semantics remain text-based&lt;/strong&gt; according to RFC 9110.&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Flexible Transport Layer
&lt;/h4&gt;

&lt;p&gt;Traditionally, HTTP relies on &lt;strong&gt;TCP&lt;/strong&gt; as its transport protocol (for reliable, ordered delivery).&lt;/p&gt;

&lt;p&gt;However, starting with &lt;strong&gt;HTTP/3&lt;/strong&gt; , HTTP now runs over &lt;strong&gt;QUIC&lt;/strong&gt; , a modern protocol built on &lt;strong&gt;UDP&lt;/strong&gt; that offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster connection establishment&lt;/li&gt;
&lt;li&gt;Better handling of packet loss&lt;/li&gt;
&lt;li&gt;Improved performance under poor network conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Point:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Regardless of whether HTTP uses TCP or QUIC, its logical structure of &lt;strong&gt;requests and responses stays the same&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Fundamental Components of HTTP Communication
&lt;/h3&gt;

&lt;p&gt;When a client sends an HTTP request and a server responds, several key components are involved:&lt;/p&gt;
&lt;h4&gt;
  
  
  HTTP Request
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt; : Specifies the desired action.
 — Examples: GET, POST, PUT, DELETE, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt; : Metadata about the request.
 — Examples: Content-Type, Authorization, Accept, User-Agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional Body&lt;/strong&gt; : Payload data (for methods like POST, PUT, PATCH).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  HTTP Response
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status Code&lt;/strong&gt; : Numeric code indicating the result.
 — Examples: 200 OK, 404 Not Found, 500 Internal Server Error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt; : Metadata about the response.
 — Examples: Content-Type, Cache-Control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional Body&lt;/strong&gt; : The returned data (HTML document, JSON data, file, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r3r85anibggpof3drf6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r3r85anibggpof3drf6.png" alt="Diagram showing structure of an HTTP request and response pair" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Every HTTP interaction consists of a structured request and a structured response.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Evolution of HTTP Versions
&lt;/h3&gt;

&lt;p&gt;HTTP has evolved over time to meet the growing demands of modern applications:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgrveo8yh6clezs3rbnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgrveo8yh6clezs3rbnn.png" alt="Table comparing features across HTTP/1.1, HTTP/2, and HTTP/3" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, modern browsers and servers automatically &lt;strong&gt;negotiate the best HTTP version&lt;/strong&gt; they both support — typically via the ALPN (Application-Layer Protocol Negotiation) extension during the TLS handshake.&lt;/p&gt;
&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;HTTP is a &lt;strong&gt;stateless, application-layer protocol&lt;/strong&gt; governing client-server communication.&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;extensible&lt;/strong&gt; and &lt;strong&gt;independent of the underlying transport&lt;/strong&gt; (TCP or QUIC).&lt;/li&gt;
&lt;li&gt;HTTP interactions are structured as &lt;strong&gt;requests&lt;/strong&gt; and &lt;strong&gt;responses&lt;/strong&gt; , with clearly defined methods, headers, status codes, and optional bodies.&lt;/li&gt;
&lt;li&gt;Modern HTTP evolves across versions, improving performance while preserving core semantics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Now that we know what HTTP is, let’s walk through the full journey of an HTTP request — from typing a URL to receiving a server response.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How an HTTP Request Travels Across the Internet
&lt;/h3&gt;

&lt;p&gt;Understanding HTTP isn’t complete without seeing the &lt;strong&gt;full journey of a request&lt;/strong&gt;  — from the moment a user types a URL, to the server processing the request, and back to the browser rendering the response.&lt;/p&gt;

&lt;p&gt;Each step involves &lt;strong&gt;multiple protocols&lt;/strong&gt; , &lt;strong&gt;different network layers&lt;/strong&gt; , and &lt;strong&gt;important optimizations&lt;/strong&gt; working together seamlessly.&lt;/p&gt;

&lt;p&gt;Let’s walk through the complete process.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1: DNS Resolution
&lt;/h4&gt;

&lt;p&gt;Before any HTTP request can be sent, the client needs the server’s IP address.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a user types a URL like &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt; into the browser, the browser first checks:
 — Browser DNS cache
 — OS DNS cache&lt;/li&gt;
&lt;li&gt;If the IP address isn’t already cached, the client sends a &lt;strong&gt;DNS query&lt;/strong&gt; (usually over UDP) to a DNS resolver.&lt;/li&gt;
&lt;li&gt;The resolver returns the IP address (e.g., 93.184.216.34).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Without DNS resolution, the browser would have no way to find the server.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Establishing a Connection
&lt;/h4&gt;

&lt;p&gt;Once the client knows the server’s IP address, it must &lt;strong&gt;establish a transport connection&lt;/strong&gt;. Depending on the HTTP version:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For HTTP/1.1 and HTTP/2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;TCP connection&lt;/strong&gt; is established using a &lt;strong&gt;three-way handshake&lt;/strong&gt; :&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduhlwlh7os0frirnnqa7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduhlwlh7os0frirnnqa7.png" alt="Diagram illustrating TCP three-way handshake steps: SYN, SYN-ACK, ACK" width="740" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only after the TCP handshake is complete can data be sent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For HTTPS (secure HTTP):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After TCP, a &lt;strong&gt;TLS handshake&lt;/strong&gt; happens:
 — Negotiates encryption parameters (e.g., cipher suites).
 — Authenticates the server identity via digital certificates.
 — Establishes a secure, encrypted communication channel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HTTPS ensures confidentiality, integrity, and authenticity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For HTTP/3 (over QUIC and UDP):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No TCP handshake is needed.&lt;/li&gt;
&lt;li&gt;QUIC (which runs over UDP) &lt;strong&gt;combines connection setup and encryption&lt;/strong&gt; into a single step.&lt;/li&gt;
&lt;li&gt;This reduces latency and improves performance, especially over unreliable networks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;QUIC is one of the major innovations of HTTP/3.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3: Sending the HTTP Request
&lt;/h4&gt;

&lt;p&gt;With a connection established (TCP/TLS or QUIC), the client sends the actual &lt;strong&gt;HTTP request&lt;/strong&gt;. A typical HTTP request contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt; : e.g., GET, POST&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path&lt;/strong&gt; : e.g., /index.html&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt; : e.g., Host, User-Agent, Accept&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional Body&lt;/strong&gt; : for methods like POST, PUT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example of a simple HTTP/1.1 request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: text/html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the HTTP semantics defined in RFC 9110 come fully into play.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Server Processing and Response
&lt;/h4&gt;

&lt;p&gt;Upon receiving the request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server processes it (maybe involving database queries, cache lookups, internal logic).&lt;/li&gt;
&lt;li&gt;The server formulates an HTTP response:
 —  &lt;strong&gt;Status code&lt;/strong&gt; (e.g., 200 OK, 404 Not Found).
 —  &lt;strong&gt;Response headers&lt;/strong&gt; (e.g., Content-Type: text/html).
— &lt;strong&gt;Optional body&lt;/strong&gt; (e.g., HTML page, JSON API response).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example of a simple HTTP/1.1 response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1234

&amp;lt;html&amp;gt;...&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server sends this response back over the established transport connection.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5: Browser Processes the Response
&lt;/h4&gt;

&lt;p&gt;Once the browser receives the response:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It reads the &lt;strong&gt;status code&lt;/strong&gt; and  &lt;strong&gt;headers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;renders&lt;/strong&gt; content (for HTML documents) or &lt;strong&gt;processes&lt;/strong&gt; API data (for JSON responses).&lt;/li&gt;
&lt;li&gt;It may issue &lt;strong&gt;additional HTTP requests&lt;/strong&gt; to load assets like:
 — Images
 — CSS files
 — JavaScript files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These subsequent requests create a &lt;strong&gt;cascade of network activity&lt;/strong&gt;  — visible in the browser’s Developer Tools Network tab.&lt;/p&gt;

&lt;p&gt;This is how full web pages are progressively loaded and rendered.&lt;/p&gt;

&lt;h4&gt;
  
  
  Visual Summary of the Journey
&lt;/h4&gt;

&lt;p&gt;The typical sequence of an HTTP request looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feip1gznqlrndo8psh9bm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feip1gznqlrndo8psh9bm.png" alt="End-to-end diagram showing full HTTP request lifecycle across layers and protocols" width="784" height="635"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Multiple protocols work together to deliver a single web page request.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Important Performance Observations
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DNS Resolution latency&lt;/strong&gt; can slow down page loads if DNS is slow or not cached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP/TLS Handshakes&lt;/strong&gt; introduce round-trip delays before the first byte is sent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/2 and HTTP/3&lt;/strong&gt; optimize performance by:
 — Reducing connection overhead.
 — Allowing multiple parallel streams.
 — Mitigating head-of-line blocking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these phases is crucial for diagnosing slow websites and network issues.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Before any HTTP request, the browser resolves the server’s IP address via DNS.&lt;/li&gt;
&lt;li&gt;A transport connection (TCP/TLS or QUIC) must be established first.&lt;/li&gt;
&lt;li&gt;The browser sends an HTTP request, and the server returns a structured HTTP response.&lt;/li&gt;
&lt;li&gt;Modern browsers handle dozens (sometimes hundreds) of HTTP requests per page load, optimizing for speed and efficiency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Now that we understand the full journey, let’s observe it hands-on using Chrome DevTools and Wireshark — validating each step of the HTTP lifecycle.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Example — Observing a Real HTTP Request: Chrome DevTools and Wireshark
&lt;/h3&gt;

&lt;p&gt;Theory is important — but seeing HTTP communication &lt;strong&gt;live in action&lt;/strong&gt; truly deepens understanding. In this section, we’ll walk through a &lt;strong&gt;real-world experiment&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perform an HTTP request using Chrome.&lt;/li&gt;
&lt;li&gt;Observe the full lifecycle — DNS resolution, connection establishment, and HTTP exchange — using:
 —  &lt;strong&gt;Chrome DevTools&lt;/strong&gt; (Application Layer view)
 —  &lt;strong&gt;Wireshark&lt;/strong&gt; (Network Layer view)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;h4&gt;
  
  
  Test Scenario
&lt;/h4&gt;

&lt;p&gt;We’ll open the browser and load a simple URL: &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This triggers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS lookup&lt;/li&gt;
&lt;li&gt;TCP or QUIC connection establishment&lt;/li&gt;
&lt;li&gt;TLS handshake (for HTTPS)&lt;/li&gt;
&lt;li&gt;HTTP request and response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll capture and inspect every step.&lt;/p&gt;

&lt;h4&gt;
  
  
  Observing the HTTP Journey in Chrome DevTools
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Step 1: Preparing Chrome DevTools
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Google Chrome&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Press F12 to open &lt;strong&gt;DevTools&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Network&lt;/strong&gt;  tab.&lt;/li&gt;
&lt;li&gt;Enable:
 —  &lt;strong&gt;Preserve log&lt;/strong&gt; (to keep records even if page reloads).
 —  &lt;strong&gt;Disable cache&lt;/strong&gt; (to avoid cached responses affecting the results).&lt;/li&gt;
&lt;li&gt;(Optional) Right-click the Network tab’s column headers and enable the &lt;strong&gt;Protocol&lt;/strong&gt; column if not already visible.&lt;/li&gt;
&lt;li&gt;Press the &lt;strong&gt;Clear (⟲)&lt;/strong&gt; button to clear old network activity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7wrwr9fclkowwtuu9s7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7wrwr9fclkowwtuu9s7.png" alt="Screenshot of Chrome DevTools Network tab capturing HTTP traffic" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Optional: Forcing a Fresh Connection
&lt;/h4&gt;

&lt;p&gt;To ensure Chrome performs a full DNS lookup and handshake instead of reusing an existing connection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visit: chrome://net-internals/#sockets
 — Click &lt;strong&gt;Flush socket pools&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bdtk1h3t2vg78vgcevz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bdtk1h3t2vg78vgcevz.png" alt="Screenshot of Chrome's net-internals page showing socket pool flushing option" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visit: chrome://net-internals/#dns
 — Click &lt;strong&gt;Clear host cache&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu1q446ubgp0aqendl42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu1q446ubgp0aqendl42.png" alt="Screenshot of Chrome's net-internals DNS tab with Clear host cache button" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or simply open a new &lt;strong&gt;Incognito Window&lt;/strong&gt; with cache disabled.&lt;/p&gt;

&lt;p&gt;This forces Chrome to perform every network step fresh.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Loading the Test URL
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In the address bar, type &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Press Enter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observe the network activity in the DevTools Network panel.&lt;/p&gt;

&lt;p&gt;Focus on the &lt;strong&gt;main request&lt;/strong&gt; to example.com.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Inspecting the Request Details
&lt;/h4&gt;

&lt;p&gt;Click on the example.com request and check:&lt;/p&gt;

&lt;h4&gt;
  
  
  General Overview
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request URL&lt;/strong&gt; : &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Method&lt;/strong&gt; : GET&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status Code&lt;/strong&gt; : 200 OK&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote Address&lt;/strong&gt; : e.g., 96.7.128.175:443 (or a different one based on the returned result from the DNS Resolution)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt; : (Shown in the Network table) — typically h2 (HTTP/2) or http/1.1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqk4gsiafctc3cahxsvr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqk4gsiafctc3cahxsvr9.png" alt="Screenshot of DevTools Headers tab showing HTTP request and response details" width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmze4z7tjeylrozvovcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmze4z7tjeylrozvovcy.png" alt="Screenshot of DevTools General tab with remote address and protocol information" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Timing Breakdown (Timing Tab)
&lt;/h4&gt;

&lt;p&gt;In the Timing tab, you will see a waterfall graph divided into phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS Lookup Time&lt;/li&gt;
&lt;li&gt;TCP Connection Time&lt;/li&gt;
&lt;li&gt;TLS Handshake Time&lt;/li&gt;
&lt;li&gt;Request Sent Time&lt;/li&gt;
&lt;li&gt;Waiting (TTFB) — Time to First Byte&lt;/li&gt;
&lt;li&gt;Content Download Time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each phase maps directly to the theoretical journey we described earlier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If the connection is reused, only the Request/Response phases will be visible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m6gys3x0z8x0xsypntb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m6gys3x0z8x0xsypntb.png" alt="Screenshot of DevTools Timing tab showing DNS, TCP, TLS, and download durations" width="800" height="663"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Observing the Same Journey in Wireshark
&lt;/h4&gt;

&lt;p&gt;For a deeper, packet-level view, we’ll capture and inspect network traffic using &lt;strong&gt;Wireshark&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Setting Up Wireshark Capture
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Wireshark&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select your active network interface (e.g., Wi-Fi, Ethernet).&lt;/li&gt;
&lt;li&gt;Start &lt;strong&gt;capturing traffic&lt;/strong&gt;  — no filter needed yet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy03lwks4k8awcc0qg58q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy03lwks4k8awcc0qg58q.png" alt="Screenshot of Wireshark interface selecting network adapter for traffic capture" width="800" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now Wireshark records all network activity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Loading the Test URL
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In Chrome (DevTools open, caching disabled or after flushing sockets),
reload &lt;a href="https://example.com." rel="noopener noreferrer"&gt;https://example.com.&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wireshark captures all the DNS, TCP, TLS, and HTTP packets involved.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Filtering Relevant Packets
&lt;/h4&gt;

&lt;p&gt;After the capture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the &lt;strong&gt;resolved IP address&lt;/strong&gt; for example.com:
 — (You can see it in DevTools → Headers → Remote Address.)&lt;/li&gt;
&lt;li&gt;In Wireshark, apply this &lt;strong&gt;display filter&lt;/strong&gt; :
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dns or ip.addr == [resolved IP address]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0lduwhkl9rka1o71gj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0lduwhkl9rka1o71gj3.png" alt="Wireshark screenshot filtered for DNS and traffic to server IP" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This filters the traffic down to only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS queries/responses&lt;/li&gt;
&lt;li&gt;TCP or QUIC connection packets&lt;/li&gt;
&lt;li&gt;TLS handshake packets&lt;/li&gt;
&lt;li&gt;HTTP encrypted application data&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 4: Analyzing the Captured Packets
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;You’ll observe:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DNS Resolution:&lt;br&gt;
 — &lt;/strong&gt; DNS query for example.com
 — DNS response with IP address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc7yz26kdxegn8arzjbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc7yz26kdxegn8arzjbk.png" alt="DNS query and response for example.com captured in Wireshark" width="800" height="17"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TCP Three-Way Handshake&lt;/strong&gt; (for HTTP/1.1 or HTTP/2):
 — SYN → SYN-ACK → ACK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqd9vahzybewyu41ahie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqd9vahzybewyu41ahie.png" alt="TCP three-way handshake packets captured in Wireshark" width="800" height="34"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLS 1.3 Handshake&lt;/strong&gt; (HTTPS only):
 — ClientHello
— ServerHello&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q0rub316ljgqk9egoya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q0rub316ljgqk9egoya.png" alt="TLS 1.3 handshake packets including ClientHello and ServerHello in Wireshark" width="800" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important: If TLS 1.2 you will see more steps&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Request and Response&lt;/strong&gt; (encrypted inside TLS Application Data frames):
 — Encrypted packet containing HTTP GET request
 — Encrypted packet containing HTTP 200 OK response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb8787hiwqwivjpqxnmk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb8787hiwqwivjpqxnmk.png" alt="Encrypted TLS Application Data packets containing HTTP request and response" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TCP Session Closure&lt;/strong&gt; :
 — FIN-ACK packets cleanly closing the connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskz3cj4x2np70jqvooe0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskz3cj4x2np70jqvooe0.png" alt="TCP FIN-ACK packets closing the connection, captured in Wireshark" width="800" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each step &lt;strong&gt;perfectly matches&lt;/strong&gt; the theoretical journey described earlier.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Observations
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DNS lookup&lt;/strong&gt; must complete successfully before any connection is attempted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP handshakes and TLS negotiation&lt;/strong&gt; introduce real-world latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS handshake&lt;/strong&gt; ensures secure communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP request and response&lt;/strong&gt; data are encrypted (not directly visible unless you decrypt TLS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QUIC (for HTTP/3)&lt;/strong&gt; would show a slightly different pattern — no separate TCP and TLS handshakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real-world inspection confirms how different protocols work together to deliver even a simple webpage.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Chrome DevTools shows the &lt;strong&gt;application-level&lt;/strong&gt; phases of HTTP requests.&lt;/li&gt;
&lt;li&gt;Wireshark reveals the &lt;strong&gt;network-layer&lt;/strong&gt; behavior — from DNS, to TCP/QUIC, to TLS, to HTTP Application Data.&lt;/li&gt;
&lt;li&gt;Together, they validate and demystify the &lt;strong&gt;full HTTP communication lifecycle&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In the next part of the series, we’ll zoom into the structure of HTTP requests and responses — learning about headers, methods, status codes, and how they work across different HTTP versions.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What do you think?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Was this breakdown helpful?&lt;br&gt;&lt;br&gt;
I'd love to hear your thoughts, feedback, or any questions you have in the comments.&lt;/p&gt;

&lt;p&gt;Let's discuss — whether you're just learning HTTP or you've used it for years, your perspective is welcome!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>techleadership</category>
      <category>networking</category>
      <category>backenddevelopment</category>
    </item>
  </channel>
</rss>
