Skip to content

What happen when you type link and enter?

大家经常会说自己知道如何使用电脑,但是很多人对电脑背后的运行的基础原理却一窍不通。浏览网页是我们日常上网的过程中最经常使用的场景,不知道你有没有想过,从你输入网址,到按下回车键的过程,浏览器的背后都发生了什么?

网址和URL之间的关系

在日常生活中我们似乎很容易将网址URL这两个概念联系起来,尽管他们可能长得比较类似,但他们并不完全相同

  1. 网址是URL的一种形式
  • URL 是一种用于定位互联网上资源的统一标准,它定义了资源的访问方式(协议)、主机地址、路径和参数
  • 网址 是人们通常用来访问网页的URL,特指能通过HTTP或HTTPS协议访问的URL
  1. URL的组成

一个完整的URL包括以下内容:

protocol :// hostname[:port] / path / [;parameters][?query]#fragment

或者

协议://主机名[:端口]/路径[?查询参数][#片段标识符]

例如: https://www.example.com:443/path/to/resource?query=123#sectionftp://example.com/file.txt

第一个就是我们很熟悉的网址,第二个则是ftp文件协议,这两种都属于URL

  1. 网址的特点
  • 网址是URL的子集,一般仅指HTTP和HTTPS协议的资源
  • 网址更贴近日常使用,例如打开浏览器输入的网址通常是简化的URL

URL解析

当你输入一个URL到浏览器中,比如这个URL是:https://example.com,浏览器就能凭借这个URL知道以下信息:

  • Protocol:

    • 解释: 指明使用的通信协议,例如 httphttpsFTPFile等等,在之后我们将详细介绍httphttps
    • 示例:
      • URL: http://example.com/
      • 解析: 使用的是 HTTP 协议
  • Host:

    • 解释: 提供服务的主机地址,可以是域名(例如 example.com)或 IP 地址(例如 192.168.1.1)。
    • 示例:
      • URL: http://example.com/
      • 解析: 主机为 example.com
  • Port:

    • 解释: 通信使用的端口号,默认为 80(HTTP)或 443(HTTPS)。如果 URL 中未指定端口,使用协议的默认端口。
    • 示例:
      • URL: http://example.com:8080/
      • 解析: 使用的是 8080 端口
      • URL: https://example.com/
      • 解析:使用的是 443端口
  • Path (Resource):

    • 解释: 服务器上的具体资源路径,通常指文件、目录或应用接口。/ 表示网站的根路径(主页)。
    • 示例:
      • URL: http://example.com/
      • 解析: 请求的资源是 主页(根路径)
  • Query String:

    • 解释: ? 后的参数,用于传递附加信息到服务器。
    • 示例:
      • URL: http://example.com/?key=value
      • 解析: 查询字符串为 key=value
  • Fragment:

    • 解释: # 后的部分,表示文档的特定部分,通常用于导航到页面中的某一部分。
    • 示例:
      • URL: http://example.com/#section
      • 解析: 页面片段标识为 section

现代的浏览器通常比较智能,如果你输入的东西并不符合上述URL的解析规则,那么他就会将你所输入的内容发送到默认的搜索引擎中,来帮助你搜索关键词

检查 HSTS 列表

我们用户在浏览器中最能直观接受到的协议应该是httphttps。实际上http在实际传输的过程中并不安全,这在我们第二次“信息安全与开源软件”的讲座中已经叙述过了

  • 浏览器检查自带的“预加载 HSTS(HTTP严格传输安全)”列表,这个列表里包含了那些请求浏览器只使用HTTPS进行连接的网站,如果网站在这个列表内,那么只会使用https协议进行连接

  • 浏览器会自动把你输入的补全成 https://github.com(如果域名在 HSTS preload list 里,有些浏览器会补全成 https://github.com)。

在这里的strict-transport-security可以看得出是支持HSTS的,或者你也可以进入到HSTS proload list中进行检查:

