HTTP协议基础总结

1. HTTP 协议基础

目录

  • [1. HTTP 协议基础](#1. HTTP 协议基础)
    • [1.1 什么是 HTTP?](#1.1 什么是 HTTP?)
    • [1.2 HTTP 请求结构](#1.2 HTTP 请求结构)
    • [1.3 HTTP 响应结构](#1.3 HTTP 响应结构)
    • [1.4 常见请求头与响应头](#1.4 常见请求头与响应头)
    • [1.5 HTTP 方法](#1.5 HTTP 方法)
      • [1. GET(获取资源)](#1. GET(获取资源))
      • [2. POST(创建资源)](#2. POST(创建资源))
      • [3. PUT(全量更新/替换)](#3. PUT(全量更新/替换))
      • [4. PATCH(部分更新)](#4. PATCH(部分更新))
      • [5. DELETE(删除资源)](#5. DELETE(删除资源))
      • [6. HEAD(仅获取响应头,不获取 Body)](#6. HEAD(仅获取响应头,不获取 Body))
      • [7. OPTIONS(预检/探测支持的方法)](#7. OPTIONS(预检/探测支持的方法))
      • [8. GET 与 POST 的区别](#8. GET 与 POST 的区别)
    • [1.6 HTTP 状态码:场景举例](#1.6 HTTP 状态码:场景举例)
      • 一眼速查(带举例)
      • [1xx 信息性响应(⭐ 很少直接感知)](#1xx 信息性响应(⭐ 很少直接感知))
        • [100 Continue ⭐](#100 Continue ⭐)
        • [101 Switching Protocols ⭐](#101 Switching Protocols ⭐)
      • [2xx 成功(⭐⭐⭐ 最常见)](#2xx 成功(⭐⭐⭐ 最常见))
        • [200 OK ⭐⭐⭐](#200 OK ⭐⭐⭐)
        • [201 Created ⭐⭐⭐](#201 Created ⭐⭐⭐)
        • [204 No Content ⭐⭐](#204 No Content ⭐⭐)
        • [206 Partial Content ⭐](#206 Partial Content ⭐)
      • [3xx 重定向(⭐⭐ 浏览器常见,API 调用需注意)](#3xx 重定向(⭐⭐ 浏览器常见,API 调用需注意))
        • [301 Moved Permanently ⭐⭐](#301 Moved Permanently ⭐⭐)
        • [302 Found ⭐⭐](#302 Found ⭐⭐)
        • [304 Not Modified ⭐⭐](#304 Not Modified ⭐⭐)
      • [4xx 客户端错误(⭐⭐⭐ 开发中最常排查)](#4xx 客户端错误(⭐⭐⭐ 开发中最常排查))
        • [400 Bad Request ⭐⭐⭐](#400 Bad Request ⭐⭐⭐)
        • [401 Unauthorized ⭐⭐⭐](#401 Unauthorized ⭐⭐⭐)
        • [403 Forbidden ⭐⭐⭐](#403 Forbidden ⭐⭐⭐)
        • [404 Not Found ⭐⭐⭐](#404 Not Found ⭐⭐⭐)
        • [405 Method Not Allowed ⭐⭐](#405 Method Not Allowed ⭐⭐)
        • [408 Request Timeout ⭐](#408 Request Timeout ⭐)
        • [409 Conflict ⭐⭐](#409 Conflict ⭐⭐)
        • [413 Payload Too Large ⭐⭐](#413 Payload Too Large ⭐⭐)
        • [415 Unsupported Media Type ⭐⭐](#415 Unsupported Media Type ⭐⭐)
        • [422 Unprocessable Entity ⭐⭐](#422 Unprocessable Entity ⭐⭐)
        • [429 Too Many Requests ⭐⭐](#429 Too Many Requests ⭐⭐)
      • [5xx 服务器错误(⭐⭐⭐ 需要后端/运维排查)](#5xx 服务器错误(⭐⭐⭐ 需要后端/运维排查))
        • [500 Internal Server Error ⭐⭐⭐](#500 Internal Server Error ⭐⭐⭐)
        • [502 Bad Gateway ⭐⭐](#502 Bad Gateway ⭐⭐)
        • [503 Service Unavailable ⭐⭐](#503 Service Unavailable ⭐⭐)
        • [504 Gateway Timeout ⭐⭐](#504 Gateway Timeout ⭐⭐)
        • [507 Insufficient Storage ⭐](#507 Insufficient Storage ⭐)
      • [在 Chrome DevTools 里看状态码](#在 Chrome DevTools 里看状态码)
    • [1.7 HTTP vs HTTPS](#1.7 HTTP vs HTTPS)---

1.1 什么是 HTTP?

HTTP (HyperText Transfer Protocol,超文本传输协议)是 客户端与服务器之间通信的应用层协议。它基于 请求-响应 模型,默认使用 TCP 作为传输层。

一次完整的请求流程

  1. 浏览器解析出请求的域名。
  2. 通过DNS(域名系统)获取服务器的IP地址。
  3. 与服务器建立TCP连接(如果是HTTPS,还需进行TLS握手)。
  4. 构建并发送HTTP请求报文。
  5. 服务器接收、解析并处理请求,然后返回HTTP响应报文。
  6. 浏览器解析响应,并关闭或复用TCP连接。

1.2 HTTP 请求结构

一次 HTTP 请求由三部分组成:

部分 说明 示例
请求行 方法 + URL + 协议版本 GET /api/users HTTP/1.1
请求头 元数据(键值对) Content-Type: application/json
请求体 可选,携带数据 {"name": "张三"}

完整请求示例:

http 复制代码
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Accept: application/json

{
  "name": "张三",
  "email": "zhangsan@example.com"
}

1.3 HTTP 响应结构

部分 说明 示例
状态行 协议版本 + 状态码 + 描述 HTTP/1.1 200 OK
响应头 元数据 Content-Type: application/json
响应体 实际返回的数据 {"id": 1, "name": "张三"}

完整响应示例:

http 复制代码
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": 1,
  "name": "张三",
  "email": "zhangsan@example.com"
}

1.4 常见请求头与响应头

HTTP 头(Header)是键值对形式的元数据,不参与业务 Body,但决定服务端如何解析请求、客户端如何处理响应。格式统一为:

复制代码
Header-Name: value

下面按请求头响应头分开说明日常开发中最常用的字段。

常见请求头
Content-Type
项目 说明
作用 告诉服务器:请求体(Body)是什么格式,服务端据此选择 JSON 解析器、表单解析器或文件处理器
何时需要 POST / PUT / PATCH 等带 Body 的请求;GET 通常不需要
示例 Content-Type: application/json
http 复制代码
POST /api/users HTTP/1.1
Content-Type: application/json

{"name": "张三", "email": "zhangsan@example.com"}

常见取值包括 application/jsonapplication/x-www-form-urlencodedmultipart/form-data 等,各格式的 Body 写法与代码示例见 [§1.4.1 Content-Type 详解](#§1.4.1 Content-Type 详解)

Authorization
项目 说明
作用 携带身份认证凭证,证明「我是谁」,用于访问需要登录或鉴权的接口
常见格式 Bearer <Token>(JWT 最常见)、Basic <Base64>(用户名密码)
示例 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
http 复制代码
GET /api/orders HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
  • Token 无效或过期时,服务器通常返回 401 Unauthorized
  • 前端一般在登录成功后保存 Token,之后每次请求自动附加此头
  • 注意: 不要把 Token 写在 URL 里,应放在 Header 中
User-Agent
项目 说明
作用 标识发起请求的客户端类型(浏览器、爬虫、移动端 App、Postman 等)
谁发送 浏览器通常自动添加;后端可据此做统计、兼容性处理或反爬策略
示例 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
http 复制代码
GET /api/products HTTP/1.1
User-Agent: MyApp/1.0 (Android 14)
  • 一般无需手动设置;调用 API 时若服务端有 UA 校验,需按文档指定
  • 伪造 UA 可能触发风控,生产环境应使用真实、规范的值
Accept
项目 说明
作用 告诉服务器:客户端希望收到什么格式的响应(内容协商)
与 Content-Type 区别 Accept 描述「我能接受什么响应」;请求侧的 Content-Type 描述「我发送的 Body 是什么」
示例 Accept: application/json
http 复制代码
GET /api/users/1 HTTP/1.1
Accept: application/json

常见取值:

Accept 值 含义
application/json 期望 JSON(REST API 最常用)
text/html 期望 HTML 页面(浏览器访问网页)
application/xml 期望 XML
*/* 任意格式均可(默认值之一)

可同时声明多种格式并带优先级,例如:Accept: application/json, text/plain;q=0.9q 为权重,越大越优先)。

Cache-Control
项目 说明
作用 控制缓存行为:是否使用缓存、缓存多久、是否必须向源站验证
请求侧含义 客户端声明自己对缓存的要求
示例 Cache-Control: no-cache
http 复制代码
GET /api/profile HTTP/1.1
Cache-Control: no-cache

请求侧常见指令:

指令 含义
no-cache 可以使用缓存,但使用前必须向服务器确认是否仍有效
no-store 不要存储任何缓存(敏感数据)
max-age=0 立即视为过期,需重新验证

调试接口时,可在浏览器 DevTools 中勾选 Disable cache,等效于强制跳过本地缓存。

Connection
项目 说明
作用 控制TCP 连接是否保持(长连接 / 短连接)
HTTP/1.1 默认 Connection: keep-alive(同一 TCP 连接可复用,减少握手开销)
示例 Connection: keep-aliveConnection: close
http 复制代码
GET /api/data HTTP/1.1
Connection: keep-alive
含义
keep-alive 请求完成后不立即关闭 TCP 连接,后续请求可复用
close 本次响应结束后关闭连接(HTTP/1.0 风格)
  • 空闲超时 (Idle Timeout) :这是最主要的方式。如果连接在指定时间内没有新请求,服务器就会主动关闭它常见默认值 :Nginx 默认 75秒,Tomcat 默认 30秒,Node.js 默认 5分钟
  • 最大请求数限制 (Max Requests) :为防止单一连接处理过多请求,服务器会限制其最大使用次数,达到上限后关闭。常见如 Nginx 默认 100次
Accept-Encoding
项目 说明
作用 告诉服务器:客户端支持哪些响应压缩算法,服务器可对响应 Body 压缩后再传输,节省带宽
示例 Accept-Encoding: gzip, deflate, br
http 复制代码
GET /api/large-report HTTP/1.1
Accept-Encoding: gzip, deflate, br
编码 说明
gzip 最普遍,几乎所有服务器和浏览器支持
deflate 较少单独使用
br Brotli 压缩,现代浏览器支持,压缩率通常更好

浏览器会自动发送此头;服务端若返回压缩内容,会在响应头 中用 Content-Encoding: gzip 标明,客户端自动解压。


常见响应头

响应头由服务器返回,描述响应本身的属性。以下与上文请求头一一对应或配合使用。

Content-Type(响应)
项目 说明
作用 告诉客户端:响应体(Body)是什么格式,浏览器或代码据此决定如何解析
示例 Content-Type: application/json; charset=UTF-8
http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8

{"id": 1, "name": "张三"}
  • 返回 JSON 接口务必设置为 application/json,否则前端可能无法正确解析
Content-Disposition(响应)
项目 说明
作用 告诉浏览器如何处理响应 Body:在页面内嵌展示,还是作为附件下载;下载时可指定默认文件名
常见取值 inline(内联展示)、attachment(触发下载)
示例 Content-Disposition: attachment; filename="report.pdf"
http 复制代码
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"

(PDF 二进制内容)
取值 / 参数 含义
inline 在浏览器内直接打开(如 PDF 预览、图片显示)
attachment 提示用户保存为文件,弹出「另存为」或使用默认文件名下载
filename="..." 建议的下载文件名(中文建议配合 filename*=UTF-8'' 编码)

典型场景:

  • 导出 Excel / PDFContent-Disposition: attachment; filename="订单列表.xlsx"
  • 在线预览 PDFContent-Disposition: inline + Content-Type: application/pdf
  • 接口返回文件流 :常与 Content-Type: application/octet-stream 配合使用
http 复制代码
HTTP/1.1 200 OK
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="export.xlsx"
Cache-Control(响应)
项目 说明
作用 告诉浏览器和中间代理:此响应能否缓存、缓存多久
示例 Cache-Control: max-age=3600, public
http 复制代码
HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
Content-Type: application/json

{"list": [...]}

响应侧常见指令:

指令 含义
public 可被浏览器和 CDN 等任意缓存
private 仅浏览器可缓存,CDN 不应缓存(含用户私有数据)
max-age=3600 缓存 3600 秒(1 小时)内可直接使用,无需再问服务器
no-store 禁止存储(登录态、支付等敏感接口)
no-cache 可存但必须每次向源站验证

静态资源(JS/CSS/图片)常设较长 max-age;动态 API 数据多用 no-cacheno-store

Connection(响应)
项目 说明
作用 告知客户端本次响应后是否关闭 TCP 连接
示例 Connection: keep-alive
http 复制代码
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json

通常与请求侧的 Connection 一致;HTTP/1.1 下多数场景为 keep-alive,由服务器或反向代理(Nginx)统一管理。

Content-Encoding(响应,配合 Accept-Encoding)
项目 说明
作用 标明响应 Body 使用的压缩方式 ,与请求头 Accept-Encoding 配合
示例 Content-Encoding: gzip
http 复制代码
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: application/json

(gzip 压缩后的二进制 Body,浏览器会自动解压)

客户端在 Accept-Encoding 中声明支持 gzip 后,服务器可选择压缩响应;若未压缩,则不发送此头


请求头与响应头对照速查:

头名称 请求 响应 核心作用
Content-Type 声明 Body 的媒体类型
Authorization --- 携带认证凭证
User-Agent --- 标识客户端类型
Accept --- 指定期望的响应格式
Cache-Control 控制缓存策略
Connection 控制 TCP 连接是否保持
Accept-Encoding --- 声明支持的压缩算法
Content-Encoding --- 标明响应已采用的压缩方式
Content-Disposition --- 控制内联展示或附件下载、文件名
1.4.1 Content-Type 详解:常见类型与传参方式

Content-Type 请求头声明 请求体(Body)的数据格式,服务端据此解析参数。没有 Body 的请求(如 GET)通常不需要设置此头。

格式说明
复制代码
Content-Type: 主类型/子类型[; 参数=值]

示例:Content-Type: application/json; charset=UTF-8

常见类型速查
Content-Type 用途 参数位置 典型场景
application/json JSON 格式 请求体 Body REST API、前后端分离
application/x-www-form-urlencoded URL 编码键值对 请求体 Body 传统表单、OAuth Token
multipart/form-data 多部分表单 请求体 Body(分段) 文件上传、含文件的表单
text/plain 纯文本 请求体 Body 简单文本、 Webhook
application/xml XML 格式 请求体 Body SOAP、旧式接口
application/octet-stream 二进制流 请求体 Body(原始字节) 文件直传、下载
text/html HTML 文档 请求体 Body 少见(多为响应)

#mermaid-svg-1MtEFxFrz0W7gfas{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1MtEFxFrz0W7gfas .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1MtEFxFrz0W7gfas .error-icon{fill:#552222;}#mermaid-svg-1MtEFxFrz0W7gfas .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1MtEFxFrz0W7gfas .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1MtEFxFrz0W7gfas .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1MtEFxFrz0W7gfas .marker.cross{stroke:#333333;}#mermaid-svg-1MtEFxFrz0W7gfas svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1MtEFxFrz0W7gfas p{margin:0;}#mermaid-svg-1MtEFxFrz0W7gfas .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1MtEFxFrz0W7gfas .cluster-label text{fill:#333;}#mermaid-svg-1MtEFxFrz0W7gfas .cluster-label span{color:#333;}#mermaid-svg-1MtEFxFrz0W7gfas .cluster-label span p{background-color:transparent;}#mermaid-svg-1MtEFxFrz0W7gfas .label text,#mermaid-svg-1MtEFxFrz0W7gfas span{fill:#333;color:#333;}#mermaid-svg-1MtEFxFrz0W7gfas .node rect,#mermaid-svg-1MtEFxFrz0W7gfas .node circle,#mermaid-svg-1MtEFxFrz0W7gfas .node ellipse,#mermaid-svg-1MtEFxFrz0W7gfas .node polygon,#mermaid-svg-1MtEFxFrz0W7gfas .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1MtEFxFrz0W7gfas .rough-node .label text,#mermaid-svg-1MtEFxFrz0W7gfas .node .label text,#mermaid-svg-1MtEFxFrz0W7gfas .image-shape .label,#mermaid-svg-1MtEFxFrz0W7gfas .icon-shape .label{text-anchor:middle;}#mermaid-svg-1MtEFxFrz0W7gfas .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1MtEFxFrz0W7gfas .rough-node .label,#mermaid-svg-1MtEFxFrz0W7gfas .node .label,#mermaid-svg-1MtEFxFrz0W7gfas .image-shape .label,#mermaid-svg-1MtEFxFrz0W7gfas .icon-shape .label{text-align:center;}#mermaid-svg-1MtEFxFrz0W7gfas .node.clickable{cursor:pointer;}#mermaid-svg-1MtEFxFrz0W7gfas .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1MtEFxFrz0W7gfas .arrowheadPath{fill:#333333;}#mermaid-svg-1MtEFxFrz0W7gfas .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1MtEFxFrz0W7gfas .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1MtEFxFrz0W7gfas .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1MtEFxFrz0W7gfas .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1MtEFxFrz0W7gfas .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1MtEFxFrz0W7gfas .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1MtEFxFrz0W7gfas .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1MtEFxFrz0W7gfas .cluster text{fill:#333;}#mermaid-svg-1MtEFxFrz0W7gfas .cluster span{color:#333;}#mermaid-svg-1MtEFxFrz0W7gfas div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1MtEFxFrz0W7gfas .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1MtEFxFrz0W7gfas rect.text{fill:none;stroke-width:0;}#mermaid-svg-1MtEFxFrz0W7gfas .icon-shape,#mermaid-svg-1MtEFxFrz0W7gfas .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1MtEFxFrz0W7gfas .icon-shape p,#mermaid-svg-1MtEFxFrz0W7gfas .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1MtEFxFrz0W7gfas .icon-shape .label rect,#mermaid-svg-1MtEFxFrz0W7gfas .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1MtEFxFrz0W7gfas .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1MtEFxFrz0W7gfas .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1MtEFxFrz0W7gfas :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

JSON 对象/数组
简单键值对
XML
原始二进制
选择 Content-Type
有文件上传?
multipart/form-data
数据结构?
application/json
application/x-www-form-urlencoded
application/xml
application/octet-stream


1. application/json(最常用)

请求头:

http 复制代码
Content-Type: application/json

Body 格式: JSON 对象或数组

请求示例:

http 复制代码
POST /api/users HTTP/1.1
Content-Type: application/json

{
  "name": "张三",
  "email": "zhangsan@example.com",
  "age": 25,
  "tags": ["vip", "active"]
}

JavaScript(fetch):

javascript 复制代码
fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: '张三',
    email: 'zhangsan@example.com'
  })
});

注意:

  • 嵌套对象、数组直接写在 JSON 中
  • 数字、布尔值不要加引号
  • 中文无需额外编码(UTF-8 默认)

2. application/x-www-form-urlencoded

请求头:

http 复制代码
Content-Type: application/x-www-form-urlencoded

Body 格式: key1=value1&key2=value2,特殊字符 URL 编码

字符 编码后
空格 +%20
& %26
= %3D
中文 %E4%B8%AD%E6%96%87

请求示例:

http 复制代码
POST /api/login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=zhangsan&password=123456&remember=true

JavaScript:

javascript 复制代码
// 方式 1:URLSearchParams(推荐)
const params = new URLSearchParams();
params.append('username', 'zhangsan');
params.append('password', '123456');

fetch('/api/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: params.toString()
});

// 方式 2:手动拼接
const body = 'username=zhangsan&password=' + encodeURIComponent('123456');

与 JSON 对比:

对比项 form-urlencoded JSON
嵌套对象 不支持(需 user[name] 约定) 原生支持
数组 需重复 key 原生支持
文件 不支持 不支持(需 multipart)
可读性 简单键值对直观 结构复杂时更清晰

3. multipart/form-data(文件上传)

请求头:

http 复制代码
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

boundary 是分隔各字段的随机字符串,由客户端自动生成,不要手动写固定值。

Body 格式: 多个「部分(Part)」用 boundary 分隔,每部分可含普通字段或文件

http 复制代码
POST /api/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary123

------Boundary123
Content-Disposition: form-data; name="title"

我的文档
------Boundary123
Content-Disposition: form-data; name="file"; filename="report.pdf"

<二进制文件内容>
------Boundary123--

JavaScript(FormData,无需手动设 Content-Type):

javascript 复制代码
const formData = new FormData();
formData.append('title', '我的文档');
formData.append('file', fileInput.files[0]);  // File 对象

fetch('/api/upload', {
  method: 'POST',
  body: formData
  // ⚠️ 不要手动设置 Content-Type,浏览器会自动加 boundary
});

字段结构说明:

部分 说明
Content-Disposition: form-data; name="字段名" 普通文本字段
Content-Disposition: form-data; name="字段名"; filename="文件名" 文件字段
空行后的内容 字段值或文件二进制

注意:

  • 同时传文件和普通字段时使用
  • 使用 FormData不要 手动设置 Content-Type(boundary 由浏览器生成)
  • Postman 选 form-data 类型即可

4. text/plain

请求头:

http 复制代码
Content-Type: text/plain

Body 格式: 纯文本字符串,无结构

http 复制代码
POST /api/webhook HTTP/1.1
Content-Type: text/plain

Hello, this is a plain text message.

JavaScript:

javascript 复制代码
fetch('/api/webhook', {
  method: 'POST',
  headers: { 'Content-Type': 'text/plain' },
  body: 'Hello, this is a plain text message.'
});

5. application/xml

请求头:

http 复制代码
Content-Type: application/xml

Body 格式: XML 文档

http 复制代码
POST /api/soap HTTP/1.1
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<user>
  <name>张三</name>
  <email>zhangsan@example.com</email>
</user>

JavaScript:

javascript 复制代码
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<user><name>张三</name></user>`;

fetch('/api/soap', {
  method: 'POST',
  headers: { 'Content-Type': 'application/xml' },
  body: xml
});

6. application/octet-stream

请求头:

http 复制代码
Content-Type: application/octet-stream

Body 格式: 原始二进制字节流(无结构)

javascript 复制代码
// 上传原始文件字节
const buffer = await file.arrayBuffer();

fetch('/api/files', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/octet-stream',
    'Content-Disposition': `attachment; filename="${file.name}"`
  },
  body: buffer
});

典型场景: 大文件直传、对象存储 PUT、固件升级包上传



各类型完整对比
类型 结构 嵌套/数组 文件 编码 REST API 常用
application/json JSON UTF-8 ⭐⭐⭐ 最常用
application/x-www-form-urlencoded 键值对 URL 编码 ⭐⭐ 登录/表单
multipart/form-data 多段 ✅(多字段) 每段独立 ⭐⭐ 上传
text/plain 纯文本 文本 ⭐ 少见
application/xml XML UTF-8 ⭐ SOAP 遗留
application/octet-stream 二进制 --- 原始字节 ⭐ 直传
常见错误与排查
错误现象 原因 解决
415 Unsupported Media Type 服务端不支持该 Content-Type 对照 API 文档改用正确类型
400 + JSON 解析失败 发了 JSON 但 Content-Type 是 form 改为 application/json
后端收到空 Body 用了 JSON 但 Content-Type 是 form-urlencoded 统一类型与 Body 格式
文件上传失败 手动设置了 multipart 的 Content-Type 但 boundary 错误 用 FormData,让浏览器自动设置
中文乱码 缺少 charset ; charset=UTF-8
Postman / Apifox 对照
工具中的 Body 类型 对应 Content-Type
none 无 Body
form-data multipart/form-data
x-www-form-urlencoded application/x-www-form-urlencoded
raw → JSON application/json
raw → XML application/xml
raw → Text text/plain
binary application/octet-stream

1.5 HTTP 方法

方法 语义 是否幂等 是否有请求体
GET 获取资源
POST 创建资源
PUT 全量替换资源
PATCH 部分更新资源
DELETE 删除资源
HEAD 同 GET,但只返回响应头
OPTIONS 查询服务器支持的方法(含浏览器预检)

幂等:多次相同请求产生的效果与一次相同。GET、PUT、DELETE 通常是幂等的;POST 不是。

1 . GET(获取资源)
  • 前端 Fetch

    // 路径参数
    fetch('/api/users/123');
    // 查询参数(手动拼URL)
    fetch('/api/users?page=1&size=10');

  • 后端 Spring Boot

    @GetMapping("/users/{id}")
    public User get(@PathVariable Long id) { return service.get(id); }
    @GetMapping("/users")
    public List list(@RequestParam int page, @RequestParam int size) {
    return service.list(page, size);
    }


2. POST(创建资源)
  • 前端 Fetch

    fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: '张三', age: 25 })
    });

  • 后端 Spring Boot

    @PostMapping("/users")
    public User create(@RequestBody UserDto dto) {
    return service.save(dto);
    }


3. PUT(全量更新/替换)
  • 前端 Fetch

    fetch('/api/users/123', {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: '张三新名', age: 30, email: 'new@xx.com' }) // 必须传全量字段
    });

  • 后端 Spring Boot

    @PutMapping("/users/{id}")
    public User update(@PathVariable Long id, @RequestBody UserDto dto) {
    return service.fullUpdate(id, dto); // 全量覆盖
    }


4. PATCH(部分更新)
  • 前端 Fetch

    fetch('/api/users/123', {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email: 'new_email@xx.com' }) // 只传要改的字段
    });

  • 后端 Spring Boot

    @PatchMapping("/users/{id}")
    public User patch(@PathVariable Long id, @RequestBody Map<String, Object> patch) {
    return service.partialUpdate(id, patch); // 只更新传入的非空字段
    }


5. DELETE(删除资源)
  • 前端 Fetch (参数放 URL,禁止放 Body

    // 删除单个
    fetch('/api/users/123', { method: 'DELETE' });
    // 批量删除(Query传参)
    fetch('/api/users?ids=1&ids=2&ids=3', { method: 'DELETE' });

  • 后端 Spring Boot

    @DeleteMapping("/users/{id}")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
    service.delete(id);
    return ResponseEntity.noContent().build(); // 返回 204
    }
    @DeleteMapping("/users")
    public ResponseEntity<Void> deleteBatch(@RequestParam List<Long> ids) {
    service.deleteBatch(ids);
    return ResponseEntity.noContent().build();
    }


6. HEAD(仅获取响应头,不获取 Body)
  • 前端 Fetch

    fetch('/api/files/123', { method: 'HEAD' }).then(res => {
    console.log(res.headers.get('Content-Length')); // 获取文件大小
    console.log(res.headers.get('Last-Modified')); // 获取修改时间
    // 注意:此时 res.body 为空,无法读取数据
    });

  • 后端 Spring Boot

    // 方式一:@GetMapping 默认自动支持 HEAD(但会执行完整查询逻辑,浪费性能)
    // 方式二:专门写轻量级 HEAD 逻辑(推荐)
    @RequestMapping(value = "/files/{id}", method = RequestMethod.HEAD)
    public ResponseEntity head(@PathVariable Long id) {
    long size = service.getFileSize(id); // 只查元数据,不读文件流
    return ResponseEntity.ok()
    .header("Content-Length", String.valueOf(size))
    .build();
    }


7. OPTIONS(预检/探测支持的方法)
  • 前端 Fetch(通常浏览器自动发,无需手动,但可测试)

    fetch('/api/users', { method: 'OPTIONS' }).then(res => {
    console.log(res.headers.get('Allow')); // 打印服务器支持的方法,如 GET,POST,PUT,DELETE
    });

  • 后端 Spring Boot无需编写任何代码

java

复制代码
// Spring 框架自动响应 OPTIONS 请求。
// 只要在类上或方法上标注了 @CrossOrigin 或全局 CORS 配置,
// 框架会自动返回 Allow 头部和跨域相关头部。
// 如果完全没配 CORS,OPTIONS 也会返回默认支持的 Allow 头。

这是浏览器强制自动 发出的,只有同时满足以下两个条件才会触发:

  • 条件一(跨域) :前端页面域名(如 localhost:3000)和后端接口域名(如 api.example.com)不同。

  • 条件二(非简单请求):请求不满足"简单请求"标准。最常见的是:

    • 用了 PUTDELETEPATCH 方法。

    • 请求头带了 AuthorizationX-Token 等自定义头。

    • Content-Typeapplication/json

      注意 :如果是跨域但满足"简单请求" (比如纯 GET 请求,且不带自定义头,只传 text/plain),浏览器不会OPTIONS,直接发 GET


8、 GET 与 POST 的区别

GET 和 POST 是最常用的两种方法,初学者容易混淆。核心差异如下:

对比维度 GET POST
语义 获取/读取资源 创建资源或提交数据
参数位置 URL 查询字符串(Query String) 请求体(Body)
是否有 Body 否(规范上不携带 Body) 是(JSON、表单等)
是否幂等 是(重复请求不改变资源) 否(重复提交可能创建多条记录)
是否可缓存 通常可缓存 通常不缓存
参数长度 受 URL 长度限制(约 2KB~8KB,因浏览器/服务器而异) 无严格限制,适合大数据量
可见性 参数出现在 URL 中,会进入浏览器历史、服务器访问日志 参数在 Body 中,不显示在地址栏
典型场景 查询列表、搜索、分页、获取详情 登录、注册、创建订单、提交表单、文件上传
如何选用:
  • 读数据、不改变服务器状态 → 用 GET (如 /api/products?category=phone
  • 写数据、创建或提交 → 用 POST (如 POST /api/orders 创建订单)
  • 敏感信息 (密码、Token)→ 应放在 POST Body 中,不要放在 GET 的 URL 参数里

常见误区: 「POST 比 GET 安全」并不绝对------POST 只是参数不出现在 URL 中;传输安全依赖 HTTPS。另外,部分老系统用 POST 做查询(参数放 Body),不符合 REST 语义,但技术上可行。

1.6 HTTP 状态码:场景举例

状态码是服务器告诉客户端「这次请求结果如何」的三位数字。先看第一位就能大致判断:

首位 类别 含义 谁的问题?
1 信息性 收到,继续处理 ---
2 成功 请求成功 ✅ 正常
3 重定向 需要去另一个地址 通常正常
4 客户端错误 请求有问题 ❌ (前端/调用方)
5 服务器错误 服务端出错了 ❌ 后端/运维

遇频率说明(下文示例中标注):

标记 含义
⭐⭐⭐ 日常开发必遇,几乎每个人都见过
⭐⭐ 做 API/上传/权限时会遇到
特定场景才出现,知道即可

#mermaid-svg-sbAqgi8iAZ2oiV3n{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sbAqgi8iAZ2oiV3n .error-icon{fill:#552222;}#mermaid-svg-sbAqgi8iAZ2oiV3n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sbAqgi8iAZ2oiV3n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .marker.cross{stroke:#333333;}#mermaid-svg-sbAqgi8iAZ2oiV3n svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sbAqgi8iAZ2oiV3n p{margin:0;}#mermaid-svg-sbAqgi8iAZ2oiV3n .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .cluster-label text{fill:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .cluster-label span{color:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .cluster-label span p{background-color:transparent;}#mermaid-svg-sbAqgi8iAZ2oiV3n .label text,#mermaid-svg-sbAqgi8iAZ2oiV3n span{fill:#333;color:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .node rect,#mermaid-svg-sbAqgi8iAZ2oiV3n .node circle,#mermaid-svg-sbAqgi8iAZ2oiV3n .node ellipse,#mermaid-svg-sbAqgi8iAZ2oiV3n .node polygon,#mermaid-svg-sbAqgi8iAZ2oiV3n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .rough-node .label text,#mermaid-svg-sbAqgi8iAZ2oiV3n .node .label text,#mermaid-svg-sbAqgi8iAZ2oiV3n .image-shape .label,#mermaid-svg-sbAqgi8iAZ2oiV3n .icon-shape .label{text-anchor:middle;}#mermaid-svg-sbAqgi8iAZ2oiV3n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .rough-node .label,#mermaid-svg-sbAqgi8iAZ2oiV3n .node .label,#mermaid-svg-sbAqgi8iAZ2oiV3n .image-shape .label,#mermaid-svg-sbAqgi8iAZ2oiV3n .icon-shape .label{text-align:center;}#mermaid-svg-sbAqgi8iAZ2oiV3n .node.clickable{cursor:pointer;}#mermaid-svg-sbAqgi8iAZ2oiV3n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .arrowheadPath{fill:#333333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sbAqgi8iAZ2oiV3n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sbAqgi8iAZ2oiV3n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sbAqgi8iAZ2oiV3n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sbAqgi8iAZ2oiV3n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .cluster text{fill:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n .cluster span{color:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sbAqgi8iAZ2oiV3n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sbAqgi8iAZ2oiV3n rect.text{fill:none;stroke-width:0;}#mermaid-svg-sbAqgi8iAZ2oiV3n .icon-shape,#mermaid-svg-sbAqgi8iAZ2oiV3n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sbAqgi8iAZ2oiV3n .icon-shape p,#mermaid-svg-sbAqgi8iAZ2oiV3n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sbAqgi8iAZ2oiV3n .icon-shape .label rect,#mermaid-svg-sbAqgi8iAZ2oiV3n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sbAqgi8iAZ2oiV3n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sbAqgi8iAZ2oiV3n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sbAqgi8iAZ2oiV3n :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 5xx 服务器错误 ⭐⭐⭐
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
4xx 客户端错误 ⭐⭐⭐
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
3xx 重定向 ⭐⭐
301 Moved Permanently
302 Found
304 Not Modified
2xx 成功 ⭐⭐⭐
200 OK
201 Created
204 No Content
1xx 信息性 ⭐
100 Continue

一眼速查(带举例)
状态码 含义 举例(你什么时候会看到) 频率
200 成功 登录成功返回用户信息;查询订单列表 ⭐⭐⭐
201 已创建 POST 新建客户/订单,资源创建成功 ⭐⭐⭐
204 成功,无内容 DELETE 删除一条记录,不需要返回 body ⭐⭐
301 永久搬家 旧域名 http://old.com 永久跳到 https://new.com ⭐⭐
304 用缓存 刷新页面时,CSS 没改过,浏览器直接用本地缓存 ⭐⭐
400 参数错了 手机号少一位、JSON 少逗号、必填字段没传 ⭐⭐⭐
401 没登录/Token 失效 Token 过期调接口;没带 Authorization 头 ⭐⭐⭐
403 没权限 普通员工访问「仅管理员」接口 ⭐⭐⭐
404 找不到 URL 写错 /api/usres;订单 ID 不存在 ⭐⭐
500 服务器崩了 后端空指针、SQL 报错、未捕获异常 ⭐⭐⭐
502 网关连不上后端 Nginx 后面的 Java 服务挂了 ⭐⭐
503 服务暂不可用 系统维护中;流量太大被限流熔断 ⭐⭐
504 请求超时 504 Gateway Timeout ,是后端服务(Tomcat/Node)处理请求太慢了,超过了中间层(如 Nginx)设置的等待时间 ⭐⭐⭐

下面按类别展开,每个状态码用真实场景 + 请求/响应示例说明,帮助理解「什么情况下会遇到」。


1xx 信息性响应(⭐ 很少直接感知)

这类状态码你在浏览器里几乎看不到,大文件上传、WebSocket 升级时才会涉及。

100 Continue ⭐

场景: 上传 500MB 文件前,客户端先问服务器「我准备发大 body 了,你要吗?」,服务器说「继续发」。

http 复制代码
# 客户端先发请求头
PUT /api/files/big.zip HTTP/1.1
Expect: 100-continue

# 服务器同意
HTTP/1.1 100 Continue

# 客户端再发送文件内容...

你什么时候遇到: 自己写大文件上传客户端,或用 curl -L 上传超大文件时。日常调 JSON 接口基本不会见到。

101 Switching Protocols ⭐

场景: 网页从 HTTP 升级到 WebSocket 长连接(在线聊天、实时通知)。

http 复制代码
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

你什么时候遇到: 做 WebSocket 开发时;普通 REST API 不会遇到。


2xx 成功(⭐⭐⭐ 最常见)
200 OK ⭐⭐⭐

场景 1: 查询用户列表成功

http 复制代码
GET /api/users?page=1 HTTP/1.1
Authorization: Bearer eyJhbGci...

HTTP/1.1 200 OK
Content-Type: application/json

{"data": [{"id": 1, "name": "张三"}], "total": 100}

场景 2: 登录成功(也有接口用 200 而非 201)

http 复制代码
POST /api/login HTTP/1.1
Content-Type: application/json

{"username": "admin", "password": "123456"}

HTTP/1.1 200 OK

{"token": "eyJhbG...", "userId": 1}

⚠️ 注意陷阱: 有些接口 HTTP 返回 200,但 body 里写 "code": 500, "message": "余额不足"。所以要同时看状态码和 body

json 复制代码
// HTTP 200,但业务失败 ------ 很多国内接口这样设计
{"code": 40001, "message": "订单不存在", "success": false}
201 Created ⭐⭐⭐

场景: 新建一条销售订单、创建一个客户

http 复制代码
POST /api/sales-orders HTTP/1.1
Content-Type: application/json

{"customerId": 100, "items": [{"sku": "A001", "qty": 2}]}

HTTP/1.1 201 Created
Location: /api/sales-orders/9527
Content-Type: application/json

{"id": 9527, "status": "pending", "createdAt": "2026-07-06T10:00:00Z"}

和 200 的区别: 201 专用于「新资源被创建 」,响应头里常有 Location 指向新资源地址。

204 No Content ⭐⭐

场景: 删除一条记录、更新设置(不需要返回任何数据)

http 复制代码
DELETE /api/users/42 HTTP/1.1
Authorization: Bearer eyJhbG...

HTTP/1.1 204 No Content
(响应体为空)

前端常见坑:

javascript 复制代码
// ❌ 204 没有 body,这样写会报错
const data = await response.json();  // Unexpected end of JSON input

// ✅ 正确写法
if (response.status === 204) {
  console.log('删除成功');
} else {
  const data = await response.json();
}
206 Partial Content ⭐

场景: 视频播放拖动进度条、断点续传下载

http 复制代码
GET /videos/demo.mp4 HTTP/1.1
Range: bytes=0-1023

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/1048576
Content-Length: 1024

(只返回文件的第 0~1023 字节)

你什么时候遇到: 看视频拖进度条、下载工具「续传」时。调普通 JSON 接口不会遇到。


3xx 重定向(⭐⭐ 浏览器常见,API 调用需注意)
301 Moved Permanently ⭐⭐

场景: 公司换了域名,旧地址永久跳转到新地址

http 复制代码
GET http://old-company.com/api/users HTTP/1.1

HTTP/1.1 301 Moved Permanently
Location: https://new-company.com/api/users

举例: 访问 http://example.com 被永久跳到 https://example.com(HTTP → HTTPS)。

你该怎么做: 更新代码里的 baseURL,不要长期依赖 301 跳转。

302 Found ⭐⭐

场景: 未登录访问后台,被临时跳到登录页

http 复制代码
GET /admin/dashboard HTTP/1.1
Cookie: (无 session)

HTTP/1.1 302 Found
Location: /login?redirect=/admin/dashboard

和 301 的区别: 302 是临时跳转,以后还可能变回原地址。

⚠️ 经典坑: 旧浏览器遇到 302 时,可能把 POST 变成 GET ,导致提交的数据丢失。现代 API 更推荐用 307/308

304 Not Modified ⭐⭐

场景: 浏览器第二次加载网页,问服务器「我本地的 app.js 改过吗?」,服务器说「没改,用你缓存的就行」

http 复制代码
GET /static/app.js HTTP/1.1
If-None-Match: "abc123"
If-Modified-Since: Wed, 01 Jul 2026 10:00:00 GMT

HTTP/1.1 304 Not Modified
(无 body,浏览器直接用本地缓存)

你什么时候遇到: 打开 DevTools → Network,看到某些静态资源 Status 是 304。说明缓存生效,不是错误

开发排查: 「我明明改了代码,页面怎么还是旧的?」→ 强刷 Ctrl+F5 或禁用缓存。


4xx 客户端错误(⭐⭐⭐ 开发中最常排查)

4xx = 你的请求有问题,优先检查:URL、参数、Header、Token、权限。

400 Bad Request ⭐⭐⭐

场景 1: JSON 格式错误

http 复制代码
POST /api/users HTTP/1.1
Content-Type: application/json

{"name": "张三", "age": }    ← 少了值,JSON 非法

HTTP/1.1 400 Bad Request

{"error": "Invalid JSON at line 1 column 25"}

场景 2: 必填参数缺失

http 复制代码
POST /api/users HTTP/1.1

{"name": "张三"}    ← 缺少必填字段 email

HTTP/1.1 400 Bad Request

{"error": "Validation failed", "fields": {"email": "不能为空"}}

场景 3: 类型不对

http 复制代码
POST /api/users HTTP/1.1

{"name": "张三", "age": "二十五"}    ← age 应该是数字

HTTP/1.1 400 Bad Request

{"error": "age must be a number"}

怎么排查: 对照 API 文档;用 Postman 对比正确请求;看响应 body 里的字段级错误。

401 Unauthorized ⭐⭐⭐

场景 1: 没带 Token

http 复制代码
GET /api/orders HTTP/1.1
(没有 Authorization 头)

HTTP/1.1 401 Unauthorized

{"error": "Missing authentication token"}

场景 2: Token 过期

http 复制代码
GET /api/orders HTTP/1.1
Authorization: Bearer eyJhbGci...(已过期)

HTTP/1.1 401 Unauthorized

{"error": "Token expired", "code": "TOKEN_EXPIRED"}

场景 3: 登录账号密码错误(有些接口也返回 401)

http 复制代码
POST /api/login HTTP/1.1

{"username": "admin", "password": "wrong"}

HTTP/1.1 401 Unauthorized

{"error": "Invalid username or password"}

怎么排查: 检查 Authorization 头格式是否为 Bearer <token>;Token 是否过期;是否需要先调登录接口。

403 Forbidden ⭐⭐⭐

场景: 已登录,但没有权限操作

http 复制代码
DELETE /api/admin/users/1 HTTP/1.1
Authorization: Bearer eyJhbGci...(普通员工 Token)

HTTP/1.1 403 Forbidden

{"error": "Permission denied", "required": "admin"}

和 401 的区别(必记):

状态码 含义 生活比喻
401 不知道你是谁 没刷工牌就进公司
403 知道你是谁,但不让你做 刷了工牌,但你是访客不能进机房
404 Not Found ⭐⭐⭐

场景 1: URL 路径写错

http 复制代码
GET /api/usres/1 HTTP/1.1          ← users 拼成了 usres

HTTP/1.1 404 Not Found

{"error": "Route not found"}

场景 2: 资源已被删除或 ID 不存在

http 复制代码
GET /api/orders/999999 HTTP/1.1

HTTP/1.1 404 Not Found

{"error": "Order 999999 not found"}

怎么排查: 核对 URL 拼写、HTTP 方法、资源 ID 是否存在。

405 Method Not Allowed ⭐⭐

场景: 对接口用了错误的 HTTP 方法

http 复制代码
GET /api/users HTTP/1.1     ← 创建用户应该用 POST

HTTP/1.1 405 Method Not Allowed
Allow: POST

{"error": "Method GET not allowed, use POST"}

怎么排查: 看响应头 Allow 字段,确认支持的 Method。

408 Request Timeout ⭐

场景: 客户端发送请求体太慢,服务器等不及了

你什么时候遇到: 网络极差时上传大文件;物联网弱网环境。一般后端框架较少主动返回 408。

409 Conflict ⭐⭐

场景 1: 重复创建(邮箱/用户名唯一)

http 复制代码
POST /api/users HTTP/1.1

{"email": "zhangsan@example.com"}    ← 该邮箱已存在

HTTP/1.1 409 Conflict

{"error": "Email already exists"}

场景 2: 乐观锁版本冲突(两人同时编辑)

http 复制代码
PUT /api/orders/9527 HTTP/1.1

{"status": "shipped", "version": 3}    ← 服务器已是 version 4

HTTP/1.1 409 Conflict

{"error": "Resource was modified by another user", "currentVersion": 4}

场景 3: 重复提交订单(没做幂等)

http 复制代码
POST /api/orders HTTP/1.1
Idempotency-Key: order-20260706-001    ← 同一 Key 提交了两次

HTTP/1.1 409 Conflict

{"error": "Duplicate request"}
413 Payload Too Large ⭐⭐

场景: 上传的文件超过服务器限制

http 复制代码
POST /api/upload HTTP/1.1
Content-Type: multipart/form-data

(上传 200MB 文件,服务器限制 50MB)

HTTP/1.1 413 Payload Too Large

{"error": "File size exceeds 50MB limit"}

怎么解决: 压缩文件;分片上传;让运维调大 Nginx client_max_body_size

415 Unsupported Media Type ⭐⭐

场景: Content-Type 和服务端期望的不一致

http 复制代码
POST /api/users HTTP/1.1
Content-Type: text/plain          ← 服务端只接受 JSON

{"name": "张三"}

HTTP/1.1 415 Unsupported Media Type

{"error": "Content-Type must be application/json"}

常见原因: 发了 JSON 但 Header 写成了 application/x-www-form-urlencoded

422 Unprocessable Entity ⭐⭐

场景: JSON 格式正确,但业务规则不满足

http 复制代码
POST /api/orders HTTP/1.1

{"productId": 1, "quantity": -5}    ← 数量不能为负数

HTTP/1.1 422 Unprocessable Entity

{"error": "Validation failed", "fields": {"quantity": "must be greater than 0"}}

和 400 的区别: 400 偏「格式/语法错误」;422 偏「格式对,但语义/业务规则不通过」。很多框架两者混用,知道即可。

429 Too Many Requests ⭐⭐

场景: 接口被限流(防刷、API 配额)

http 复制代码
GET /api/data HTTP/1.1

HTTP/1.1 429 Too Many Requests
Retry-After: 60

{"error": "Rate limit exceeded, max 100 requests per minute"}

举例: 1 分钟内调了 200 次接口;短信验证码连点 5 次;爬虫被抓。

怎么解决:Retry-After 秒数后重试;加缓存;降低调用频率。


5xx 服务器错误(⭐⭐⭐ 需要后端/运维排查)

5xx = 服务端的问题,前端通常无法自行修复,应记录请求信息并联系后端。

500 Internal Server Error ⭐⭐⭐

场景 1: 后端代码 bug(空指针)

http 复制代码
GET /api/orders/9527 HTTP/1.1

HTTP/1.1 500 Internal Server Error

{"error": "Internal server error"}    ← 生产环境通常不暴露细节

场景 2: 数据库连接失败

复制代码
后端日志:Connection refused: mysql://localhost:3306
前端看到:500 Internal Server Error

场景 3: 未捕获的异常

python 复制代码
# 后端代码
name = order.customer.name   # customer 是 null → 500
502 Bad Gateway ⭐⭐

场景: Nginx/网关前面的服务正常,但后面的应用挂了

复制代码
用户 → Nginx(正常)→ Java 应用(进程挂了)→ 502
http 复制代码
GET /api/users HTTP/1.1

HTTP/1.1 502 Bad Gateway

<html><body>502 Bad Gateway</body></html>

常见原因: 后端进程崩溃;Docker 容器重启中;upstream 地址配错;端口不通。

和 500 的区别: 500 是应用自己 报错;502 是网关连不上应用

503 Service Unavailable ⭐⭐

场景 1: 系统维护

http 复制代码
GET /api/users HTTP/1.1

HTTP/1.1 503 Service Unavailable
Retry-After: 3600

{"error": "System maintenance, back at 18:00"}

场景 2: 过载/熔断

复制代码
流量突增 → 服务器扛不住 → 主动返回 503 保护系统

你怎么应对:Retry-After 头;稍后重试;联系运维确认是否在维护。

504 Gateway Timeout ⭐⭐

场景: 后端处理太慢,网关等超时了

http 复制代码
POST /api/reports/generate HTTP/1.1    ← 生成报表要 5 分钟

HTTP/1.1 504 Gateway Timeout

{"error": "Gateway timeout after 60s"}

常见原因: 慢 SQL;导出大数据;第三方 API 响应慢;Nginx proxy_read_timeout 太短。

怎么解决: 优化后端性能;改为异步任务(先返回 202,完成后通知);调大网关超时。

507 Insufficient Storage ⭐

场景: 服务器磁盘满了,无法写入

你什么时候遇到: 自建服务器、网盘类应用。云 SaaS 较少直接暴露 507。


在 Chrome DevTools 里看状态码
  1. F12 打开开发者工具

  2. 切到 Network(网络) 标签

  3. 刷新页面或触发请求

  4. Status 列:200 绿色、3xx/4xx/5xx 通常橙色或红色

    Name Status Type
    users 200 xhr ← 成功
    login 401 xhr ← Token 失效,要重新登录
    orders/999 404 xhr ← 订单不存在
    upload 413 xhr ← 文件太大
    api/data 502 xhr ← 后端挂了,找运维

1.7 HTTP vs HTTPS

特性 HTTP HTTPS
端口 80 443
加密 明文传输 TLS/SSL 加密
证书 不需要 需要 CA 证书
安全性 低(可被窃听/篡改)
性能 无 TLS 握手开销 首次连接需 TLS 握手(约 1~2 RTT)

HTTPS(超文本传输安全协议) 就是 HTTP 的安全加强版 。简单说,它等于 HTTP + SSL/TLS 加密层

它的核心价值在于解决了 HTTP 最致命的缺陷------明文传输。在 HTTP 下,你的账号密码、聊天记录在网络中像"裸奔"一样能被任何人窃取或篡改,而 HTTPS 通过加密手段,将这些信息装进了一个只有收发双方才能打开的"保险箱"里。

具体来说,HTTPS 做了三件关键的事:

  1. 数据加密(防窃听):将传输内容打乱成乱码,即使黑客截获了数据包,看到的也是一堆无意义的密文。

  2. 数据完整性(防篡改):确保数据在传输过程中没有被中间人偷偷修改或调包。

  3. 身份验证(防冒充) :通过数字证书验证服务器确实是它声称的那个网站(比如你访问银行网站,证书能证明它真的是银行,而不是钓鱼网站)。

为了实现这些,HTTPS 采用了混合加密 策略:握手阶段 使用非对称加密 (公钥/私钥)安全地交换密钥;数据传输阶段 则改用对称加密,这种算法计算量小、速度快,保证了用户体验。
#mermaid-svg-6BDX3ypdPyLBWxb0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6BDX3ypdPyLBWxb0 .error-icon{fill:#552222;}#mermaid-svg-6BDX3ypdPyLBWxb0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6BDX3ypdPyLBWxb0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .marker.cross{stroke:#333333;}#mermaid-svg-6BDX3ypdPyLBWxb0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6BDX3ypdPyLBWxb0 p{margin:0;}#mermaid-svg-6BDX3ypdPyLBWxb0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .cluster-label text{fill:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .cluster-label span{color:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .cluster-label span p{background-color:transparent;}#mermaid-svg-6BDX3ypdPyLBWxb0 .label text,#mermaid-svg-6BDX3ypdPyLBWxb0 span{fill:#333;color:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .node rect,#mermaid-svg-6BDX3ypdPyLBWxb0 .node circle,#mermaid-svg-6BDX3ypdPyLBWxb0 .node ellipse,#mermaid-svg-6BDX3ypdPyLBWxb0 .node polygon,#mermaid-svg-6BDX3ypdPyLBWxb0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .rough-node .label text,#mermaid-svg-6BDX3ypdPyLBWxb0 .node .label text,#mermaid-svg-6BDX3ypdPyLBWxb0 .image-shape .label,#mermaid-svg-6BDX3ypdPyLBWxb0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-6BDX3ypdPyLBWxb0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .rough-node .label,#mermaid-svg-6BDX3ypdPyLBWxb0 .node .label,#mermaid-svg-6BDX3ypdPyLBWxb0 .image-shape .label,#mermaid-svg-6BDX3ypdPyLBWxb0 .icon-shape .label{text-align:center;}#mermaid-svg-6BDX3ypdPyLBWxb0 .node.clickable{cursor:pointer;}#mermaid-svg-6BDX3ypdPyLBWxb0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .arrowheadPath{fill:#333333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6BDX3ypdPyLBWxb0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6BDX3ypdPyLBWxb0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6BDX3ypdPyLBWxb0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6BDX3ypdPyLBWxb0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .cluster text{fill:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 .cluster span{color:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6BDX3ypdPyLBWxb0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6BDX3ypdPyLBWxb0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-6BDX3ypdPyLBWxb0 .icon-shape,#mermaid-svg-6BDX3ypdPyLBWxb0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6BDX3ypdPyLBWxb0 .icon-shape p,#mermaid-svg-6BDX3ypdPyLBWxb0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6BDX3ypdPyLBWxb0 .icon-shape .label rect,#mermaid-svg-6BDX3ypdPyLBWxb0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6BDX3ypdPyLBWxb0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6BDX3ypdPyLBWxb0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6BDX3ypdPyLBWxb0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTPS(加密)
HTTP
TLS 加密层
TCP
HTTP(明文)
HTTP
TCP

日期:2026-07-10

相关推荐
hj2862511 小时前
Docker 核心知识点整理(网络 + Dockerfile + 原理 + 命令)
网络·docker·容器
so~what2 小时前
NTN全局控制器集中管理的优势
网络·ntn
normanhere2 小时前
华为S5735堆叠配置加华为AC S9700-S主备配置案例
网络
sdghterhd11 小时前
WebSocket 快速入门教程(附示例源码)
网络·websocket·网络协议
xy345312 小时前
Wireshark捕获过滤器——语法元素详解
网络·测试工具·渗透测试·wireshark
DLYSB_13 小时前
生命通道:如何用 HIS 医疗系统直连网络声光终端,打造“零延误”的危急值响应网关?
java·网络·数据库·报警灯
德福危险13 小时前
富有想象力的XSS盲打:靶机练习之Tempus_fugit5
服务器·网络·xss
哥是强混15 小时前
Means:基于 .NET 10 打造的开源自部署 S3 兼容对象存储服务
网络·数据库·.net
Piko61416 小时前
锐捷 VSU 虚拟化堆叠配置
运维·网络·笔记