Scientyfic World

What Is an HTTP Request? Structure, Methods & Examples

An HTTP request is a message a client (a browser, an app or a script) sends to a server to ask it to do something: return a web page, send...

Share:

Get an AI summary of this article

Blog banner titled http request containing sitelogo and a vector image of a boy and a girl with a pencil and a notebook

An HTTP request is a message a client (a browser, an app or a script) sends to a server to ask it to do something: return a web page, send data, save a form or delete a record. Every request has a method such as GET or POST, a URL, headers and an optional body, and the server answers with an HTTP response containing a status code, headers and usually a body.

This guide shows what an HTTP request looks like on the wire, what each method is for, and how to make GET and POST requests with curl, JavaScript’s fetch and Python. Every example was run against a small local server (its code is at the end), and the outputs shown are real.

What Happens When You Make an HTTP Request

  1. The client resolves the domain name to an IP address using DNS.
  2. It opens a connection to the server (for HTTPS, it also performs a TLS handshake to encrypt the connection).
  3. It sends the request: method, path, headers and, if needed, a body.
  4. The server processes it and sends back a response with a status code, headers and body.
  5. The client uses the response, for example by rendering the HTML or reading the JSON.

HTTP is stateless: each request stands on its own, and the server does not remember previous ones. Logins and shopping carts work by sending extra information, such as a cookie or an Authorization header, with every request.

The Structure of an HTTP Request

Running curl -v http://localhost:3000/posts shows the exact request curl sent (lines starting with >) and the response it received (<):

> GET /posts HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/8.7.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Thu, 22 Oct 2026 15:03:17 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
<
[{"id":1,"title":"Hello HTTP"}]

A request has four parts:

PartExampleWhat it does
Request lineGET /posts HTTP/1.1The method, the path (plus any query string) and the protocol version
HeadersHost, Accept, Content-Type, AuthorizationMetadata: which site, what formats the client accepts, what the body contains, who is asking
Blank lineMarks the end of the headers
Body (optional){"title":"My first post"}Data sent to the server, mostly with POST, PUT and PATCH

The response mirrors it: a status line (HTTP/1.1 200 OK), headers, a blank line and the body. With HTTP/2 and HTTP/3 the same information is sent in a compressed binary form, but the methods, headers and status codes are identical, so everything in this guide applies to all three versions.

HTTP Request Methods

The method (sometimes called a verb) tells the server what you want to do. RFC 9110, the current HTTP specification, defines these, and PATCH comes from RFC 5789:

MethodPurposeHas a body?SafeIdempotent
GETRetrieve a resourceNoYesYes
POSTSend data to be processed, often creating a new resourceYesNoNo
PUTCreate or replace a resource at a known URLYesNoYes
PATCHPartially update a resourceYesNoNo (not guaranteed)
DELETEDelete a resourceUsually noNoYes
HEADSame as GET but returns only the headersNoYesYes
OPTIONSAsk which methods and options a resource supports; used by browsers for CORS preflight checksNoYesYes
TRACEEcho the request back for diagnostics; usually disabled for securityNoYesYes
CONNECTAsk a proxy to open a tunnel, for example for HTTPS through a proxyNoNoNo
  • Safe means the request should not change anything on the server, so browsers and crawlers can make it freely.
  • Idempotent means sending the same request several times has the same effect as sending it once. Deleting user 42 twice still leaves user 42 deleted, but submitting the same POST twice can create two orders. That is why clients can safely retry idempotent requests after a network error, but should be careful retrying POST.

A common misconception is that POST is “secure” because the data is not in the URL. It keeps data out of browser history and server logs, but the body is only encrypted if you use HTTPS. Never send passwords or tokens over plain HTTP, whatever the method.

How to Make a GET Request

With curl

curl http://localhost:3000/posts
# [{"id":1,"title":"Hello HTTP"}]

curl -I http://localhost:3000/posts      # HEAD: headers only
# HTTP/1.1 200 OK
# Content-Type: application/json

With JavaScript fetch

fetch is built into browsers and into Node.js 18 and later, so you don’t need a library. Use URLSearchParams to build query strings so that values are encoded correctly:

const params = new URLSearchParams({ page: '2', sort: 'new' });
const res = await fetch(`http://localhost:3000/echo?${params}`);
console.log(res.status, await res.json());
// 200 { method: 'GET', query: { page: '2', sort: 'new' }, ... }

With Python

import requests

r = requests.get("http://localhost:3000/echo", params={"page": 2, "sort": "new"}, timeout=10)
print(r.status_code, r.json()["query"])
# 200 {'page': '2', 'sort': 'new'}

How to Make a POST Request

To send JSON, put it in the body and set the Content-Type: application/json header so the server knows how to read it. Forgetting that header is one of the most common reasons a server says the body is empty or invalid.

With curl

curl -X POST http://localhost:3000/posts \
  -H 'Content-Type: application/json' \
  -d '{"title":"My first post"}'
# {"id":2,"title":"My first post"}   (status 201 Created)

With fetch

const created = await fetch('http://localhost:3000/posts', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Sent with fetch' }),
});
console.log(created.status, await created.json());
// 201 { id: 3, title: 'Sent with fetch' }

With Python

r = requests.post("http://localhost:3000/posts", json={"title": "Sent with Python"}, timeout=10)
print(r.status_code, r.json())
# 201 {'id': 2, 'title': 'Sent with Python'}

Passing json= makes requests serialize the data and set the Content-Type header for you. HTML forms send POST data differently, as application/x-www-form-urlencoded (or multipart/form-data when uploading files). If you prefer a library in JavaScript, see how to use Axios with React.

Handle Errors: fetch Does Not Throw on 404 or 500

