Skip to content

0.0.0.0 和 127.0.0.1 的区别

  • 0.0.0.0:这是一个特殊的 IP 地址,通常用作通配符地址或默认路由。在网络配置中,将 0.0.0.0 用作监听地址时,表示该服务监听所有可用的网络接口或 IP 地址。这样,服务将能够接受来自任何网络接口的连接请求。例如,在服务器配置中,将服务监听 0.0.0.0 可以使该服务对外部网络可见,能够接受来自所有网络接口的连接请求。
  • 127.0.0.1:这是本地回环地址(loopback address),也称为本地主机或环回地址。它是计算机上的特殊地址,用于在本地主机上进行网络通信。当你在计算机上访问 127.0.0.1,实际上是在与本地计算机进行通信,而不是通过网络连接到其他计算机。一般来说,将 127.0.0.1 用作主机地址时,表示你正在与本地主机上的服务或进程进行通信。

总结:

  • 0.0.0.0 是一个通配符地址,表示监听所有可用的网络接口或 IP 地址。
  • 127.0.0.1 是本地回环地址,用于在本地主机上进行网络通信。

JWT(JSON Web Token)

一种用于在网络应用中传递信息的开放标准(RFC 7519)。它是一种轻量且安全的身份验证和授权机制,经常用于实现无状态的身份验证(HTTP 是无状态的,因此需要一个介质来确定访问者的信息)

JWT 由三个部分组成,通过点号(.)分隔开:

  • Header(头部):包含描述 JWT 的元数据和算法信息的 JSON 对象。通常包括使用的签名算法(例如 HMAC SHA256 或 RSA)和令牌类型(例如 JWT)。
  • Payload(负载):包含要传输的声明或数据的 JSON 对象。声明是有关实体(通常是用户)和其他数据的声明性语句。例如,它可以包含用户的身份信息、权限等。
  • Signature(签名):使用头部和负载、以及提供的密钥,通过指定的签名算法生成的签名字符串。用于验证令牌的完整性和身份验证。

http1.0、http1.1、http2 的区别

  1. 在http1.0h协议中,一个Request一个Response,这次http请求就结束了
  2. 在http1.1中进行了改进,WebSocket有一个connection:Keep-alive,也就是说,在一个http连接中,可以发送多个Request,接收多个Response。
  3. http2.0中:
    • 允许多路复用:多路复用允许同时通过单一的HTTP/2连接发送多重请求-响应信息。改善了:在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制(连接数量),超过限制会被阻塞。
    • 二进制分帧:HTTP2.0会将所有的传输信息分割为更小的信息或者帧,并对他们进行二进制编码
    • 首部压缩

HTTPS

HTTPS的端口号是443,HTTP的端口号是80,除了这点与http不同之外,其他的都完全沿用HTTP。那么HTTPS是如何做到安全的呢?实现方式就在于这个“S”上。HTTPS的下层协议是SSL/TLS。也就是说HTTPS是身披SSL外壳的HTTP,即HTTP+加密+认证+完整性保护=HTTPS。

在交换密钥阶段使用非对称加密的方式,之后建立通信交换报文阶段则使用对称加密方式。

为什么要有HTTPS?

因为HTTP是不安全的。

  1. 机密性 HTTP在通信过程中使用明文,这使得通信过程可能会被窃听。为了防止被窃听,最常见的处理方式就是加密。加密方式如下:
    • 通信加密:HTTP协议中没有加密机制,可以使用SSL或者TSL来进行加密;
    • 内容的加密:对通信内容进行加密,将报文中所包含的内容进行加密
  2. 完整性 由于HTTP协议无法验证报文的完整性,因此数据在传输过程中可能已经遭到中间人攻击,导致报文被篡改。
  3. 身份认证 HTTP协议中不会对请求和应答的双方进行身份确认,所以身份有可能遭遇伪装。HTTPS的SSL不仅提供加密服务,还提供证书,用来确定通信方。证书是由值得信任的第三方机构办法,伪造证书异常困难,所以只要能够确认通信方持有的证书,则可以确认对方身份。
什么是 SSL/TLS?

