Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Networking

URLs

What parts is a URL made of?

A URL such as http://localhost:8080/hello?name=kim, which you type in the address bar, looks like one block of characters, but it is a set of parts divided by fixed symbols (://, :, /, ?). The scheme (http) tells which rules to talk by, the host (localhost) tells which computer, the port (8080) tells which program on that computer, the path (/hello) tells what to ask that program for, and the query (?name=kim) is an extra value sent along. The client (the browser) splits the URL into these parts, connects with the host and the port, and writes only the path and the query in the first line of the HTTP request that it sends to the server. In this lab, you remove or change the parts one at a time, send a request to the same server (a server that has only the /hello address), and see where each part is used and what happens when a part is missing.

Checked against real execution · Ran all 24 combinations on Node.js 24.18.0 and checked them (for the combinations without a port, it did not connect to port 80 and only intercepted where the client tried to connect)

Concepts in this lab

URL components
A URL is divided into several parts at fixed symbols. In https://shop.example:8443/shop/list?q=a#review, https is the scheme, shop.example is the host, 8443 is the port, /shop/list is the path, q=a is the query, and review is the fragment. If the port is not written, the connection uses the default port of the scheme (80 for http, 443 for https). The host and port decide where to connect, and the path and the query are carried in the request line to the server. The fragment is used only by the browser to find a position in the document it received, and it is not sent to the server.
Scheme and default port
The scheme is the name at the very beginning of a URL, up to the first :, and it tells which rules to talk by for this URL. In http://localhost/hello, http is the scheme, and it begins with a letter (RFC 3986 section 3.1). A scheme can also define a default port (section 3.2.3), so the default port of http is 80, and if the URL does not write a port, the client connects to port 80 (RFC 9110 section 4.2.1). Without a scheme, it cannot be known what symbols such as : and / divide, so according to the URL standard (WHATWG), the text is not read as an address unless there is another address to use as a base. If there is a : as in localhost:8080/hello, localhost may even be read as the scheme.
Path and query
The path runs from the / after the host and the port up to the ?, and the query runs from the first ? up to the # or the end of the URL (RFC 3986 section 3.3 and section 3.4). A query is a value written in the form name=kim and attached to the path, and when there are several values, joining them with & is a widely used convention. Of the URL, the client writes only these two in the first line of the request (the request line) and sends them (origin-form in RFC 9112 section 3.2.1), and if the path is empty it must send /. The scheme, the host, and the port do not go into the first line. The host and the port are used to connect, and they are also written in the Host header (RFC 9110 section 7.2).
Port
A port is a number from 0 to 65535 that tells apart which of the several programs running on one computer should receive the data. If an IP address points to the computer, a port points to the program inside that computer, so the place to connect to is written as "IP address:port". A server program waits for connections on a port it has chosen, and some numbers are widely agreed upon, such as 80 (HTTP) and 443 (HTTPS) for web servers. Normally only one program can wait for connections on a port, so starting a server on a port that is already in use causes an "address already in use" error. The ports of TCP and the ports of UDP are managed separately, so the same number in each is a different thing.

Try these