This catches many developers out. fetch only rejects when the request cannot be made at all, such as a network failure. A 404 or 500 response is still a “successful” fetch, so you must check res.ok (true for status 200–299):

const missing = await fetch('http://localhost:3000/nope');
console.log('ok?', missing.ok, 'status', missing.status);
// ok? false status 404
if (!missing.ok) console.log('handle the error here:', await missing.json());
// handle the error here: { error: 'Not found' }

In Python, call r.raise_for_status(), which raised 404 Client Error: Not Found for url: http://localhost:3000/nope in my test. Always set a timeout too; requests waits forever by default.

HTTP Status Codes You Will See Most

CodeMeaningTypical cause
200 OKSuccessThe request worked and the body has the result
201 CreatedA resource was createdSuccessful POST or PUT
204 No ContentSuccess with no bodySuccessful DELETE
301 / 308Moved permanentlyThe URL changed; follow the Location header
304 Not ModifiedUse your cached copyConditional GET with If-None-Match or If-Modified-Since
400 Bad RequestThe request is malformedInvalid JSON, missing fields
401 UnauthorizedNot authenticatedMissing or invalid credentials
403 ForbiddenAuthenticated but not allowedInsufficient permissions
404 Not FoundNo such resourceWrong URL or deleted item
429 Too Many RequestsRate limitedSlow down; check the Retry-After header
500 Internal Server ErrorThe server failedA bug or crash on the server
503 Service UnavailableTemporarily unavailableOverload or maintenance

Common Request Headers

HeaderExamplePurpose
Hostexample.comWhich website on the server you want (required in HTTP/1.1)
Acceptapplication/jsonFormats the client can handle
Content-Typeapplication/jsonFormat of the request body
AuthorizationBearer <token>Credentials for an API
Cookiesession=abc123Session and preference data set earlier by the server
User-Agentcurl/8.7.1Which client is making the request
Cache-Controlno-cacheCaching instructions

Making Requests from the Browser: CORS

When JavaScript on one site calls an API on a different origin (domain, protocol or port), the browser applies the same-origin policy. The API must allow it with CORS headers such as Access-Control-Allow-Origin, and for some requests, like POST with JSON, the browser first sends an OPTIONS “preflight” request to check. If you see a CORS error in the console, the fix is on the server’s response headers; the same request from curl or Python works because CORS is enforced only by browsers.

The Test Server Used in This Guide

To reproduce the examples, save this as server.mjs and run node server.mjs (Node.js 18 or later). It has no dependencies:

import { createServer } from 'node:http';

const posts = [{ id: 1, title: 'Hello HTTP' }];

createServer(async (req, res) => {
  let body = '';
  for await (const chunk of req) body += chunk;
  const url = new URL(req.url, 'http://localhost');
  const send = (status, data) => {
    res.writeHead(status, { 'Content-Type': 'application/json' });
    res.end(data === undefined ? undefined : JSON.stringify(data));
  };

  if (url.pathname === '/posts' && ['GET', 'HEAD'].includes(req.method)) return send(200, posts);
  if (url.pathname === '/posts' && req.method === 'POST') {
    const post = { id: posts.length + 1, ...JSON.parse(body) };
    posts.push(post);
    return send(201, post);
  }
  if (url.pathname === '/echo') {
    return send(200, { method: req.method, query: Object.fromEntries(url.searchParams), headers: { 'content-type': req.headers['content-type'] ?? null }, body });
  }
  send(404, { error: 'Not found' });
}).listen(3000, () => console.log('listening on 3000'));

To see how to build a fuller API with validation and authentication, read how to build a REST API with Node.js and Express.

Conclusion

An HTTP request is just a method, a URL, some headers and an optional body. Use GET to read, POST to create, PUT or PATCH to update and DELETE to remove; send JSON with the right Content-Type; check the status code instead of assuming success; and always use HTTPS for anything sensitive. With curl, fetch and Python’s requests you can make any request you need, and curl -v or your browser’s Network tab will show you exactly what was sent when something goes wrong.

FAQs

What is an HTTP request?

A message a client sends to a server asking it to perform an action, such as returning a page or saving data. It contains a method (like GET or POST), a URL, headers and an optional body. The server replies with an HTTP response.

What is an example of an HTTP GET request?

Typing a URL into a browser sends a GET request. On the wire it looks like “GET /posts HTTP/1.1” followed by headers such as “Host: example.com”. From the command line, “curl https://example.com/posts” sends one.

What is the difference between GET and POST?

GET retrieves data and puts any parameters in the URL; it should not change anything on the server. POST sends data in the request body to be processed, such as creating a record. GET is safe and idempotent; POST is neither.

What is the difference between PUT and PATCH?

PUT replaces the whole resource with the data you send and is idempotent. PATCH applies a partial update, changing only the fields you include.

What are the parts of an HTTP request?

A request line (method, path and protocol version), headers, a blank line, and an optional body.

Is POST more secure than GET?

Only slightly: POST keeps data out of the URL, browser history and many server logs. Neither method encrypts anything. Use HTTPS to protect data in transit.

Why does fetch not throw an error on a 404?

fetch only rejects when the request cannot complete, such as a network error. HTTP error statuses are valid responses, so check response.ok or response.status yourself.

Snehasish Konger
Developed @scientyficworld.org | Technical writer @Nected | Content Developer
Connect with Snehasish Konger

On This page

Take a Pause with Intervals

A Sunday letter on building, writing, and thinking deeper as a developer — short, honest, and worth your time.

Snehasish Konger profile photo

"Hey there — I'm Snehasish. Hope this post saved you some head-scratching time! I've spent years turning technical chaos into clarity, and I'm here to be your guide through the maze of modern tech. Stick around for more lightbulb moments — we're just getting started."

Related Posts