SSL即安全套接层,是一个非常好的安全通信协议,其发展到v3版本的时候,互联网工程组将其改名为TLS传输层安全,目前应用最广泛的版本是1.2,除了HTTP,SSL/TLS还承接了其他应用协议,比如FTP=>FTPS等。

HTTPS 链接的建立过程

在HTTP协议中,建立连接后会立即发送请求报文,但是HTTPS还需要另外一个“握手”的过程,即TLS握手。

  1. 浏览器发送Client Hello消息,信息如下:
    • 客户端支持的SSL/TLS版本号,如TLS1.2版本
    • 支持的密码套件,如 ECDHE
    • 客户端产生的随机数C,用于生成后续的会话密钥
  2. 服务器收到Client Hello消息后,会发送Server Hello
    • 确实SSL/TLS协议版本,如果浏览器不支持,则关闭加密通信
    • 确认密码套件列表,选择最合适的加密算法,如ECDHE
    • 服务器产生的随机数S,用于生成后续的会话密钥
    • 服务端为了证明身份,把证书也发送给客户端
  3. 客户端回应,Client Key Exchange。客户端收到服务器的消息后,用浏览器或者系统中的CA公钥验证数字证书的真实性,如果证书没问题,客户端从数字证书中取出服务器的公钥,用其加密报文。
    • 一个随机数,该随机数会被上面提到的服务器的公钥加密,以防被黑客破解。这个随机数加上上文生成的其他两个随机数,使用会话中约定的加密算法,会各自生成加密会话的主密钥。
    • 加密通信算法改变通知,随后的信息都将用会话密钥加密通信
    • Finished消息,结束通知。把之前所有发送的数据做一个摘要再加密一下,让服务器做验证
  4. 服务器的最后回应 - 加密通信算法改变通知 - Finished消息,结束通知。把之前所有发送的数据做一个摘要再加密一下,让客户端做验证
常见面试题汇总

Q: 为什么需要证书?

A: 防止“中间人”攻击,确定会话双方的身份

Q: 使用 HTTPS还会被抓包吗?

A: 可以被抓包,只不过抓包后看不到明文,无法篡改

Q: HTTPS的加密过程是怎么样的?

A: 客户端向服务端索要并验证其公钥,用公钥对TLS握手过程中产生的随机数进行加密生成会话密钥,双方采用会话密钥进行加密通信。

Q: HTTPS 握手过程中,客户端如何验证证书的合法性 A: 数字证书包括序列号、用途、颁发者、有效时间、公钥,如果只是简单的将这些信息发送给浏览器,中间人可以很轻易的将公钥改成自己的公钥,解决办法就是使用数字签名。将证书的信息生成摘要,将摘要用CA的私钥进行加密,生成数字签名。服务器将数字证书和数字签名一同发送给浏览器,因为有数字签名,所以数字证书无法被中间人修改(修改后的话会导致摘要变了,数字签名实现了不可否认)。浏览器拿到数字证书,根据“证书链”去验证其可信度。

HTTP 缓存

缓存方式:强缓存, 协商缓存

强缓存优先级要大于协商缓存

强缓存

在设置时间到期之前,客户端直接使用缓存资源,不再询问服务器

javascript
app.get('/api', (req, res) => {
    res.setHeader('Expires', new Date('2024-5-1 20:00:00').toUTCString())
    res.end('hello')
})
协商缓存

在设置时间到期之前,客户端直接使用缓存资源,不再询问服务器

javascript
// public 任务服务器都可以缓存(代理服务器,CDN)
// private 只能浏览器缓存,不包括代理服务器
// max-age 缓存的时间,单位为 秒
// Expires、Cache-control 同时出现,max-age 优先
app.get('/api', (req, res) => {
    res.setHeader('Cache-Control', 'public, max-age=60')
    res.end('hello')
})

// 协商缓存(Last-Modified)
function getModifyTime() {
    return fs.statSync('./index.js').mtime.toISOString() // 获取文件最后修改时间
}
app.get('/api', (req, res) => {
    res.setHeader('Cache-Control', 'no-cache') // 告诉浏览器走协商缓存(no-store 不走任何缓存)
    const ifModifiedSince = req.headers['if-modified-since']
    const modifyTime = getFileModifyTime()
    if (ifModifiedSince === modifyTime) {
        res.statusCode = 304
        res.end() // 直接 end 就行,指示客户端发送的请求的资源未发生变化,可以继续使用客户端缓存的副本
        return
    }
    res.setHeader('Last-Modified', modifyTime)
    res.end('hello')
})

