HTTP 精读:方法、状态码、头部与「无状态」到底是什么
把前后端天天打交道的 HTTP 一次讲透:请求与响应的结构、五大类状态码、常见头部、为什么说 HTTP 无状态,以及 cookie-session-token 三代身份方案是怎么演进来的
- 看懂一次 HTTP 请求/响应的完整结构,分清请求行、头部、主体
- 记住五大类状态码与部署排障最常用的十几个具体码
- 理解 HTTP「无状态」的含义,以及 cookie、session、token 各自解决什么
- 看懂 Content-Type、缓存相关头部,能据此判断接口与缓存问题
你写的每个接口,说的都是 HTTP
应用层最核心的协议就是 HTTP(超文本传输协议),HTTPS 只是给它套了一层 TLS 加密(Stage15-m6 细讲)。无论是 App 请求后端、Nginx 返回静态网页,还是后端去调大模型 API,载体都是 HTTP。看懂它的报文结构和状态码,你才能在部署和排障时读懂 Nginx 日志、浏览器 Network 面板和 curl 的输出,而不是对着「请求失败」四个字无从下手。
一次 HTTP 报文长什么样
HTTP 是纯文本、一问一答的协议。请求由三部分组成:请求行(方法 + 路径 + 协议版本)、若干请求头(键值对)、空行后的请求体;响应同理:状态行(版本 + 状态码 + 原因短语)、响应头、响应体。
# 浏览器/App 发出的请求
POST /api/chat HTTP/1.1
Host: pygood.com
Content-Type: application/json
Authorization: Bearer <token>
Content-Length: 42
{"message":"什么是变量"}
# 服务器返回的响应
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-store
{"ok":true,"data":"变量是给数据起的名字……"}最常见的请求方法(也叫动词)各有语义,REST 设计正是建立在这套语义上:GET 取数据、POST 新建或提交、PUT 整体替换、PATCH 局部更新、DELETE 删除。还有一个容易被忽略的 HEAD(只要头部不要主体,用于探测)和 OPTIONS(询问服务器允许什么,跨域预检用,本模块第 2 课讲)。
状态码:服务器用三位数字告诉你结果
状态码第一位代表大类,记住大类就能先判断问题出在谁身上:
状态码五大类(看首位定方向)1xx 信息 :请求收到了、继续(平时少见,100 Continue)2xx 成功 :200 OK / 201 已创建 / 204 成功但无内容返回3xx 重定向 :301 永久跳转 / 302 临时跳转 / 304 命中缓存未修改4xx 客户端错 :400 参数错 / 401 未认证 / 403 无权限 / 404 不存在 / 405 方法不允许 / 429 请求太频繁被限流5xx 服务器错 :500 内部错误 / 502 网关收到坏响应 / 503 不可用 / 504 网关超时
401 vs 403:401 是「你没登录/令牌无效」,该去补身份;403 是「我知道你是谁,但你没权限」,身份没问题、是授权问题,两者修复方向完全不同。502/504 是 Nginx 这类网关报的:502 Bad Gateway 说明 Nginx 把请求转给后端、后端回了乱码或直接断开(多半后端崩了);504 Gateway Timeout 说明后端太久没响应(多半卡死或在等大模型)。看到 502/504,问题在 Nginx 后面的应用,而不是 Nginx 本身。
HTTP 是「无状态」的:它天生记不住你是谁
HTTP 协议本身不记录上一次请求的任何信息,每个请求都是独立的,这叫无状态(Stateless)。可现实中你登录一次,后面几十个请求都该认得你——于是身份识别方案经历了三代演进:
第一代 Cookie+Session:
登录后服务器建一条 session 记录,把 sessionId 通过 Set-Cookie 下发,
浏览器之后自动带上 Cookie,服务器凭 sessionId 查到你是谁。
缺点:状态存在服务器,多台服务器要共享 session。
第二代 Token / JWT:
登录后服务器签发一个令牌交给客户端保存,之后每次请求放在
Authorization: Bearer <token> 里,服务器只验令牌、不必存会话,
天然适合多服务器与移动端。JWT 形如 头.载荷.签名 三段 Base64URL。
第三代(在 Token 之上叠加):
Access Token 短期有效 + Refresh Token 长期、用来换新,
兼顾安全与体验,是今天 App 的主流做法。JWT 的头和载荷只是 Base64 编码、不是加密,任何人拿到都能解开看内容,所以绝不能在里面放密码等敏感信息;它的第三段是签名,用来防止内容被篡改——服务端用密钥一验就知道载荷有没有被改过。JWT 解决的是「防篡改、无需服务器存会话」,不是「保密」,这点新手最容易误会。
几个决定行为的关键头部
HTTP 头部是键值对,是客户端和服务器协商行为的地方,部署与调优时高频遇到这几个:Content-Type 声明体是什么格式(application/json、text/html、multipart/form-data 上传文件、application/x-www-form-urlencoded 表单);Content-Encoding 声明压缩方式(gzip/br);缓存三件套 Cache-Control、ETag、Last-Modified 决定浏览器要不要重新下载;Authorization 携带身份令牌;CORS 相关头部决定跨域能否放行(下一课讲)。
缓存是怎么省掉一次下载的(选学)
重复下载不变的静态文件(JS/CSS/图片)既慢又费流量,HTTP 用两套机制避免:
Cache-Control: max-age=31536000 —— 告诉浏览器「一年内直接用本地副本,别来问」, 适合带内容哈希文件名的构建产物(文件名一变就是新 URL,自然重新下载)。ETag / If-None-Match —— 不确定是否过期时,浏览器带上上次的 ETag 问服务器, 没变服务器就回 304(不带体,极省流量),变了才回 200 和新内容。
朋友好学的 Next.js 静态导出正是利用这套:带哈希的 _next/static 资源可以长缓存,HTML 则短缓存或不缓存,兼顾「更新即时」与「加载飞快」。
用户反馈接口报 504 Gateway Timeout,最可能的原因和排查方向是?
本节小结
HTTP 是纯文本一问一答的应用层协议,请求=请求行+头部+体,响应=状态行+头部+体。方法有语义(GET 取/POST 增/PUT 换/PATCH 改/DELETE 删,OPTIONS 跨域预检)。状态码看首位:2xx 成功、3xx 跳转缓存、4xx 客户端错(401 未认证≠403 无权限)、5xx 服务端错(502 后端坏、504 后端慢)。HTTP 无状态,身份靠 Cookie-Session 演进到 Token/JWT(JWT 只编码不加密、靠签名防篡改,别放敏感信息),主流是短 Access+长 Refresh。关键头部:Content-Type 定格式、Cache-Control/ETag 控缓存、Authorization 带令牌。
资深工程师加餐
底层原理 · 大厂视角 · 工程经验,点卡片展开
从浏览器到你的应用,一次请求依次经过 DNS 解析、TCP 三次握手、TLS 握手、反向代理、上游应用,再到数据库或缓存,沿原路返回。每一跳都可能是延迟或故障点,所以排错要分层推进:先确认域名解析和端口连通,再看证书是否有效,最后看应用日志与依赖,而不是出问题就先重启。能把链路一层层说清,定位线上故障会快一个数量级。