Running with the default settings

  1. The client (the browser) receives the URL "http://localhost:8080/hello?name=kim". A URL is not one block of characters but a set of parts divided by fixed symbols (://, :, /, ?). The client looks at these symbols and splits the URL into parts from the left. The server is a server that has only the /hello address.
  2. From the beginning up to :// is the scheme, and here it is "http". The scheme tells which rules to talk to the server by. http means to talk by HTTP rules, that is, to send a request line and headers and receive a response.
  3. From after :// up to the / is the host and the port. The part before the : is the host, and here it is "localhost". The host tells which computer to connect to.
  4. The part after the : is the port, and here it is "8080". Several programs can run on one computer, and the port tells which of them to connect to. Our server program is waiting on port 8080.
  5. Then from the / up to the ? is the path, and here it is "/hello". The path tells the connected program what to ask for.
  6. What follows the ? is the query, and here it is "name=kim". It is in the form name=value, and it is a value sent along with the path.
  7. The client connects with the host and the port. It connects to the server program waiting on port 8080 of the localhost computer (this PC). The scheme, the host, and the port were used for this connection.
  8. Once connected, the client writes the path and the query in the first line of the request and sends it: "GET /hello?name=kim HTTP/1.1". The scheme (http), the host (localhost), and the port (8080) do not go into the first line. The host and the port were used to connect, and they are also written in the Host header of the request. In this experiment, the Host line the server received was "Host: localhost:8080".
  9. The server looks at the path in the first line. /hello is an address it has, so it makes a 200 response. It reads the name in the body from the query. The value of name is kim, so the body is "Hello, kim". This server code is not shown on the screen, but it was built to answer this way.
  10. The browser receives a 200 response. The body is "Hello, kim".

Result of this run

Code

http://localhost:8080/hello?name=kim

Assumptions of this model

The server is a single one built with the http module of Node.js 24.18.0. For GET /hello it returns 200 with the body "Hello, <the value of name>" (or "Hello, guest" if there is no name), and for any other path it returns 404. We ran and checked all 24 combinations. The result of splitting the URL into parts (scheme, host, port, path, query) is the value that Node.js's new URL(text) produced. This parser follows the same URL standard (WHATWG URL) as browsers. We sent the request by giving that URL to http.request of Node.js, and we recorded the first line and the Host line of the request that the server received exactly as they were. 8080 on the screen is an example. For the combinations that write a port, we started the server on a free port, put that number in the 8080 slot of the URL, and really connected by the name localhost, and we checked against it after changing the number in the Host line the server received to 8080. We also redirected only the connection of the same URL text (with 8080 as it is) to a test server, and recorded where the client tried to connect (it was port 8080). For the combinations that omit the port, we did not really connect to port 80. We intercepted the connection and recorded only that where the client tried to connect was port 80 of localhost, and the first line and the Host line ("Host: localhost", with no port number) of the request it was going to send. So the condition "if there is no server on port 80, the connection cannot be made" in the response box was not checking port 80 of this PC, but a condition that comes from the fact that the place it tried to connect to was port 80, and we did not look at the state of port 80 on this PC. For the combinations without a scheme, we followed the actual results. With a : as in localhost:8080/hello, new URL read localhost as the scheme, left the host and the port empty, and read 8080/hello as the path, and without a : as in localhost/hello, it was an Invalid URL error (ERR_INVALID_URL). In the former case, http.request could not send the request with ERR_INVALID_PROTOCOL, and fetch could not with unknown scheme (this is a case where no connection happens, so we really tried it). On this PC, localhost resolved to the two addresses ::1 and 127.0.0.1 (::1 first), and even though the test server was opened on 127.0.0.1 only, with the default setting of Node.js (try several addresses in turn) the connection went to 127.0.0.1. With the setting that turns that attempt off, the connection was refused on ::1. We did not look at what browsers do. What we opened in the documents and checked is section 3 of RFC 3986 (URI = scheme ":" hier-part [ "?" query ], the division into scheme, authority, path, and query), section 3.1 (scheme), section 3.2.3 (a scheme may define a default port, and if the port is empty it is omitted), section 3.3 (path), section 3.4 (the query runs from the first ? to # or the end), section 4.2.1 of RFC 9110 (for http, if the port is empty or not given, TCP port 80 is the default), section 7.2 (Host tells the host and port of the target URI), section 3.2.1 of RFC 9112 (origin-form sends only the path and the query as the request target, and if the path is empty it must send /), and section 4.4 of the WHATWG URL standard (if it cannot find a scheme and there is no base URL, it fails; if a special scheme is not followed by //, the rest is read as the path; a port that equals the default port is left empty). The documents were opened only as summaries, so we could not check the whole original text against them. The address bar of a browser has a convenience feature that adds http:// for you even if you do not write it, but this lab dealt only with the rules of the URL itself, and we did not check the behavior of the address bar by execution. The client of this lab is Node.js, and we did not run it with a real browser. The detailed rules such as the fragment (#), percent-encoding, and relative URLs are covered in the in-depth lab "URL structure".

Previous lab: TCP connections · Next lab: DNS

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these