// 协商缓存(ETag), ETag 优先级比 Last-Modified 高
function getFileHash() {
    return crypto.createHash('sha256').update(fs.readFileSync('index.js')).digest('hex')
}

app.get('/api', (req, res) => {
    res.setHeader('Cache-Control', 'no-cache, max-age=2592000') // 表示走协商缓存
    const etag = getFileHash()
    const ifNoneMatch = req.headers['if-none-match']
    if (ifNoneMatch === etag) {
        res.sendStatus(304)
        return
    }
    res.setHeader('ETag', etag)
    res.send('Etag')
})
GPT

HTTP 缓存是 Web 性能优化的重要组成部分,它可以减少网络请求、降低服务器负载、加快页面加载速度。HTTP 缓存主要分为两大类:

  • 强缓存 (Strong Caching)
  • 协商缓存 (Conditional Caching)

1. 强缓存 (Strong Caching)

  • 原理: 浏览器直接从本地缓存中读取资源, 向服务器发送请求。
  • 控制方式: 通过 HTTP 响应头中的 Cache-ControlExpires 字段来控制。
  • 优先级: Cache-Control 的优先级高于 Expires

Cache-Control 字段 (HTTP/1.1):

  • public: 表示响应可以被任何对象(包括客户端、代理服务器等)缓存。
  • private: 表示响应只能被客户端缓存,不能被代理服务器缓存。
  • no-cache: 可以使用缓存,但必须先向服务器验证缓存是否仍然有效(即协商缓存)。
  • no-store: 完全禁止缓存(客户端和代理服务器都不缓存)。
  • max-age=<seconds>: 缓存的最大有效时间(单位:秒)。从响应时间开始计算。
  • s-maxage=<seconds>: 类似于 max-age,但仅适用于共享缓存(例如代理服务器)。
  • must-revalidate: 缓存过期后,必须向服务器验证缓存是否仍然有效。
  • proxy-revalidate: 类似于 must-revalidate,但仅适用于共享缓存。
  • immutable: 表示响应正文不会随着时间发生改变, 在有效期内, 可以放心使用缓存.

Expires 字段 (HTTP/1.0):

  • 指定一个具体的过期日期和时间(GMT 格式)。
  • 缺点:依赖于客户端的系统时间,如果客户端时间不准确,会导致缓存失效。

示例:

shell
Cache-Control: public, max-age=3600  // 缓存 1 小时
Expires: Thu, 01 Dec 2024 16:00:00 GMT // 过期时间

流程:

  1. 浏览器首次请求资源。
  2. 服务器返回资源,并在响应头中设置 Cache-Control 或 Expires。
  3. 浏览器将资源及其过期时间存储在本地缓存中。
  4. 在缓存有效期内,浏览器再次请求相同的资源时,直接从本地缓存中读取,不向服务器发送请求。
  5. 缓存过期后,浏览器才会向服务器发送请求(可能是协商缓存请求)。

2. 协商缓存 (Conditional Caching)

  • 原理: 浏览器向服务器发送一个条件请求,询问服务器资源是否已更新。如果资源未更新,服务器返回 304 Not Modified 响应,浏览器从本地缓存中读取资源;如果资源已更新,服务器返回 200 OK 响应,以及新的资源。
  • 控制方式: 通过 HTTP 请求头中的 If-Modified-Since、If-None-Match 和响应头中的 Last-Modified、ETag 字段来控制。
  • 优先级: ETag / If-None-Match 的优先级高于 Last-Modified / If-Modified-Since。
text
// 首次响应 (200 OK)
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
ETag: "abcdef123456"

// 后续请求 (条件请求)
If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT
If-None-Match: "abcdef123456"

// 服务器响应 (304 Not Modified 或 200 OK)

