1、什么是预检请求(OPTIONS)?什么时候会触发?
答:预检请求是浏览器在跨域请求前自动发送的一次HTTP OPTIONS 请求,用来确认服务端是否允许真正的跨域请求。它不会携带实际的业务数据,只是一个安全检查。比如浏览器发请求时,先问服务器:“我打算用 POST 方法,带着 application/json 这种 Content-Type,访问你的接口,你允许吗?”,服务器必须返回一些响应头(如Access-Control-Allow-Origin),浏览器确认后,才会继续发真正的请求。
- 不是所有跨域请求都会预检,只有
非简单请求才会。 - 简单请求(不会触发预检):满足以下三个条件的才算“简单”:
- 方法:只允许
GET、HEAD、POST - 请求头:只能是浏览器默认的一些安全字段(如
Accept、Content-Type: application/x-www-form-urlencoded | multipart/form-data | text/plain) - 简单请求浏览器直接发,不预检。
- 方法:只允许
- 非简单请求(会触发预检)
- 只要不符合上面的条件,就会触发
OPTIONS 预检请求,常见情况有:- 使用了
PUT、DELETE、PATCH等方法 - 请求头里带了自定义字段,比如
Authorization、X-Custom-Header Content-Type不是三种简单类型之一,比如:application/json、text/xml
- 使用了
- 只要不符合上面的条件,就会触发
怎么减少预检请求?
- 避免非简单请求
- 比如能用
application/x-www-form-urlencoded就别用application/json
- 比如能用
- 服务端设置
Access-Control-Max-Age让浏览器缓存预检结果,比如 10 分钟内相同的跨域请求就不再预检 - 合理设计 API:比如把不必要的
PUT/DELETE改为POST
2、Content-Type 类型有哪些?常见表单上传分别用什么类型?
答:常见的Content-Type类型:
- 文本类型
text/html——HTML文档text/plain—— 普通文本text/css——CSS文件text/javascript/application/javascript——JS脚本
JSON / XMLapplication/json——JSON数据(常见于AJAX请求)application/xml/text/xml——XML格式
- 表单类型
application/x-www-form-urlencoded- 默认的
HTML <form>提交方式 - 数据会编码为
key1=value1&key2=value2;比如:username=Tom&age=18
- 默认的
multipart/form-data- 上传文件或二进制数据时用
- 表单数据会被分割成多部分(每个字段一块),支持文件上传
- 常见于
<form enctype="multipart/form-data">
text/plain- 也是表单支持的类型(
<form enctype="text/plain">) - 直接以纯文本发送,不常用
- 也是表单支持的类型(
- 文件 / 二进制
application/octet-stream二进制流,通用文件下载时常用(不知道文件类型时的兜底类型)image/png、image/jpeg、image/gif等video/mp4、audio/mpeg等
表单上传常见Content-Type
- 普通表单提交(默认)
Content-Type: application/x-www-form-urlencoded适合纯文本数据,比如用户名、密码。
- 文件上传(带
input type="file")Content-Type: multipart/form-data必须加enctype="multipart/form-data"才行,否则文件内容不会被上传。
Ajax JSON提交Content-Type: application/json常见于fetch或axios提交JSON格式请求体
- 纯文本上传
Content-Type: text/plain几乎不用,除非就是发个纯字符串。
3、一次完整的 HTTP 请求过程包含哪些步骤?
答:一次完整的HTTP请求主要有以下几个过程:URL解析 → DNS解析 → TCP连接 → TLS握手 → 发送HTTP请求 → 服务器处理 → 响应返回 → 浏览器渲染 → 缓存/复用
URL 解析:浏览器收到URL,比如:https://www.example.com:443/path/file.html?query=1#hash;会拆解成:协议(Scheme):https;域名(Host):www.example.com;端口(Port):443(HTTPS 默认);路径(Path):/path/file.html;查询参数(Query):?query=1;锚点(Fragment):#hash,不发送给服务器DNS解析- 浏览器检查本地
DNS 缓存→ 主机文件 → 操作系统缓存 →递归 DNS 查询 - 最终获取服务器 IP 地址
- 优化手段:
dns-prefetch提前解析域名;CDN / Anycast加速解析
- 浏览器检查本地
TCP连接- 浏览器向服务器
IP建立TCP连接(三次握手) HTTP/1.x每个域名多个连接(浏览器通常 6 个)HTTP/2/HTTP/3多路复用减少连接数量(一个 TCP 连接可以承载多个请求)
- 浏览器向服务器
TLS/SSL握手(HTTPS)- 如果是 HTTPS:
- 客户端发送 ClientHello
- 服务端返回 ServerHello + 证书
- 客户端验证证书 → 协商加密密钥
- 双方用对称密钥加密后续通信
- HTTP/3 基于 QUIC (UDP + TLS 1.3),握手更快
- 如果是 HTTPS:
- 发送 HTTP 请求
- 构建请求行 + 请求头 + 可选请求体
- 浏览器发送到服务器
- 服务器处理请求
- 服务器接收到请求:
- 路由匹配 → 找到对应资源/接口
- 可能经过中间件(CDN、负载均衡)
- 返回响应头 + 响应体
- 服务器接收到请求:
- 浏览器接收响应
- 状态码:
200 / 304 / 404 / 500 - 响应头:
Cache-Control, Set-Cookie, Content-Type等 - 响应体:
HTML / JSON / 图片 / JS等
- 状态码:
- 浏览器渲染页面
- 解析
HTML→ 构建DOM - 解析
CSS→ 构建CSSOM - 生成
Render Tree→ 布局 → 绘制 - 执行
JS→ 更新DOM / CSSOM / Layout
- 解析
- 缓存 & 连接复用
- 浏览器根据响应头判断是否缓存
TCP/QUIC连接可能保持复用,用于后续请求