概述
简介
- 超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在 TCP 之上。
- HTTP 是应用层协议。
- HTTP 是一种无状态协议,即服务器不保留与客户交易时的任何状态。
前言
- 因特网协议栈共有五层:
- 应用层:主要的协议有:http、ftp、telnet、smtp、pop3 等。
- 传输层:TCP 和用户数据报协议 UDP。
- 网络层:负责将数据报独立地从信源发送到信宿,主要解决路由选择、拥塞控制和网络互联等问题。
- 数据链路层:负责将 IP 数据报封装成合适在物理网络上传输的帧格式并传输,或将从物理网络接收到的帧解封,取出 IP 数据报交给网络层。
- 物理层:负责将比特流在结点间传输,即负责物理传输。该层的协议既与链路有关也与传输介质有关
- OSI 模型共分七层:
- 应用层指网络操作系统和具体的应用程序,对应 WWW 服务器、FTP 服务器等应用软件
- 表示层数据语法的转换、数据的传送等
- 会话层 建立起两端之间的会话关系,并负责数据的传送
- 传输层 负责错误的检查与修复,以确保传送的质量,是 TCP 工作的地方。(报文)
- 网络层 提供了编址方案,IP 协议工作的地方(数据包)
- 数据链路层将由物理层传来的未经处理的位数据包装成数据帧
- 物理层 对应网线、网卡、接口等物理设备(位)。
历史
- HTTP/0.9 1991
- 服务器发送完毕,就关闭 TCP 连接。
- 0.9 协议就是一个交换信息的无序协议,仅仅限于文字
- HTTP/1.0 1996
- HTTP/1.0 版的主要缺点是,每个 TCP 连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。TCP 新建成本很高。所以,HTTP 1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。
Connection: keep-alive
解决,复用 tcp,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。
- HTTP/1.1 1997
- 它进一步完善了 HTTP 协议,引入管道,可以发多个请求
Connection: keep-alive
默认不关闭,Connection: close
关闭,目前,对于同一个域名,大多数浏览器允许同时建立 6 个持久连接。
- HTTP/2
- 谷歌自研升级,它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了。
二进制
HTTP/1.1 版的头信息肯定是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。多路复用
HTTP/2 复用 TCP 连接, 举例来说,在一个 TCP 连接里面,服务器同时收到了 A 请求和 B 请求,于是先回应 A 请求,结果发现处理过程非常耗时,于是就发送 A 请求已经处理好的部分, 接着回应 B 请求,完成后,再发送 A 请求剩下的部分。 这样双向的、实时的通信,就叫做多工(Multiplexing)。头部压缩
gzip,compress 压缩,头部索引,提高头部复用。数据流
帧是最小单位,帧可以标识哪个流,客奇服偶,可以取消发到一半的数据流,同时保证 tcp 连接依然打开。服务器推送
服务器主动推送如静态资源到客户端。
相关问题
前端对 http 的优化
- 减少静态资源文件大小
- Content-Encoding: gzip
- 使用预加载:预加载需要了解 preload 和 prefetch 的知识。
- 合理使用 defer 和 async
- 利用缓存
- 使用 CDN
tcp 为什么需要三次握手,两次不行吗?
- 第一次握手:客户端发送网络包,服务端收到了。 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
- 第二次握手:服务端发包,客户端收到了。 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
- 第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
- 因此,需要三次握手才能确认双方的接收与发送能力是否正常。
- 如果是两次握手
如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。
后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,
其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,
延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,
于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,
此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。
- 第一次握手完,半连队列;全连接队列,就是已经完成三次握手。
- 第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
###ISN(Initial Sequence Number)是固定的吗?
- 当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。
ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器,每4ms加1 。
这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
SYN攻击是什么?
- 服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,
所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,
并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,
因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,
从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。 - 检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,
基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。 - netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
挥手为什么需要四次?
- 因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。
其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,
很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。
只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
CSRF
- CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。
https 过程
- HTTPS 是由 HTTP 和 SSL/TLS 一起合作完成的。
- HTTPS 为了兼顾安全与效率,同时使用了对称加密和非对称加密。
- 数据是被对称加密传输的,对称加密过程需要客户端的一个密钥, 为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,
- 总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。
- 为什么要使用对称加密?
- 非对称加密基于大数运算,比如大素数或者椭圆曲线,是复杂的数学难题,所以消耗计算量,运算速度慢。
- 除了慢,可能还有一个缺点就是需要更多的位数,相同强度的对称密钥要比非对称密钥短。
- 对称密钥一般都 128 位、256 位,而 rsa 一般要 2048 位,不过椭圆曲线的会短一点
Http 和 Https 区别
- HTTP 协议传输的数据都是未加密的,也就是明文的,因此使用 HTTP 协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了 SSL(Secure Sockets Layer)协议用于对 HTTP 协议传输的数据进行加密,从而就诞生了 HTTPS。简单来说,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 http 协议安全。 HTTPS 和 HTTP 的区别主要如下:
- 总的来说: HTTPS=SSL+HTTP
- https 协议需要到 ca 申请证书,一般免费证书较少,因而需要一定费用。
- http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议。
- http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
(这个只是默认端口不一样,实际上端口是可以改的) - http 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 http 协议安全。
Http 头部
- general:
- Cache-Control 控制缓存 ✨
- Connection 连接管理、逐条首部 ✨
- Upgrade 升级为其他协议
- via 代理服务器的相关信息
- Wraning 错误和警告通知
- Transfor-Encoding 报文主体的传输编码格式 ✨
- Trailer 报文末端的首部一览
- Pragma 报文指令
- Date 创建报文的日期
- request:
- Accept 客户端或者代理能够处理的媒体类型 ✨
- Accept-Encoding 优先可处理的编码格式
- Accept-Language 优先可处理的自然语言
- Accept-Charset 优先可以处理的字符集
- If-Match 比较实体标记(ETage) ✨
- If-None-Match 比较实体标记(ETage)与 If-Match 相反 ✨
- If-Modified-Since 比较资源更新时间(Last-Modified)✨
- If-Unmodified-Since 比较资源更新时间(Last-Modified),与 If-Modified-Since 相反 ✨
- If-Rnages 资源未更新时发送实体 byte 的范围请求
- Range 实体的字节范围请求 ✨
- Authorization web 的认证信息 ✨
- Proxy-Authorization 代理服务器要求 web 认证信息
- Host 请求资源所在服务器 ✨
- From 用户的邮箱地址
- User-Agent 客户端程序信息 ✨
- Max-Forwrads 最大的逐跳次数
- TE 传输编码的优先级
- Referer 请求原始放的 url
- Expect 期待服务器的特定行为
- response
- Accept-Ranges 能接受的字节范围
- Age 推算资源创建经过时间
- Location 令客户端重定向的 URI ✨
- vary 代理服务器的缓存信息
- ETag 能够表示资源唯一资源的字符串 ✨
- WWW-Authenticate 服务器要求客户端的验证信息
- Proxy-Authenticate 代理服务器要求客户端的验证信息
- Server 服务器的信息 ✨
- Retry-After 和状态码 503 一起使用的首部字段,表示下次请求服务器的时间
浏览器输入 URL 到页面展示的过程
- 首先,在浏览器地址栏中输入 url,先解析 url,检测 url 地址是否合法
- 浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
- 浏览器缓存:浏览器会记录 DNS 一段时间,因此,只是第一个地方解析 DNS 请求;
- 操作系统缓存:如果在浏览器缓存中不包含这个记录,则会使系统调用操作系统,获取操作系统的记录(保存最近的 DNS 查询缓存);
- 路由器缓存:如果上述两个步骤均不能成功获取 DNS 记录,继续搜索路由器缓存;
- ISP 缓存:若上述均失败,继续向 ISP 搜索。
- 在发送 http 请求前,需要域名解析(DNS 解析),解析获取相应的 IP 地址。
- 浏览器向服务器发起 tcp 连接,与浏览器建立 tcp 三次握手。
- 握手成功后,浏览器向服务器发送 http 请求,请求数据包。
- 服务器处理收到的请求,将数据返回至浏览器
- 浏览器收到 HTTP 响应
- 浏览器解码响应,如果响应可以缓存,则存入缓存。
- 浏览器发送请求获取嵌入在 HTML 中的资源(html,css,javascript,图片,音乐······)。
- 浏览器发送异步请求。
- 页面全部渲染结束。
浏览器缓存位置,按优先级排序如下:
- Service Worker
- Service Worker 是一项比较新的 Web 技术,是 Chromium 团队在吸收了 ChromePackaged App 的 Event Page 机制,同时吸取了 HTML5 AppCache 标准失败的教训之后,提出一套新的 W3C 规范,旨在提高 WebApp 的离线缓存能力,缩小 WebApp 与 NativeApp 之间差距。 Service Worker 从英文翻译过来就是一个服务工人,服务于前端页面的后台线程,基于 Web Worker 实现。有着独立的 js 运行环境,分担、协助前端页面完成前端开发者分配的需要在后台悄悄执行的任务。基于它可以实现拦截和处理网络请求、消息推送、静默更新、事件同步等服务。
'serviceWorker' in navigator
判断是否支持,无法访问 DOM- service worker 必须是 https
- 优势和应用场景
- 离线缓存:可以将 H5 应用中不变化的资源或者很少变化的资源长久的存储在用户端,提升加载速度、降低流量消耗、降低服务器压力。如中重度的 H5 游戏、框架数据独立的 web 资讯客户端、web 邮件客户端等
- 消息推送:激活沉睡的用户,推送即时消息、公告通知,激发更新等。如 web 资讯客户端、web 即时通讯工具、h5 游戏等运营产品。
- 事件同步:确保 web 端产生的任务即使在用户关闭了 web 页面也可以顺利完成。如 web 邮件客户端、web 即时通讯工具等。
- 定时同步:周期性的触发 Service Worker 脚本中的定时同步事件,可借助它提前刷新缓存内容。如 web 资讯客户端。
- Memory Cache
- 内存缓存,存在内存中,读取效率高,生存时间短,tab 页关闭就释放。
- 不关心 http 缓存头 cache-control 的值,
- Disk Cache
- 存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。
- 覆盖面基本是最大的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。
- Push Cache
- Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在 Chrome 浏览器中只有 5 分钟左右,同时它也并非严格执行 HTTP 头中的缓存指令。
浏览器缓存策略
- 强缓存和协商缓存,并且缓存策略都是通过设置 HTTP Header 来实现的。
- 浏览器请求的过程:浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识;浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中;
- 强缓存:
- 不会向服务器发送请求,直接从缓存中读取资源,在 chrome 控制台的 Network 选项中可以看到该请求返回 200 的状态码,并且 Size 显示 from disk cache 或 from memory cache。强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control。
- 其实这两者差别不大,区别就在于 Expires 是 http1.0 的产物,Cache-Control 是 http1.1 的产物,两者同时存在的话,Cache-Control 优先级高于 Expires;在某些不支持 HTTP1.1 的环境下,Expires 就会发挥用处。所以 Expires 其实是过时的产物,现阶段它的存在只是一种兼容性的写法。 强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存策略。
- 协商缓存:
- 协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:协商缓存生效,返回 304 和 Not Modified / 协商缓存失效,返回 200 和请求结果。协商缓存可以通过设置两种 HTTP Header 实现:Last-Modified 和 ETag 。
Last-Modified / If-Modified-Since
弊端:如果本地打开缓存文件,即使没有对文件进行修改,但还是会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源 因为 Last-Modified 只能以秒计时,如果在不可感知的时间内修改完成文件,那么服务端会认为资源还是命中了,不会返回正确的资源Etag / If-None-Match
是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag 就会重新生成。- 两者之间对比:
- 首先在精确度上,Etag 要优于 Last-Modified。
- Last-Modified 的时间单位是秒,如果某个文件在 1 秒内改变了多次,那么他们的 Last-Modified 其实并没有体现出来修改,但是 Etag 每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的 Last-Modified 也有可能不一致。
- 性能上,Etag 要逊于 Last-Modified,毕竟 Last-Modified 只需要记录时间,而 Etag 需要服务器通过算法来计算出一个 hash 值。
- 优先级上,服务器校验优先考虑 Etag
浏览器缓存机制
- 强制缓存优先于协商缓存进行,若强制缓存(Expires 和 Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since 和 Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回 200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回 304,继续使用缓存。
浏览器缓存应用
- 频繁变动的资源。Cache-Control: no-cache
- 不常变化的资源。Cache-Control: max-age=31536000。(如 jquery-3.3.1.min.js, lodash.min.js 等) 均采用这个模式。
浏览器缓存与用户的行为
- 所谓用户行为对浏览器缓存的影响,指的就是用户在浏览器如何操作时,会触发怎样的缓存策略。主要有 3 种:
- 打开网页,地址栏输入地址: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求。
- 普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。
- 强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(为了兼容,还带了 Pragma: no-cache),服务器直接返回 200 和最新内容。
Http 状态码
- 2XX 成功
- 200 请求已成功,请求所希望的响应头或数据体将随此响应返回。
- 201 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI 已经随 Location 头信息返回
- 202 服务器已接受请求,但尚未处理
- 3XX 重定向
- 301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
- 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
- 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
- 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
- 305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
- 307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
- 302 是 http1.0 的协议状态码,在 http1.1 版本的时候为了细化 302 状态码又出来了两个 303 和 307。
303 明确表示客户端应当采用 get 方法获取资源,他会把 POST 请求变为 GET 请求进行重定向。
307 会遵照浏览器标准,不会从 post 变为 get。
- 302 是 http1.0 的协议状态码,在 http1.1 版本的时候为了细化 302 状态码又出来了两个 303 和 307。
- 4XX 客户端错误
- 401 当前请求需要用户验证。如果当前请求已经包含了 Authorization 证书,那么 401 响应代表着服务器验证已经拒绝了那些证书
- 403 服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交
- 404 请求失败,请求所希望得到的资源未被在服务器上发现
- 5XX 服务端错误
- 500 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。
- 501 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
- 502 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
- 503 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。
CDN 是什么
- CDN的全称是Content Delivery Network,即内容分发网络。
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,
通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,
降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
Ajax
- Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),
var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象
request.onreadystatechange = function () {
// 状态发生变化时,函数被回调
if (request.readyState === 4) {
// 成功完成
// 判断响应结果:
if (request.status === 200) {
// 成功,通过responseText拿到响应的文本:
return request.responseText;
} else {
// 失败,根据响应码判断失败原因:
return request.status;
}
} else {
// HTTP请求还在继续...
}
};
// 发送请求:
request.open("GET", "/api/categories");
request.send();
最后
以上就是忐忑小甜瓜为你收集整理的【温故知新】Http简介前言历史相关问题的全部内容,希望文章能够帮你解决【温故知新】Http简介前言历史相关问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复