流程:

  1. 浏览器首次请求资源。

  2. 服务器返回资源,并在响应头中设置 Last-Modified 或 ETag。

  3. 浏览器将资源及其 Last-Modified 或 ETag 值存储在本地缓存中。

  4. 浏览器再次请求相同的资源时,发送带有 If-Modified-Since 或 If-None-Match 头的条件请求。

  5. 服务器根据条件请求头判断资源是否已更新:

    • 如果未更新,返回 304 Not Modified 响应,浏览器从本地缓存中读取资源。
    • 如果已更新,返回 200 OK 响应和新的资源,浏览器更新本地缓存。

强缓存 vs. 协商缓存:

特性强缓存协商缓存
请求不向服务器发送请求向服务器发送条件请求
响应直接从本地缓存读取资源服务器返回 304 Not Modified200 OK
控制Cache-ControlExpiresLast-Modified / If-Modified-SinceETag / If-None-Match
优先级Cache-Control > ExpiresETag / If-None-Match > Last-Modified / If-Modified-Since
适用场景静态资源(图片、CSS、JS 等),且不经常更新动态资源,或需要经常验证是否更新的资源

HTTP2

HTTP/2(HTTP2)是超文本传输协议(HTTP)的下一个主要版本,它是对 HTTP/1.1 协议的重大改进。HTTP/2 的目标是改善性能、效率和安全性,以提供更快、更高效的网络通信

HTTP2 协议在控制台上显示的协议值是 h2

区别
  • 多路复用(Multiplexing)

    HTTP/2 支持在单个 TCP 连接上同时发送多个请求和响应。这意味着可以避免建立多个连接,减少网络延迟,提高效率。

  • 二进制分帧(Binary Framing)

    在应用层(HTTP2)和传输层(TCP or UDP)之间增加了二进制分帧层,将请求和响应拆分为多个帧(frames)。这种二进制格式的设计使得协议更加高效,并且容易解析和处理。

  • 头部压缩(Header Compression)

              HTTP/2 使用首部表(Header Table)和动态压缩算法来减少头部的大小。这减少了每个请求和响应的开销,提高了传输效率。
    
              `请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销`
    

    :::

实现
javascript
import fs from 'node:fs'
import http2 from 'node:http2'

const server = http2.createSecureServer({
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.crt'),
})

server.on('stream', (stream, headers) => {
    stream.respond({
        'content-type': 'text/html; charset=utf-8',
        ':status': 200,
    })
    stream.on('error', (err) => {
        console.log(err)
    })
    stream.end(`
      <h1>http2</h1>
    `)
})

server.listen(80, () => {
    console.log('server is running on port 80')
})

WebSocket

WebSocket的出现,使得浏览器具备了实时双向通信的能力;它基于TCP传输协议,并复用HTTP的握手通道

  • 实现代码

    服务端
    javascript
    const app = require('express')()
    const server = require('node:http').Server(app)
    const WebSocket = require('ws')
    
    const wss = new WebSocket.Server({ port: 8080 })
    
    wss.on('connection', (ws) => {
        console.log('server: receive connection.')
    
        ws.on('message', (message) => {
            console.log('server: received: %s', message)
        })
    
        ws.send('world')
    })
    
    app.get('/', (req, res) => {
        res.sendfile(`${__dirname}/index.html`)
    })
    
    app.listen(3000)
    客服端
    javascript
    const ws = new WebSocket('ws://localhost:8080')
    ws.onopen = function () {
        console.log('ws onopen')
        ws.send('from client: hello')
    }
    ws.onmessage = function (e) {
        console.log('ws onmessage')
        console.log(`from server: ${e.data}`)
    }
  • 如何建立连接

    WebSocket复用了HTTP的握手通道。具体指的是,客户端通过HTTP请求与WebSocket服务端协商升级协议。协议升级完成后,后续的数据交换则遵照WebSocket的协议

    http
    GET / HTTP/1.1
    Host: localhost:8080
    Origin: http://127.0.0.1:3000
    Connection: Upgrade  # 表示要升级协议
    Upgrade: websocket   # 表示要升级到websocket协议。
    Sec-WebSocket-Version: 13 # 表示websocket的版本。如果服务端不支持该版本,需要返回一个Sec-WebSocket-Versionheader,里面包含服务端支持的版本号。
    Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw== # 与后面服务端响应首部的Sec-WebSocket-Accept是配套的,提供基本的防护,比如恶意的连接,或者无意的连接。

URL地址末尾加不加”/“有什么区别

