# Http (opens new window)
# 001. HTTP 报文结构是怎样的?
http
起始行 + 头部 + 空行 + 实体
- 请求报文
- 起始行 GET /home HTTP/1.1
- 头部 请求头
- 空行 区分头部和实体
- 实体 请求体
- 响应报文
- 起始行/状态行 HTTP/1.1 200 OK
- 响应头
- 空行 区分头部和实体
- 实体 响应体
# 002. 如何理解 HTTP 的请求方法?
- GET: 通常用来获取资源
- HEAD: 获取资源的元信息
- POST: 提交数据,即上传数据
- PUT: 修改数据
- DELETE: 删除资源(几乎用不到)
- CONNECT: 建立连接隧道,用于代理服务器
- OPTIONS: 列出可对资源实行的请求方法,用来跨域请求
- TRACE: 追踪请求-响应的传输路径
GET 和 POST 有什么区别?
- 缓存
- 编码
- 参数
- 幂等性
- TCP
# 003: 如何理解 URI?
URI 包含了 URN 和 URL
# URI 的结构
scheme user:passwd@ host:port path query fragment
# URI 编码
URI 引入了编码机制,将所有非 ASCII 码字符和界定符转为十六进制字节值,然后在前面加个%
# 004: 如何理解 HTTP 状态码?
五类
- 1xx: 表示目前是协议处理的中间状态,还需要后续操作。
- 2xx: 表示成功状态。
- 3xx: 重定向状态,资源位置发生变动,需要重新请求。
- 4xx: 请求报文有误。
- 5xx: 服务器端发生错误
# 1XX
101 Switching Protocols。在 HTTP 升级为 WebSocket 的时候,如果服务器同意变更,就会发送状态码 101
# 2XX
200 OK 是见得最多的成功状态码。通常在响应体中放有数据。 204 No Content 含义与 200 相同,但响应头后没有 body 数据。 206 Partial Content 顾名思义,表示部分内容,它的使用场景为 HTTP 分块下载和断点续传,当然也会带上相应的响应头字段 Content-Range。
# 3XX
301 Moved Permanently 即永久重定向,对应着 302 Found,即临时重定向。
比如你的网站从 HTTP 升级到了 HTTPS 了,以前的站点再也不用了,应当返回 301,这个时候浏览器默认会做缓存优化,在第二次访问的时候自动访问重定向的那个地址。
而如果只是暂时不可用,那么直接返回 302 即可,和 301 不同的是,浏览器并不会做缓存优化。
304 Not Modified: 当协商缓存命中时会返回这个状态码。详见浏览器缓存
# 4XX
400 Bad Request: 开发者经常看到一头雾水,只是笼统地提示了一下错误,并不知道哪里出错了。
403 Forbidden: 这实际上并不是请求报文出错,而是服务器禁止访问,原因有很多,比如法律禁止、信息敏感。
404 Not Found: 资源未找到,表示没在服务器上找到相应的资源。
405 Method Not Allowed: 请求方法不被服务器端允许。
406 Not Acceptable: 资源无法满足客户端的条件。
408 Request Timeout: 服务器等待了太长时间。
409 Conflict: 多个请求发生了冲突。
413 Request Entity Too Large: 请求体的数据过大。
414 Request-URI Too Long: 请求行里的 URI 太大。
429 Too Many Request: 客户端发送的请求过多。
431 Request Header Fields Too Large 请求头的字段内容太大。
# 5XX
500 Internal Server Error: 仅仅告诉你服务器出错了,出了啥错咱也不知道。
501 Not Implemented: 表示客户端请求的功能还不支持。
502 Bad Gateway: 服务器自身是正常的,但访问的时候出错了,啥错误咱也不知道。
503 Service Unavailable: 表示服务器当前很忙,暂时无法响应服务。
# 005: 简要概括一下 HTTP 的特点?HTTP 有哪些缺点
# HTTP 特点
- 灵活可扩展
- 可靠传输
- 请求-应答
- 无状态
# 缺点
# 无状态
# 明文传输
# 队头阻塞
当 http 开启长连接时,共用一个 TCP 连接,同一时刻只能处理一个请求,那么当前请求耗时过长的情况下,其它的请求只能处于阻塞状态,也就是著名的队头阻塞问题
# 006: 对 Accept 系列字段了解多少?
对于 Accept 系列字段的介绍分为四个部分: 数据格式、压缩方式、支持语言和字符集。
总结
# 007: 对于定长和不定长的数据,HTTP 是怎么传输的?
# 定长包体
Content-Length
# 不定长包体
Transfer-Encoding: chunked
- Content-Length 字段会被忽略
- 基于长连接持续推送动态内容
chunk长度(16进制的数)
第一个chunk的内容
chunk长度(16进制的数)
第二个chunk的内容
......
0
# 008: HTTP 如何处理大文件的传输?
采取了范围请求的解决方案
Accept-Ranges: none
# Range 字段拆解
请求单段数据和请求多段数据,响应头是不一样的
# 单端数据
# 多段数据
# 009: HTTP 中如何处理表单数据的提交?
Content-Type:application/x-www-form-urlencoded
Content-Type:multipart/form-data
# x-www-form-urlencoded
- 其中的数据会被编码成以&分隔的键值对
- 字符以 URL 编码方式编码。
# multipart/form-data
- 请求头中的 Content-Type 字段会包含 boundary,且 boundary 的值有浏览器默认指定。例: Content-Type: multipart/form-data;boundary=----WebkitFormBoundaryRRJKeWfHPGrS4LKe。
- 数据会分为多个部分,每两个部分之间通过分隔符来分隔,每部分表述均有 HTTP 头部描述子包体,如 Content-Type,在最后的分隔符会加上--表示结束。
form-data、x-www-form-urlencoded 的区别 (opens new window)
multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息; x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。
# 总结
值得一提的是,multipart/form-data 格式最大的特点在于:每一个表单元素都是独立的资源表述。另外,你可能在写业务的过程中,并没有注意到其中还有 boundary 的存在,如果你打开抓包工具,确实可以看到不同的表单元素被拆分开了,之所以在平时感觉不到,是以为浏览器和 HTTP 给你封装了这一系列操作。
而且,在实际的场景中,对于图片等文件的上传,基本采用 multipart/form-data 而不用 application/x-www-form-urlencoded,因为没有必要做 URL 编码,带来巨大耗时的同时也占用了更多的空间。
# 010: HTTP1.1 如何解决 HTTP 的队头阻塞问题?
# 什么是 HTTP 队头阻塞?
请求任务被放在一个任务队列中串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理
# 并发连接
对于一个域名允许分配多个长连接,那么相当于增加了任务队列
Chrome 中是 6 个。
# 域名分片
多域名或多二级域名
# 011: 对 Cookie 了解多少?
// 请求头
Cookie: a=xxx;b=xxx
// 响应头
Set-Cookie: a=xxx
set-Cookie: b=xxx
# Cookie 属性
# 生存周期
Expires 即过期时间 Max-Age 用的是一段时间间隔,单位是秒,从浏览器收到报文开始计算。
# 作用域
Domain 和 path, 给 Cookie 绑定了域名和路径,在发送请求之前,发现域名或者路径和这两个属性不匹配,那么就不会带上 Cookie。值得注意的是,对于路径来说,/表示域名下的任意路径都允许使用 Cookie。
# 安全相关
Secure 说明只能通过 HTTPS 传输 cookie HttpOnly 只能通过 HTTP 协议传输,不能通过 JS 访问,这也是预防 XSS 攻击的重要手段。 SameSite = Strict、Lax 和 None
Strict 浏览器完全禁止第三方请求携带 Cookie Lax get 方法提交表单况或者 a 标签发送 get 请求的情况下可以携带 Cookie None 请求会自动携带上 Cookie
# Cookie 的缺点
- 容量缺陷。Cookie 的体积上限只有 4KB,只能用来存储少量的信息
- 性能缺陷 有时候并不需要的时候带上了 cookie 带上以后有损耗
- 安全缺陷
- 纯文本的形式在浏览器和服务器中传递,很容易被非法用户截获并篡改
- 在 HttpOnly 为 false 的情况下,Cookie 信息能直接通过 JS 脚本来读取。
# 012: 如何理解 HTTP 代理?
请求先到代理服务器 由代理服务器发起实际请求
负载均衡
保障安全
缓存代理
# 相关头部字段
# Via
Via 中代理的顺序即为在 HTTP 传输中报文传达的顺序
# X-Forwarded-For
字面意思就是为谁转发, 它记录的是请求方的 IP 地址(注意,和 Via 区分开,X-Forwarded-For 记录的是请求方这一个 IP)。
# X-Real-IP
# 013: 如何理解 HTTP 缓存及缓存代理?
# 代理缓存
# 源服务器的缓存控制
# private 和 public
private 或者 public 表示是否允许代理服务器缓存,前者禁止,后者为允许
# proxy-revalidate
must-revalidate 的意思是客户端缓存过期就去源服务器获取,而 proxy-revalidate 则表示代理服务器的缓存过期后到源服务器获取。
# s-maxage
限定了缓存在代理服务器中可以存放多久
例子
Cache-Control: public, max-age=1000, s-maxage=2000
我这个响应是允许代理服务器缓存的,客户端缓存过期了到代理中拿,并且在客户端的缓存时间为 1000 秒,在代理服务器中的缓存时间为 2000 s。
# 客户端的缓存控制
max-stale 缓存进行宽容 min-fresh 缓存进行限制 only-if-cached 只会接受代理缓存
# 014: 什么是跨域?浏览器如何拦截响应?如何解决?
同源政策(scheme(协议)、host(主机)和 port(端口)都相同则为同源)
# 跨域的方案
# CORS
# 简单请求
- 请求方法为 GET、POST 或者 HEAD
- 请求头的取值范围: Accept、Accept-Language、Content-Language Content-Type
- Content-Type(只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain)
浏览器自动在请求头当中,添加一个 Origin 字段
Access-Control-Allow-Origin
服务器用来决定浏览器是否拦截这个响应,这是必需的字段。与此同时,其它一些可选的功能性的字段,用来描述如果不会拦截,这些字段将会发挥各自的作用。
Access-Control-Allow-Credentials
是否允许发送 cookie withCredentials 客户端也需要设置
Access-Control-Expose-Headers
允许客户端可以拿到 除包括 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified 和 Pragma 外的响应头
# 非简单请求
预检请求
响应字段
# JSONP
script 标签不一样,它可以通过 src 填上目标地址从而发出 GET 请求,实现跨域请求并拿到响应
# Nginx
server {
listen 80;
server_name client.com;
location /api {
proxy_pass server.com;
}
}
# 015: TLS1.2 握手的过程是怎样的?
HTTPS = HTTP + SSL/TLS
# 浏览器缓存
# 强缓存
HTTP/1.0
Expires 过期时间
缺点:本地时间可修改
HTTP/1.1
Cache-Control
public:资源客户端和服务器都可以缓存。
privite:资源只有客户端可以缓存。
no-cache:客户端缓存资源,但是是否缓存需要经过协商缓存来验证。
no-store:不使用缓存。
max-age:缓存保质期。
状态码:200
# 协商缓存
HTTP/1.0
Last-Modified 响应头/ If-Modified-Since 请求头
HTTP/1.1
Etag 响应头/ If-None-Match 请求头
# 三次握手
三次握手,四次挥手”你真的懂吗 (opens new window)
# 四次挥手
关于 TCP 三次握手和四次挥手,满分回答在此 (opens new window)
参考文章:
(建议精读)HTTP 灵魂之问,巩固你的 HTTP 知识体系 (opens new window)
六张图从 HTTP/0.9 进化到 HTTP3.0 (opens new window)
https://juejin.cn/post/6908327746473033741 (opens new window)