HTTP Requests

Table of Contents

  1. HTTP Is Just Text
  2. The Request Line
  3. Methods: What You Want to Do
  4. Safe and Idempotent
  5. Headers: Extra Information
  6. The Body
  7. Sending Requests with curl
  8. Reading a Request in DevTools
  9. Try It Yourself

1. HTTP Is Just Text

The connection from chapter 4 is open. Now the browser sends its request — and here's the surprising part: an HTTP request is a few lines of plain text. Here's what your browser sends when you open your GitHub Pages site:

GET /my-site/ HTTP/1.1
Host: dara-sok.github.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/130.0
Accept: text/html,application/xhtml+xml
Accept-Language: km-KH,km;q=0.9,en;q=0.8
Accept-Encoding: gzip, br
Connection: keep-alive

That's the whole thing. HTTP — the HyperText Transfer Protocol — is a set of rules for what those lines must look like. Every request has the same shape:

 1. Request line     GET /my-site/ HTTP/1.1
 2. Headers          Host: …, User-Agent: …, …
 3. A blank line     (marks the end of the headers)
 4. Body (optional)  data being sent, e.g. a form

(HTTP/2 and HTTP/3 send the same information in a compact binary form instead of text, but the meaning is identical. DevTools and curl show it to you as text either way.)

2. The Request Line

The first line has three parts:

GET  /my-site/  HTTP/1.1
 │       │         └── which version of HTTP
 │       └──────────── which resource: the path (+ query) from the URL
 └──────────────────── the method: what you want to do with it

Notice what's not there: the scheme and host aren't in this line (the host has its own header, next to it), and the fragment from chapter 2 isn't anywhere — the browser never sends it.

3. Methods: What You Want to Do

The method is a verb. The path says which resource; the method says what to do with it. These are the ones you'll use:

MethodMeansExample
GETGive me this resourceOpen a page, load an image, fetch a list of products
POSTHere's some new data — process itSubmit a sign-up form, create an order, upload a photo
PUTReplace this resource with what I'm sendingSave a whole edited profile
PATCHChange part of this resourceUpdate just your phone number
DELETERemove this resourceDelete a comment

There are a few more — HEAD (like GET, but send only the headers) and OPTIONS (what am I allowed to do here?) are the ones you'll meet, the second one in chapter 10.

When you click a link or type a URL, the browser always uses GET. When you submit a form, it usually uses POST. The others are used mostly by JavaScript and by apps talking to APIs — you'll write them yourself in the NestJS Crash Course, where a controller has a separate function for @Get(), @Post(), @Patch(), and @Delete() on the same path.

4. Safe and Idempotent

Two words describe what a method promises:

  • Safe: it doesn't change anything on the server. GET and HEAD are safe — loading a page shouldn't delete your account.
  • Idempotent: doing it twice has the same effect as doing it once. GET, PUT, and DELETE are idempotent. Deleting comment 7 twice still leaves comment 7 deleted.

POST is neither. Submitting an order form twice can create two orders. That's why your browser warns "Confirm form resubmission" when you refresh a page you got from a POST, and why payment APIs, like the ABA PayWay ones in this site's tutorials, take care to avoid charging someone twice.

The rule for when you build things: never use GET for something that changes data. Browsers, search engines, and link previews all feel free to send GET requests whenever they like, assuming nothing will change.

5. Headers: Extra Information

After the request line come headers: one per line, written as Name: value. They carry everything else the server might need to know. Header names aren't case-sensitive. The common ones:

HeaderWhat it tells the server
HostWhich website you want (required)
User-AgentWhich browser or program is asking
AcceptWhich kinds of content you can handle — HTML, JSON, images…
Accept-LanguageWhich languages you prefer, in order
Accept-EncodingWhich compression formats you understand
CookieData the server asked you to remember (chapter 8)
AuthorizationProof of who you are, like a token (Keycloak tutorial)
Content-TypeWhat kind of data is in the body (when there is one)
RefererWhich page linked you here (yes, it's spelled wrong — since 1996)

Why is Host required? Because one server computer — one IP address — often hosts thousands of websites. All GitHub Pages sites share the same few IP addresses. The Host header is the only way GitHub's server knows you want dara-sok.github.io and not someone else's site.

The q=0.9 in Accept-Language: km-KH,km;q=0.9,en;q=0.8 is a preference weight from 0 to 1: "Khmer (Cambodia) first, then any Khmer, then English." A site that supports several languages can use it to pick one for you.

6. The Body

GET requests have no body — everything they need is in the URL. POST, PUT, and PATCH usually do. The Content-Type header says how to read it. You'll see two kinds most often.

A classic HTML form sends its fields like a query string:

POST /signup HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 38

name=Dara+Sok&email=dara%40example.com

An app or JavaScript calling an API usually sends JSON:

POST /api/orders HTTP/1.1
Host: shop.example.com
Content-Type: application/json
Content-Length: 32

{"productId": 42, "quantity": 2}

Content-Length says how many bytes the body has, so the server knows where it ends. Notice the blank line between the headers and the body — that's how the server knows the headers are over.

Remember from chapter 4: with HTTPS, all of this — headers and body — is encrypted. With plain HTTP, that email address is readable by everyone on the way.

7. Sending Requests with curl

curl lets you write requests by hand. Some options you'll use all the time:

curl https://example.com                 # GET, print the body
curl -v https://example.com              # also show request + response headers
curl -I https://example.com              # HEAD: headers only
curl -X POST https://example.com/api     # use a different method
curl -H "Accept-Language: km" https://example.com   # add a header
curl -d "name=Dara" https://example.com/signup      # send a body (implies POST)

With -v, lines starting with > are what you sent, and lines starting with < are what came back:

> GET /my-site/ HTTP/2
> Host: dara-sok.github.io
> User-Agent: curl/8.7.1
> Accept: */*
>
< HTTP/2 200
< content-type: text/html; charset=utf-8
< …

Look how short curl's request is compared with a browser's. Accept: */* means "I'll take anything." Servers don't need all those extra headers; browsers send them to get the best version of a page.

Practise safely: the site https://httpbin.org exists for exactly this. It echoes back whatever you send it, so you can try any method without breaking anything. curl https://httpbin.org/get shows you your own request, as the server saw it.

8. Reading a Request in DevTools

In the browser:

  1. Open DevTools → Network and reload the page.
  2. Click a request in the list.
  3. The Headers tab shows the URL, the method, and the status code at the top (under General), then Response Headers, then Request Headers.
  4. For a POST, the Payload tab (Chrome/Edge) or Request tab (Firefox) shows the body.

Two things worth turning on: right-click the column headers in the request list and add the Method column, and tick Preserve log at the top so the list isn't cleared when a form submission takes you to a new page.

Developers spend a lot of time here. When an app "doesn't work", the first question is almost always: what request did it actually send?

9. Try It Yourself

  1. See your own request. Run curl https://httpbin.org/headers. Then open the same address in your browser. Compare the headers. How many more does the browser send?

  2. Try other methods.

    curl -X POST https://httpbin.org/post -d "name=Dara"
    curl -X DELETE https://httpbin.org/delete
    curl -X POST https://httpbin.org/post \
      -H "Content-Type: application/json" \
      -d '{"productId": 42, "quantity": 2}'
    

    In each reply, find where httpbin shows the body it received.

  3. Ask for another language. Run curl -I -H "Accept-Language: km" https://www.google.com and then again with en. Do the response headers change?

  4. Watch a form. On any site with a search box, open DevTools → Network, tick Preserve log, and search for something. Find the request. Was it GET or POST? Where did your search term go — the URL or the body?

The request has been sent. Next: what the server sends back, and what all those numbers like 200 and 404 mean.

Buy Me a Coffee

Found this tutorial helpful? Consider buying me a coffee to support more free content!