URL(统一资源定位符) :用于唯一标识互联网资源,如网页、图片、API等

URL 形式作用影响
https://example.com/folder/目录通常返回 folder/ 下的默认文件,如 index.html,相对路径解析基于 folder/
https://example.com/folder资源(或重定向)可能被解析为文件,或者服务器重定向到 folder/,相对路径解析可能错误
https://api.example.com/data/API 路径可能与 https://api.example.com/data 表现不同,具体由 API 设计决定

TCP

在计算机网络中,TCP(传输控制协议)是实现可靠数据传输的核心协议之一。它广泛应用于各种网络应用中,如Web浏览、文件传输和电子邮件等。

  1. TCP连接的建立(三次握手)

    TCP协议通过三次握手建立可靠的点对点连接。三次握手的过程如下:

    1. 第一次握手:客户端发送一个SYN(同步)包到服务器,并进入SYN_SENT状态,等待服务器确认。这个包中包含一个初始序列号seq,表示客户端希望与服务器建立连接。

    2. 第二次握手:服务器收到SYN包后,回应一个SYN+ACK(同步+确认)包给客户端,此时服务器进入SYN_RCVD状态。这个包中包含服务器的初始序列号seq,以及对客户端SYN包的确认号ack

    3. 第三次握手:客户端收到服务器的SYN+ACK包后,向服务器发送一个ACK(确认)包,并进入ESTABLISHED状态。这个包中包含对服务器SYN包的确认号ack

    连接建立完成:服务器收到客户端的ACK包后,也进入ESTABLISHED状态,至此,连接建立完成。

    alt text

    意义

    • 确保双方都准备好进行数据传输:通过三次握手,客户端和服务器可以确认彼此的存在,并准备好进行数据传输。

    • 防止已失效的连接请求干扰:如果客户端发送的SYN包在网络中延迟到达服务器,服务器可能会误以为这是一个新的连接请求。通过三次握手,可以避免这种情况的发生。


  1. TCP数据的传输

    TCP协议通过分段发送和确认机制实现可靠的数据传输。

    分段发送: TCP协议将数据分成多个数据段(segments)进行发送。每个数据段包含一个序列号(seq),用于标识数据段的顺序。

    可靠传输: 为了解决数据报丢失、数据报错乱等问题,TCP协议要求接收方收到数据报后,必须对数据报进行确认(ACK)。确认报文包含期望下一次接收的数据报序号(ack)。如果发送方长时间没有收到确认报文,会判定数据报丢失或错误,然后重发。

    alt text


  1. TCP连接的销毁(四次挥手)

    当数据传输完成后,需要关闭连接。TCP协议通过四次挥手来销毁连接。四次挥手的过程如下:

    1. 第一次挥手:客户端发送一个FIN(结束)包给服务器,表示客户端已经完成数据发送,并希望关闭连接。客户端进入FIN_WAIT_1状态,等待服务器返回ACK包。

    2. 第二次挥手:服务器收到FIN包后,发送一个ACK包给客户端,表示服务器已经收到客户端的关闭请求。服务器进入CLOSE_WAIT状态,客户端进入FIN_WAIT_2状态。

    3. 第三次挥手:服务器完成数据发送后,发送一个FIN包给客户端,表示服务器也已经完成数据发送,并希望关闭连接。服务器进入LAST_ACK状态。

    4. 第四次挥手:客户端收到服务器的FIN包后,发送一个ACK包给服务器,表示客户端已经收到服务器的关闭请求。客户端进入TIME_WAIT状态,等待足够长的时间(2MSL)以确保服务器收到ACK包。最后,客户端回到CLOSED状态,释放网络资源。

    服务器收到客户端的ACK包后,也回到CLOSED状态,释放网络资源。

    alt text

    意义

    确保数据传输的完整性:通过四次挥手,可以确保双方都完成数据发送,并且确认对方已经收到所有数据。

    防止资源泄漏:通过四次挥手,可以确保连接被正确关闭,避免网络资源的泄漏。

  2. HTTP与TCP的关系

    HTTP(超文本传输协议)是应用层协议,用于定义Web内容的格式。TCP是传输层协议,用于实现可靠的数据传输。HTTP协议使用TCP协议完成消息的可靠传输。