面试题[HTTP]
1. HTTP 基础
1.1 什么是 HTTP
HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最广泛的一种网络协议,它定义了客户端(如浏览器)和服务器之间如何通信,用于传输网页、图片、视频等超文本数据。
- 核心特点
- 请求-响应模型:客户端发送一个请求,服务器返回对应的响应。
- 无状态:每个请求独立,服务器不会记住之前的请求(但可通过Cookie、Session等方式模拟状态)。
- 基于TCP:默认使用80端口(HTTPS使用443端口)。
- 明文传输(HTTP本身不加密,安全版本HTTPS则加密)。
- 发展历史
- HTTP/1.0:简单,每个请求建立新连接
- HTTP/1.1:引入持久连接、管道化
- HTTP/2:多路复用、头部压缩、服务器推送
- HTTP/3:基于QUIC(UDP),减少延迟
- HTTP方法
- HTTP状态码
1.2 HTTP 各版本的区别
按时间顺序对比主要版本的核心区别:
- HTTP/0.9(1991年)—— 最简单的原型
- 只有 GET 方法,且响应只能是 HTML 文本。
- 无状态、无头部,服务器响应后立即关闭连接。
- 没有状态码(只有实际内容),没有版本号标识。
- HTTP/1.0(1996年)—— 扩展能力
- 引入 请求方法(POST、HEAD)、状态码(200、404等)、头部字段(Content-Type、User-Agent等)。
- 支持 缓存控制(Expires、If-Modified-Since)。
- 缺点:每次请求建立一次 TCP 连接,连接无法复用,效率低(队头阻塞、握手开销大)。
- HTTP/1.1(1997年)—— 标准化的主力版本
- 持久连接(Connection: keep-alive):默认复用同一 TCP 连接处理多个请求/响应,减少握手延迟。
- 管道化(pipelining):允许客户端在收到前一个响应前连续发送多个请求,但服务器仍须按顺序响应,队头阻塞未完全解决。
- 分块传输编码(chunked transfer):动态生成内容时可分块发送。
- 新增更多方法:PUT、PATCH、DELETE、OPTIONS、TRACE、CONNECT。
- Host 头部:支持同一 IP 上托管多个域名(虚拟主机)。
- 更好的缓存机制(Cache-Control、ETag)。
- HTTP/2(2015年)—— 性能革命
- 二进制分帧层:将 HTTP 消息拆分为更小的帧(HEADERS、DATA等),不再是文本协议。
- 多路复用(Multiplexing):在一个 TCP 连接上交错发送多个请求/响应的帧,彻底解决 HTTP/1.x 的队头阻塞。
- 头部压缩(HPACK):减少重复头部开销。
- 服务器推送(Server Push):服务器可主动向客户端推送资源(如 HTML 中的 CSS/JS)。
- 流优先级:客户端可指定请求的优先级。
- 要求加密(虽未强制,但主流浏览器仅支持基于 TLS 的 HTTP/2,即 h2)。
- HTTP/3(2022年)—— 突破 TCP 的限制
- 底层传输由 TCP 改为 QUIC 协议(基于 UDP)。
- 解决 TCP 的队头阻塞:即使某个数据包丢失,也不影响其他流的数据交付。
- 0-RTT 快速连接:首次握手后,后续连接可立即发送数据,大幅减少延迟。
- 内置加密和传输可靠性,QUIC 本身提供类似 TLS 1.3 的加密和纠错机制。
- 连接迁移:当用户从 WiFi 切换到移动网络时,连接 ID 不变,无需重建连接。
关键区别总结表
| 特性 | HTTP/1.0 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|---|
| 连接复用 | 无(每请求重建) | 持久连接(默认) | 多路复用(单连接) | 多路复用(单连接) |
| 队头阻塞 | 严重 | 请求级(管道化无效) | 无(帧级别) | 无(流级别,基于UDP) |
| 头部压缩 | 无 | 无 | HPACK | QPACK |
| 服务器推送 | 无 | 无 | 有 | 有 |
| 传输层 | TCP | TCP | TCP | QUIC (UDP) |
| 加密要求 | 无 | 无(HTTPS可选) | 实际强制(TLS) | 强制(QUIC自带) |
| 连接握手(新连接) | 3次TCP + 多RTT | 3次TCP + 多RTT | 3次TCP + TLS | 0-1 RTT(QUIC) |
| 典型端口 | 80 | 80 | 443(h2) | 443 |
实际使用建议
- 当前仍广泛使用 HTTP/1.1,兼容性最好,适用于简单 API 或老旧系统。
- HTTP/2 是现代 Web 的首选(配合 TLS),能极大提升页面加载速度。
- HTTP/3 适用于对延迟敏感、弱网环境(如移动 APP、视频直播),但需要服务器和客户端同时支持(目前约 30% 流量已使用)。
1.3 HTTP 缓存
HTTP 缓存是一种减少冗余数据传输、降低服务器负载、提升页面加载速度的重要机制。它通过复用之前获取的资源,避免重复向源服务器请求相同内容。核心概念:两种缓存策略。
- 强缓存(强制缓存)
- 无需与服务器通信,直接使用本地缓存。
- 由响应头中的
Cache-Control(HTTP/1.1)或Expires(HTTP/1.0,已老旧)控制。 - 状态码:强缓存命中时,浏览器直接返回
200 (from disk cache)或200 (from memory cache),无网络请求。
- 协商缓存(对比缓存)
- 与服务器通信,询问资源是否变更。若未变更,服务器返回
304 Not Modified(无响应体),节省带宽;若已变更,返回新资源(200)。 Last-Modified+If-Modified-Since:- 服务器返回
Last-Modified: <最后修改时间>,浏览器后续请求携带If-Modified-Since: <该时间>。 - 缺点:时间精度只能到秒,毫秒级变动无法感知;文件内容未改但时间变化会误触发更新。
- 服务器返回
ETag+If-None-Match(优先级更高):- 服务器返回一个唯一标识(如文件哈希),浏览器下次请求携带
If-None-Match: <该标识>。 可精确判断内容是否变化,推荐使用。
- 服务器返回一个唯一标识(如文件哈希),浏览器下次请求携带
- 与服务器通信,询问资源是否变更。若未变更,服务器返回
- 常见问题
- Ctrl+F5(强制刷新):忽略所有缓存,请求头携带
Cache-Control: no-cache和Pragma: no-cache,协商缓存也失效。 - 普通刷新(F5):跳过强缓存,但会携带协商缓存头(
If-Modified-Since/If-None-Match)。 - 后退/前进:可能直接使用强缓存。
- Ctrl+F5(强制刷新):忽略所有缓存,请求头携带
1.4 HTTP 方法
HTTP 方法用于指示对指定资源执行的操作。每个请求方法都有其语义,并且一些方法具有 安全(不改变服务器状态)和 幂等(多次执行效果相同)的特性。
| 方法 | 安全性 | 幂等性 | 说明 |
|---|---|---|---|
| GET | ✅ 安全 | ✅ 幂等 | 请求指定的资源。不应有副作用,仅用于获取数据。 |
| HEAD | ✅ 安全 | ✅ 幂等 | 与 GET 类似,但服务器只返回响应头(无响应体),常用于检查资源是否存在或获取元信息(如 Content-Length)。 |
| POST | ❌ 不安全 | ❌ 不幂等 | 向服务器提交数据(如表单、上传文件),导致服务器状态变化。每次请求可能产生不同结果(例如多次提交生成多个订单)。 |
| PUT | ❌ 不安全 | ✅ 幂等 | 用请求的载荷替换目标资源的所有内容。若资源不存在,部分实现会创建它。多次相同的 PUT 请求效果一致。 |
| DELETE | ❌ 不安全 | ✅ 幂等 | 删除指定的资源。 |
| PATCH | ❌ 不安全 | ❌ 不幂等(通常) | 对资源进行部分修改。由于修改内容可能是增量(如 JSON Patch),多次相同请求可能效果不同,因此一般视为非幂等。 |
| OPTIONS | ✅ 安全 | ✅ 幂等 | 返回服务器支持的 HTTP 方法(通过 Allow 响应头),用于 CORS 预检请求。 |
| CONNECT | ❌ 不安全 | ❌ 不幂等 | 将连接转换为透明的 TCP 隧道,通常用于代理与 HTTPS 服务器建立隧道(由代理使用)。 |
| TRACE | ✅ 安全 | ✅ 幂等 | 回显服务器收到的请求内容,主要用于调试(可能引发安全风险,许多生产环境禁用)。 |
额外说明
- GET vs POST:GET 参数通过 URL 传递,长度有限且可见;POST 参数在请求体中,更安全(但非加密)且无大小限制。不要用 GET 执行修改操作(如删除)。
- PUT vs POST:PUT 是“完整替换”,客户端知道资源最终 URL;POST 是“创建附属资源”或“处理非幂等操作”,由服务器决定最终 URL。
- PATCH:通常使用
application/merge-patch+json或application/json-patch+json格式,描述变更指令。
实际开发中,RESTful API 主要使用 GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS。
1.5 HTTP 状态码
HTTP 状态码(Status Code)是服务器对客户端请求的响应结果标识,由三位数字组成,首位数字定义了响应类别。
| 分类 | 范围 | 含义 | 描述 |
|---|---|---|---|
| 1xx | 100–101 | 信息响应 | 请求已接收,继续处理 |
| 2xx | 200–207 | 成功响应 | 请求成功完成 |
| 3xx | 300–308 | 重定向 | 需要进一步操作以完成请求 |
| 4xx | 400–451 | 客户端错误 | 请求有误或无法处理 |
| 5xx | 500–511 | 服务器错误 | 服务器处理请求时出错 |
常见状态码详解
1xx 信息类
100 Continue:客户端应继续发送请求(用于 Expect: 100-continue)101 Switching Protocols:服务器同意升级协议(如 WebSocket)
2xx 成功类
200 OK:请求成功,返回内容(取决于方法:GET返回资源,POST返回结果)201 Created:资源创建成功(常见于 POST/PUT),Location 头可指向新资源202 Accepted:请求已接收但未处理完(异步处理)204 No Content:成功但无返回体(常用于 DELETE、PUT 更新不返回数据)206 Partial Content:返回部分内容(用于断点续传、分块下载),配合 Range 头
3xx 重定向类
301 Moved Permanently:资源永久移动到新 URL(后续应使用新地址)302 Found(HTTP/1.0 临时重定向):资源临时位于另一 URL,后续仍用原地址303 See Other:重定向到新 URL,且必须用 GET 请求(常用于 POST 后跳转结果页)304 Not Modified:资源未修改,可使用缓存(协商缓存命中时返回,无响应体)307 Temporary Redirect(HTTP/1.1):与 302 类似,但不允许改变请求方法(保持 POST→POST)308 Permanent Redirect(HTTP/1.1):与 301 类似,但不允许改变请求方法
注意:302 在实践中有歧义,部分客户端会将 POST 改为 GET,推荐使用 303 或 307。
4xx 客户端错误类
400 Bad Request:服务器无法理解请求(语法错误、参数错误、请求头过大等)401 Unauthorized:需要身份验证(未登录或凭证无效),响应头应包含WWW-Authenticate403 Forbidden:服务器理解请求但拒绝执行(无权限,且不提供登录方式)404 Not Found:资源不存在(或服务器故意掩盖存在性)405 Method Not Allowed:请求方法不被允许(如 GET 要求但接口只支持 POST),响应头Allow: GET, HEAD406 Not Acceptable:请求的Accept头要求的内容类型服务器无法提供408 Request Timeout:客户端未在服务器等待时间内发送完整请求409 Conflict:请求与当前资源状态冲突(如文件编辑冲突)410 Gone:资源已永久删除,类似 404 但明确表示“不再可用”413 Payload Too Large:请求体超过服务器限制415 Unsupported Media Type:请求的 Content-Type 不被支持418 I'm a teapot:愚人节彩蛋,源自茶壶超文本咖啡壶控制协议( RFC 2324)422 Unprocessable Content(WebDAV):语义正确但无法处理(例如参数校验失败)429 Too Many Requests:请求频率超限(常用于限流)
5xx 服务器错误类
500 Internal Server Error:服务器内部错误(通用错误,无法定位具体问题)501 Not Implemented:服务器不支持请求的功能(如某个方法未实现)502 Bad Gateway:网关/代理服务器收到上游无效响应(如 PHP-FPM 挂掉)503 Service Unavailable:服务器暂时不可用(超载或维护),可包含Retry-After头504 Gateway Timeout:网关/代理等待上游响应超时505 HTTP Version Not Supported:服务器不支持请求中使用的 HTTP 版本
2. HTTP 进阶
2.1 Restful API
RESTful API 是一种遵循 REST(Representational State Transfer,表现层状态转移)架构风格的 API 设计规范。它不是协议或标准,而是一组设计原则,使 API 更简洁、可扩展、易理解。
RESTful API 的核心思想是:利用 HTTP 协议的能力,把一切操作抽象为对资源的管理。
RESTful API 核心设计要素:
资源(Resource)
- 一切都是资源,用 URI 标识(名词,而非动词)。
- 示例:
/users、/orders/123、/users/456/orders
HTTP 方法(动作)
方法 用途 示例 GET 获取资源 GET /users→ 用户列表POST 创建子资源 POST /users→ 新增用户PUT 完整替换资源(幂等) PUT /users/123→ 整体更新用户PATCH 部分更新(非幂等) PATCH /users/123→ 修改邮箱DELETE 删除资源 DELETE /users/123→ 删除用户
RESTful API 最佳实践:
- URI 命名规范
- 使用 复数名词:
/products而非/product - 多层路径:
/authors/12/books - 避免动词:❌
/getUsers,✅/users - 用
/表示层级,用-或_提高可读性,全部小写 - 过滤/排序/分页使用查询参数:
/users?role=admin&page=2&sort=name
- 使用 复数名词:
- 安全注意事项
- 敏感操作使用 HTTPS。
- 认证常用方式:JWT、OAuth 2.0、API Key。
- 对写操作进行 CSRF 防护;限制请求频率(rate limiting)。
2.2 HTTP 和 HTTPS 的区别
HTTP 与 HTTPS 的核心区别在于安全性,具体体现在以下几个方面:
| 对比维度 | HTTP | HTTPS |
|---|---|---|
| 加密传输 | 明文传输,数据不加密 | 使用 SSL/TLS 协议加密,数据密文传输 |
| 端口号 | 默认 80 | 默认 443 |
| 身份验证 | 无服务器身份验证 | 需向 CA(证书颁发机构)申请数字证书,验证服务器身份 |
| 篡改/监听风险 | 高(中间人可轻松窃听、篡改) | 低(加密防窃听,摘要防篡改) |
| 性能 | 快(无加密握手) | 略慢(增加 TLS 握手及加解密损耗,但 HTTP/2 等可优化) |
| URL 前缀 | http:// | https:// |
| SEO 与浏览器标识 | 主流浏览器标记为“不安全” | 显示安全锁图标,利于搜索排名 |
- 工作原理简述
- HTTP:直接基于 TCP 传输纯文本,请求/响应可被任意中间节点读取。
- HTTPS = HTTP + SSL/TLS:先进行 TLS 握手(协商加密算法、交换证书、生成会话密钥),随后所有 HTTP 数据均用会话密钥加密传输。
- 实际建议
- 任何涉及登录、支付、个人信息等敏感数据的场景必须使用 HTTPS。
- 现代 Web 推荐全站 HTTPS,即使无敏感信息(可防止劫持、运营商广告注入)。
- 启用 HTTPS 需要证书(可用 Let‘s Encrypt 免费获取)。
2.3 HTTP 和 TCP 长链接的区别
要理解 HTTP 长连接 与 TCP 长连接 的区别,首先需要明确:HTTP 长连接本质上还是基于 TCP 的,只是两者关注的层次和细节不同。
基本定义
- HTTP 长连接(通常称为 HTTP Keep‑Alive 或持久连接):在同一个 TCP 连接上连续发送多个 HTTP 请求/响应,避免每次请求都重新进行 TCP 三次握手和 TLS 握手。
- TCP 长连接:指 TCP 连接建立后不立即关闭,而是保持打开状态,供上层应用(不限于 HTTP)多次发送数据。通常需要应用层或操作系统发送“心跳”来维持。
核心区别
对比维度 HTTP 长连接 TCP 长连接 协议层次 应用层(HTTP 协议中的优化机制) 传输层(TCP 协议本身的连接特性) 控制方式 通过 HTTP 头部 Connection: keep-alive、Keep-Alive: timeout=5, max=100等协商由应用程序或操作系统通过 SO_KEEPALIVE选项(TCP Keep‑Alive)或自定义心跳包来维持作用范围 仅在 HTTP 请求/响应之间复用连接 可用于任何基于 TCP 的协议(HTTP、SMTP、自定义协议等) 典型超时设定 通常较短(几秒到几分钟),由服务器配置(如 Nginx 的 keepalive_timeout)通常较长(几小时甚至永久),或通过应用层心跳保活 连接关闭 一方发送 Connection: close或达到超时/最大请求数后主动关闭需要应用明确调用 close(),或因为错误/超时而被动关闭对请求的处理 一个 HTTP 长连接中,请求必须按照发送顺序依次响应(HTTP/1.1 存在队头阻塞) TCP 长连接可以承载任意顺序的二进制数据帧(如 HTTP/2 多路复用) 常见误解澄清
- HTTP 长连接 ≠ TCP 长连接:HTTP Keep‑Alive 只是复用 TCP 连接的一种应用层约定;而 TCP 长连接是泛指连接被持续使用,不限于 HTTP。
- TCP Keep‑Alive ≠ HTTP Keep‑Alive:
- TCP Keep‑Alive 是操作系统的空闲探测机制(默认通常关闭,开启后每隔一段时间发送空探测包,确认对端是否存活)。
- HTTP Keep‑Alive 是应用层让连接不立即关闭的协商。
- HTTP/2 和 HTTP/3 进一步改变了“长连接”的含义
- HTTP/2 在一个 TCP 连接上实现多路复用,依然是 HTTP 长连接的延伸。
- HTTP/3 基于 QUIC(UDP),不再依赖 TCP 长连接的概念,但内部有自己的连接复用与保活。
总结
- HTTP 长连接是应用层对 TCP 连接的复用策略,目的是节省 HTTP 请求的建连开销。
- TCP 长连接是传输层连接的生命周期特性,可能被任何上层协议使用。
两者互不冲突:HTTP 长连接依赖于 TCP 长连接(不关连),但 TCP 长连接不必用于 HTTP。
3. HTTP 拓展
3.1 除了 HTTP 和 HTTPS,前端开发中还涉及到哪些通信协议
- WebSocket:WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。相比于传统的 HTTP 请求-响应模式,WebSocket 允许服务器主动向客户端发送数据,实现实时通信。在前端开发中,可以使用 WebSocket 协议来建立持久连接,实现实时聊天、实时数据更新等功能。
- WebRTC:WebRTC(Web 实时通信)是一项基于浏览器的实时通信技术,允许在浏览器之间进行点对点的音视频通信和数据传输,而无需借助插件或其他第三方软件。WebRTC 使用了多种协议和 API,包括实时传输协议(RTP)、会话描述协议(SDP)等。前端开发者可以利用 WebRTC 实现音视频通话、屏幕共享等实时通信应用。
- MQTT:MQTT(Message Queuing Telemetry Transport)是一种轻量级的发布/订阅消息传输协议。它被设计用于低带宽、不稳定网络环境下的物联网设备通信。前端开发中,可以利用 MQTT 协议实现与物联网设备的通信,获取传感器数据、控制设备等。
- RESTful API:虽然 REST(Representational State Transfer)本身不是一种通信协议,但它是一种架构风格,常用于设计 Web API。RESTful API 使用标准的 HTTP 方法(如 GET、POST、PUT、DELETE)进行通信,通过请求资源的 URL 来表达操作,并使用 HTTP 状态码表示响应状态。前端开发者可以通过使用 RESTful API 与服务器进行数据交互。
- FTP(File Transfer Protocol):FTP 是一种用于在客户端和服务器之间传输文件的协议。在前端开发中,可以使用 FTP 协议来上传、下载和管理网站文件。
- SSH(Secure Shell):SSH 是一种加密的网络协议,用于远程登录到服务器并执行命令。前端开发人员可以使用 SSH 协议来通过终端或命令行界面连接到远程服务器,进行文件操作、运行程序等任务。
- DNS(Domain Name System):DNS 是一种用于将域名转换为 IP 地址的协议。在前端开发中,当用户输入一个域名时,浏览器会使用 DNS 协议将域名解析为相应的 IP 地址,以便建立与服务器的通信。
3.2 CORS 跨域是如何做的?从协议的角度去讲一下
CORS(跨域资源共享)是一种用于解决浏览器的同源策略限制,允许在不同域名之间进行跨域请求的机制。从协议的角度来看,CORS通过HTTP头部字段进行通信。
以下是CORS的基本工作原理:
- 简单请求:对于简单请求(例如GET、POST、HEAD等),浏览器会在实际发送请求前,自动发送一个预检请求(Preflight request)来获取服务器的许可。预检请求是一个OPTIONS方法的HTTP请求,其中包含一些额外的头部字段。
- 预检请求:预检请求包含了一些关键信息,如请求方法、请求头、请求的目标URL等。服务器收到预检请求后,需要进行验证并返回响应,确认是否允许跨域请求。验证的方式包括检查Origin头部字段、Access-Control-Request-Method头部字段、Access-Control-Request-Headers头部字段等。
- 响应处理:如果服务器确认允许跨域请求,它会在响应中返回一些特定的头部字段,以授权浏览器访问响应的内容。这些头部字段包括Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等。
- 安全限制:浏览器会根据响应头部字段进行安全限制,只有在响应中包含了正确的头部字段,浏览器才会允许跨域请求,并将响应的内容返回给前端。
需要注意的是,CORS机制只对浏览器发起的异步请求(如Ajax请求)有效,而对于直接在浏览器地址栏中输入URL的同步请求,则不会触发CORS限制。通过CORS机制,服务器可以灵活地控制哪些域名可以访问其资源,从而提高Web应用程序的安全性和可扩展性。
从协议的角度来看,CORS是通过HTTP头部字段进行通信的。具体来说,CORS使用了以下几个HTTP头部字段:
- Origin:表示浏览器发起请求的源地址(协议+域名+端口号),例如http://www.example.com。
- Access-Control-Request-Method:表示浏览器实际发送的请求方法,例如GET、POST、PUT等。
- Access-Control-Request-Headers:表示浏览器实际发送的请求头部信息,例如Content-Type、Authorization等。
- Access-Control-Allow-Origin:表示服务器允许请求的源地址,可以是单个域名、多个域名、或者通配符*。
- Access-Control-Allow-Methods:表示服务器允许请求的方法,例如GET、POST、PUT等。
- Access-Control-Allow-Headers:表示服务器允许请求的头部信息,例如Content-Type、Authorization等。
当浏览器发起跨域请求时,它会自动在请求头部中添加Origin字段,告诉服务器请求的源地址。服务器在收到请求后,检查Origin字段,如果认为请求合法,则在响应头部中添加Access-Control-Allow-Origin、Access-Control-Allow-Methods和Access-Control-Allow-Headers字段,授权浏览器访问响应的内容。