zsh
(base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % curl -I https://juniortree.com

HTTP/2 200 
**accept-ranges**: bytes
**alt-svc**: h3=":443"; ma=2592000
**content-type**: text/html
**date**: Tue, 03 Dec 2024 02:48:37 GMT
**etag**: "66ba2098-7e1"
**last-modified**: Mon, 12 Aug 2024 14:47:52 GMT
**server**: Caddy
**server**: nginx/1.21.5
**strict-transport-security**: max-age=31536000; includeSubDomains; preload
**content-length**: 2017

image

  • 如果网站不在这个列表内,那么首次连接将会使用http,如果是负责任的服务器,他会帮你把http请求重定向(308)到https去:
bash
(base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % curl -i http://oneleaf.me  

HTTP/1.1 308 Permanent Redirect
**Date**: Mon, 02 Dec 2024 13:11:07 GMT
**Content-Length**: 0
**Connection**: keep-alive
**Location**: https://oneleaf.me/

如何为我自己的站点开启HSTS?

DNS查询

如果上面输入的URL为IP地址,诸如10.10.10.9这种,那么浏览器就不必要进行DNS,直接与该IP地址进行通信就可以了;但是如果上述的URL为域名,诸如cnu.edu.cn,那么浏览器就要进行DNS查询,去找到该域名所对应的IP地址

  1. 浏览器缓存检测 浏览器会首先检查自己缓存中的是否存在该域名的DNS解析记录(TTL未过期),对于Chrome浏览器,你可以通过chrome://net-internals/#dns来检查当前域名的缓存

  2. 操作系统缓存 如果浏览器中没有该缓存或者该缓存已经过期了,那么浏览器就会查询操作系统中的本地缓存或者hosts文件 hosts文件本质上就是一个纯文本文件,里面存放了一些IP地址和其对应的域名,在Windows下的路径为:

    C:\Windows\System32\drivers\etc\hosts

    Linux/Unix/macOS:

    /etc/hosts

    其基本内容为:

    127.0.0.1 localhost
    255.255.255.255 broadcasthost
    ::1             localhost
    127.0.0.1 fuse-t

    在操作系统的解析过程中,hosts文件的解析优先级是最高的,如果在hosts文件中找到匹配项,则不会再去进行操作系统内DNS缓存的查询

  3. 本地DNS服务器 如果本地缓存和hosts中都没有找到对应的解析结果或者此结果已过期,那么则向本地的DNS服务器(这通常是由路由器或者ISP(Internet service provider)提供的DNS服务器)发起请求 我们可以使用nslookup来查看请求:

    bash
    (base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % nslookup baidu.com
    
    Server: 202.204.208.2(中国–北京–北京教育网/首都师范大学)
    
    Address: 202.204.208.2#53
    
    
    
    Non-authoritative answer:
    
    Name: baidu.com
    
    Address: 110.242.68.66
    
    Name: baidu.com
    
    Address: 39.156.66.10

    可以看到这里的Server指的就是系统内默认的DNS服务器,我这里使用的是学校网关自动给我分配的DNS服务器,通常会分配两个地址,一个是202.204.208.2;另外一个是202.204.208.3

  4. 递归查询 如果我们所配置的本地DNS中也没有对应的解析结果,那么他会向上游的其他DNS服务器进行查询 推荐阅读:什么是递归DNS?| Cloudflare

CAUTION

下面内容酌情阅读,如果影响了你的理解可以直接跳转到tcp(传输控制协议)和udp(用户数据报协议)

了解了上述DNS的查询过程,那我们可以尝试来查看更详细的DNS递归解析过程,在这里我尝试使用dig +traceWireShark抓包的两种方法,来尝试帮助你更深度地了解DNS的解析

dig查看DNS解析全过程

我们可以使用dig +trace <domain>来查看完整的递归查询过程:

点我展开 ``` (base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % dig +trace github.com
; <<>> DiG 9.10.6 <<>> +trace github.com

;; global options: +cmd

. 62254 IN NS b.root-servers.net.

. 62254 IN NS h.root-servers.net.

. 62254 IN NS j.root-servers.net.

. 62254 IN NS l.root-servers.net.

. 62254 IN NS e.root-servers.net.

. 62254 IN NS k.root-servers.net.

. 62254 IN NS g.root-servers.net.

. 62254 IN NS f.root-servers.net.

. 62254 IN NS i.root-servers.net.

. 62254 IN NS m.root-servers.net.

. 62254 IN NS d.root-servers.net.

. 62254 IN NS a.root-servers.net.

. 62254 IN NS c.root-servers.net.

;; Received 767 bytes from 202.204.208.2#53(202.204.208.2) in 12 ms



com. 172800 IN NS c.gtld-servers.net.

com. 172800 IN NS i.gtld-servers.net.

com. 172800 IN NS j.gtld-servers.net.

com. 172800 IN NS h.gtld-servers.net.

com. 172800 IN NS l.gtld-servers.net.

com. 172800 IN NS d.gtld-servers.net.

com. 172800 IN NS k.gtld-servers.net.

com. 172800 IN NS e.gtld-servers.net.

com. 172800 IN NS g.gtld-servers.net.

com. 172800 IN NS m.gtld-servers.net.

com. 172800 IN NS f.gtld-servers.net.

com. 172800 IN NS b.gtld-servers.net.

com. 172800 IN NS a.gtld-servers.net.

	com. 86400 IN DS 19718 13 2 

;; Received 1170 bytes from 2001:500:1::53#53(h.root-servers.net) in 37 ms



github.com. 172800 IN NS ns-520.awsdns-01.net.

github.com. 172800 IN NS ns-421.awsdns-52.com.

github.com. 172800 IN NS ns-1707.awsdns-21.co.uk.

github.com. 172800 IN NS ns-1283.awsdns-32.org.

github.com. 172800 IN NS dns1.p08.nsone.net.

github.com. 172800 IN NS dns2.p08.nsone.net.

github.com. 172800 IN NS dns3.p08.nsone.net.

github.com. 172800 IN NS dns4.p08.nsone.net.

;; Received 635 bytes from 2001:500:856e::30#53(d.gtld-servers.net) in 183 ms


github.com. 60 IN A 20.205.243.166

github.com. 900 IN NS dns1.p08.nsone.net.

github.com. 900 IN NS dns2.p08.nsone.net.

github.com. 900 IN NS dns3.p08.nsone.net.

github.com. 900 IN NS dns4.p08.nsone.net.

github.com. 900 IN NS ns-1283.awsdns-32.org.

github.com. 900 IN NS ns-1707.awsdns-21.co.uk.

github.com. 900 IN NS ns-421.awsdns-52.com.

github.com. 900 IN NS ns-520.awsdns-01.net.
. 59039 IN RRSIG NS 8 0 518400 20241212050000 20241129040000 61050 . zB82/LDAn3ihc1FwSwRTuwCuPqaWcBwhVaZ2kNMNv+jBI7GhurWJP1+0 0yts9uaQ5hPhRotPltntH+AWD5LxAshgKd68jHtW2mVaSPyOjyn7peEL a1aBnWSKlaaUFI2+/K0eiTqhtOXn90NLqWZo5NBrQmndEFBE21GiOeS5 rQXF3McjHVi26mO41rTeO2vARbDJO0DqRto+ZB9KX3YNB9M4WYZkxG9U NO3wlhYdf7R78p+yn/1u+WwAY+mF6XFlx0R7IgN1Al74ep2+mfeVfstZ l64dtRieRkU2HGm/Zs61RPTaiIocm2WYe/hxpCkKE5cQ2QRl58fFbn92 ohtuCg==

;; Received 278 bytes from 2600:9000:5306:ab00::1#53(ns-1707.awsdns-21.co.uk) in 94 ms
```
  1. 根服务器查询: 第一部分从本地的 DNS 服务器开始查询,并向 根域名服务器 请求顶级域 (TLD) .com 的权威服务器信息:
    .         62254   IN    NS    a.root-servers.net.
    .         62254   IN    NS    b.root-servers.net.
    ...
    ;; Received 767 bytes from 202.204.208.2#53(202.204.208.2) in 12 ms
    • 本地 DNS 服务器的地址为 202.204.208.2(中国–北京–北京教育网/首都师范大学),此时CNU网关把根域名服务器的地址返回给我们
    • 它返回了根服务器列表(如 a.root-servers.netb.root-servers.net 等)

小思考:如果大家都去查询根服务器,根服务器压力会不会比较大?根服务器在哪里呢?

  1. 查询 .com 顶级域名服务器: 接下来,从根服务器获取 .com 的权威名称服务器列表:

    com.       172800   IN   NS   a.gtld-servers.net.
    com.       172800   IN   NS   b.gtld-servers.net.
    ...
    ;; Received 1170 bytes from 2001:500:1::53#53(h.root-servers.net) in 37 ms
    • 我们查询的.com顶级域名服务器返回了一组权威服务器列表(a.gtld-servers.net 等)
  2. 查询 GitHub 的权威名称服务器 通过 .com 顶级域名服务器,获得 GitHub 的权威 DNS 服务器地址:

    github.com.       172800   IN   NS   dns1.p08.nsone.net.
    github.com.       172800   IN   NS   ns-1283.awsdns-32.org.
    ...
    ;; Received 635 bytes from 2001:500:856e::30#53(d.gtld-servers.net) in 183 ms
    • 此时返回了记录了GitHub的权威服务器:如 dns1.p08.nsone.netns-1283.awsdns-32.org,此时我们再去请求如 dns1.p08.nsone.netns-1283.awsdns-32.org就可以得到GitHub的最终地址了
  3. 最终解析 GitHub 的 IP 地址 通过权威 DNS 服务器,解析出 github.com 的实际 IP 地址:

    github.com.       60   IN   A   20.205.243.166
    • IP 地址 20.205.243.166 是 GitHub 的实际服务器地址。
    • 这是最终的解析结果。

通过以上的分析我们不难看出,DNS的解析是一个递归的过程,先找到最大的根服务器,之后根服务器告诉你需要去查询的二级服务器,之后二级服务器再告诉你去哪里找到你需要的域名服务器,最后再得到最终的解析结果

image

image

图片来源于:多张图带你彻底搞懂DNS域名解析过程 | 简书

WireShark抓包

传统的DNS请求是使用UDP协议,53端口,在我们抓包的过程中也印证了这一点,我们实际上抓到了两个数据包:

image

一个是本机向服务器请求的数据包,在这里可以看到印证了我们所说的传统DNS使用53端口,UDP协议的特点,值得注意的是,基于 DNS over HTTPS(DoH)或者DNS over TLS(DoT)就不使用传统的 53 端口和UDP协议,而是使用 443 或者 853 端口

传统的使用 53 端口和UDP协议的DNS的传输过程是全明文的,在DNS的解析的每一个结果都有可能被监听或者篡改

下面的每一跳中的路由都有可能篡改你的解析结果,使你进入到错误的网站

推荐阅读DNS劫持 | 卡巴斯基

bash
(base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % traceroute 1.1.1.1
traceroute to 1.1.1.1 (1.1.1.1), 64 hops max, 40 byte packets
 1  * * *
 2  <redacted>
 3  <redacted>
 4  <redacted>
 5  <redacted>
 ...
10  223.120.2.209 (223.120.2.209)  146.368 ms  98.243 ms  126.043 ms
11  223.118.4.105 (223.118.4.105)  117.717 ms
    223.118.4.101 (223.118.4.101)  111.705 ms
    223.118.4.105 (223.118.4.105)  97.162 ms
12  * 103.22.201.78 (103.22.201.78)  241.559 ms *
13  103.22.201.23 (103.22.201.23)  125.414 ms
    103.22.201.97 (103.22.201.97)  147.406 ms
    103.22.201.23 (103.22.201.23)  131.828 ms
14  one.one.one.one (1.1.1.1)  145.450 ms  95.510 ms  95.925 ms

image

另外一个是服务器向本地发送DNS解析结果的数据包,这个数据包的大小比之前请求的数量大得多,这里就可以看到我们之前使用dig得到的内容

image

TCP(传输控制协议)和UDP(用户数据报协议)

在介绍下面的内容之前,我认为有必要向各位解释一下 TCPUDP 之间的区别,这两种都是极为常用的数据传输协议,知乎上的这样两种图我觉得很形象:

image

image

TCP相较于UDP,多了三次握手,保证了数据传输的完整性,但也因此,TCP协议的传输速度不如UDP

在一些实时性要求比较高的应用场景,比如说游戏、视频通话中,使用UDP较多;而对于一些可靠性要求比较高的场景,比如说电子邮件、web浏览(http和https)协议则都是基于TCP

TCP与UDP的详细对比

TCP的三次握手

浏览器通过得到的目标服务器IP地址,开始与服务器建立TCP连接。TCP三次握手的过程如下:

  • 客户端向服务器发送一个SYN(同步)标志的数据包,表示请求建立连接。
  • 服务器接收到后回应一个SYN+ACK(同步确认)标志的数据包,表示同意建立连接。
  • 客户端再发送一个ACK(确认)标志的数据包,确认连接已建立。

image

如果上面的理解过于抽象,你可以把他当作一个人和另外一个人对话的过程:

A想找B进行对话,A先对B说:“你在吗?我能不能和你说话?”。B收到A的信息,对A说:“可以,我们来说话吧!”。A收到B的信息,确认两者可以进行交流,便对B说:“开始说话!”之后就可以正式开始聊天的这个过程

现代网站为了确保安全,一般会使用HTTPS协议进行连接,这里涉及到TLS握手的问题,推荐阅读:什么是 TLS 握手?| Cloudflare

image

发送http请求

一般来说,如果你访问的网站不在上述的HSTS列表之中,浏览器会使用http向服务器进行请求内容,http使用明文传输,非常不安全,攻击者可以篡改你看到的和输入的信息,下面是一个Web服务器(Nginx)的日志:

172.20.0.1 - - [03/Dec/2024:03:46:44 +0000] "GET / HTTP/1.1" 200 2017 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "15x.2x.22x.71"

上面的请求至少泄露了以下信息:

  • 请求IP:172.20.0.1(容器化部署)
  • 请求时间戳:[03/Dec/2024:03:46:44 +0000]
  • 请求方法与请求结果:GET / HTTP/1.1" 200
  • User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36,请求头,写过爬虫的同学肯定不陌生
  • 实际请求IP:15x.2x.22x.71,修改请求头后,实际的IP

根据以上信息我们可以获取到以下信息:

这条日志显示,IP 为 154.28.229.71 的客户端通过 Chrome 浏览器从 macOS 设备向服务器发起了一次请求,访问了根路径 /,并成功接收了大小为 2017 字节的响应内容

前面我们说了,一般支持https的网站会将来自http的请求重定向至https,这样就确保了安全

HTTP 服务器请求处理

浏览器根据用户的请求构造请求头,发送到目标服务器,请求头可能存在以下信息:

  • 请求行:包括请求方法(如 GETPOST)、目标路径(如 /)、使用的协议版本(如 HTTP/1.1
  • 请求头字段:如 Host(目标主机名)、User-Agent(浏览器信息)、Accept(客户端可以接受的内容类型)等
  • 请求体(可选):用于发送数据,如表单提交内容

对于我们在浏览器中输入网址,之后再回车的操作属于GET请求,我们也可以使用curl或者Python中的requests库来发送请求:

zsh
(base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % curl -I https://juniortree.com
HTTP/2 200 
accept-ranges: bytes
alt-svc: h3=":443"; ma=2592000
content-type: text/html
date: Tue, 03 Dec 2024 04:52:05 GMT
etag: "66ba2098-7e1"
last-modified: Mon, 12 Aug 2024 14:47:52 GMT
server: Caddy
server: nginx/1.21.5
strict-transport-security: max-age=31536000; includeSubDomains; preload
content-length: 2017

这里服务器就返回了HTTP响应:

  • HTTP/2 200:协议版本和状态码,表示使用 HTTP/2 协议,状态码 200 OK 表示请求成功,服务器返回了正常的响应内容。
  • content-type: text/html:指明响应的内容类型为 HTML 文档
  • server: Caddyserver: nginx/1.21.5:显示了服务器端使用了两个 Web 服务器,分别是 Caddy 和 Nginx,可能是采用了反向代理
  • content-length: 2017:响应内容的长度为 2017 字节

我们可以尝试不使用-I参数,而是直接获取到最原始的返回内容:

zsh
(base) liueic-aicnal@HUAWEI-MateBook-Go-ARM ~ % curl https://juniortree.com 
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="Access-Control-Allow-Origin" content="*" />
    <!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="icon" href="/images/icon/favicon.ico" />
    <link rel="apple-touch-icon" href="/images/logo/apple-touch-icon.png" />
    <link rel="bookmark" href="/images/logo/apple-touch-icon.png" />
    <link rel="apple-touch-icon-precomposed" sizes="200x200" href="/images/logo/apple-touch-icon.png" />
    <meta name="description" content="小小小站" />
    <meta name="keywords" content="小树,个人主页" />
    <meta name="author" content="小树" />
    <meta name="theme-color" content="#424242" />
    <title>小树的主页</title>
    <!-- HarmonyOS Sans -->
    <!-- 本站 CDN 已开启防盗链,非本站域名不可访问,请更改链接为下方内容,否则自定义字体将失效 -->
    <link rel="stylesheet" href="https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css" />
    <!-- <link rel="stylesheet" href="https://cdn.imsyy.top/gh/imsyy/file/font/HarmonyOS_Sans/regular.min.css" /> -->
    <!-- IE Out -->
    <script>
      if (/*@cc_on!@*/ false || (!!window.MSInputMethodContext && !!document.documentMode))
        window.location.href =
          'https://support.dmeng.net/upgrade-your-browser.html?referrer=' +
          encodeURIComponent(window.location.href);
    </script>
    <script type="module" crossorigin src="/assets/index-1ee3ac7e.js"></script>
    <link rel="stylesheet" href="/assets/index-d6ece963.css">
  <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>

  <body>
    <!-- 主体内容 -->
    <div id="app"></div>
    <!-- noscript -->
    <noscript>
      <div style="text-align: center">请开启 JavaScript</div>
    </noscript>
    
  </body>
</html>

这里就输出了网页的内容,但这些内容还只是以文本或者PlainText的形式输出来了,我们人并不能直接阅读这些所谓代码/资源,之后就需要浏览器进行处理了

浏览器的背后

浏览器在获取到资源之后会做两件事:

  • 解析 —— HTML,CSS,JS
  • 渲染 —— 构建 DOM 树 -> 渲染 -> 布局 -> 绘制

由于前端并不是本次计算机网络的主要内容,我们就先一笔带过

结语

计算机网络是一个庞大而复杂的系统,单单只靠一次讲座或者简单的讲义是没办法一下子完全覆盖的,在这里我们只能浅显地向大家介绍基础的原理,本文已尽力参考了尽量多和可靠的信息来源,但作者水平有限,如果出现疏漏还请见谅并与我联系

参考文章:

当···时发生了什么?

多张图带你彻底搞懂DNS域名解析过程 | 林小鹿

Root File | IANA

重新思考浏览器输入了 URL 并按下回车之后到底发生了什么——本地 DNS 部分

35 张图解:被问千百遍的 TCP 三次握手和四次挥手面试题 | 博客园

什么是反向代理?| 代理服务器介绍 | Cloudflare

贡献者

The avatar of contributor named as Liueic Aicnal Liueic Aicnal

页面历史