深刻理解HTTP协议,巩固HTTP知识体系——长文,可收藏阅读

前言

若是你是中高级的前端工程师,相关HTTP问题,在面试的时候被问到的几率很高,且咱们项目中会大量遇到相关的问题。javascript

懒人指南:

若是你只是想快速的知道下边面试官常常问的问题的答案,能够略过正式部分(本文为HTTP知识详解部分,其中大量阅读书籍《图解HTTP》收获,和其余网上资料的总结),直接查看问题回答总结部分。css

问题:

若是面试官问你如下问题,你是否能答过来,能答几道呢?这也是常见的面试题,来试一试吧~html

  • 什么是三次握手?前端

  • TCP与UDP的区别?vue

  • 从输入URL到页面加载完成,发生了什么?html5

  • HTTP响应码你都知道哪些?都是什么意思?java

  • HTTP协议的工做流程?node

  • HTTP/1.0 和 1.1 现存的哪些问题webpack

  • HTTP与HTTPS区别nginx

  • 什么是长连接,为何须要长链接?

  • HTTP/2的信道复用又为何能提升性能?

  • HTTP的缓存机制

  • XSS和Crsf攻击都有哪些防范手段?

  • 如何高效利用缓存,上线前端代码?

    一、缓存时间过长,发布上线了,用户端还用缓存,会有bug

    二、缓存时间太短,重复加载文件过多,浪费带宽

其实上边的一些问题,在三面、四面的时候问前端性能优化(文件获取优化)的时候也是这些问题。

正式

在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议是HTTP 。 HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通讯。 HTTP协议属于应用层,创建在传输层协议TCP之上。客户端经过与服务器须要创建TCP链接,以后发送HTTP请求与接收HTTP响应都是经过访问Socket接口来调用TCP协议实现。 由于HTTP是不存在链接这个概念的,只有请求和响应,它们都是数据包。

网络基础及web

web简述

web:(网页浏览器web browser);

web页面不会凭空显示出来。根据Web浏览器地址栏中指定的URL,web浏览器从Web服务器获取资源等信息,从而显示出web页面。web使用HTTP(超文本传输协议)的协议做为规范,完成从客服端到服务器端等一系列运做流程。Web是简历在HTTP协议上的通讯。

协议:指定规则的约定;为了让计算机可以通讯,计算机须要定义通讯规则,这些规则就是协议;是数据封装格式+传输 ;协议有多种;

客户端:像这种经过发送请求获取服务资源的web浏览器等,均可以称为客户端(client)。

网络基础TCP/IP

为了了解HTTP,咱们必须先了解TCP/IP协议族因一般使用的网络(包括互联网)是在TCP/IP协议族的基础上运做的。而HTTP属于它内部的一个子集。

TCP/IP

把与互联网相关联的协议集合起来总成为TCP/IP。

也有认为:TCP/IP是指TCP和IP这两种协议。

还有认为:TCP/IP是IP协议的通讯过程当中,使用到的协议族的统称。

为何分层?

  • 将复杂的流程分解为几个功能相对单一的子进程
  • 整个流程更加清晰,复杂问题简单化
  • 更容易发现问题并针对性的解决问题

OSI七层网络模型

分层 功能 做用
应用层 网络服务于最终用户的一个接口 提供网络与用户应用软件之间的接口服务,屏蔽了网络传输相关细节
表示层 数据的表示、安全、压缩 提供格式化的表示和转换数据服务,如加密和压缩
会话层 创建、管理、停止会话 提供包括访问验证和会话管理在内的创建和维护应用之间通讯的机制
传输层 定义传输数据的协议端口号,以及留空和差错校验 一、提供创建、维护和取消传输链接功能,负责可靠地传输数据(PC);二、向用户提供可靠的(端到端end-to-end)服务;三、传输层向高层屏蔽了下层数据通讯的细节
网络层 进行逻辑地址寻址,实现不一样网络之间的路径选择 处理网络间路由,确保数据及时传送(路由器),数据包是网络传输的最小数据单位。该层规定了经过怎样的路径(传输路线)到达对方计算机,并把数据包传送给对方。
数据链路层 创建逻辑链接、进行硬件地址寻址、差错校验等功能 用来处理连接网络的硬件部分。负责无错传输数据,确认帧、发错重传等(交换机)
物理层 创建、维护、断开物理链接 定义物理设备如何传输数据;提供机械、电气、功能和过程特性(网卡、网线、双绞线、同轴电缆、中继器)

TCP/IP参考模型

网络五层结构

  • TCP/IP是传输控制协议/网络互联协议的简称
  • 早期的TCP/IP模型是一个四层结构,从下往上依次是网络接口层、互联网层、传输层和应用层
  • 后来在使用过程当中,借鉴OSI七层参考模型,将网络接口层划分为了物理层和数据链路层,造成五层结构
分层 协议
应用层 HTTP(超文本传输协议)、FTP(文件传输协议)、TFTP、SMTP(发送邮件)、SNMP、DNS(域名系统)。。。
传输层 TCP(传输控制协议)、UDP(用户数据报协议)。。。
网络层 ICMP(网际控制消息协议,发送消息,并报告有关数据包的传送错误)、IGMP(互联组管理协议,IP主机向本地多路广播路由器报告主机组成员)、IP(网际协议,负责主机和网络之间寻址和路由数据包)、ARP(地址解析协议,得到同一物理网络中的硬件主机MAC地址)。。。
数据链路层 由底层网络定义的协议
物理层 由底层网络定义的协议

数据包封装

上层协议数据是如何转变为下层协议数据的呢?

这是经过封装(encapsulate)来实现的。应用程序数据在发送到物理网络以前,会沿着协议栈从上往下传递。每层协议都将在上层协议数据的基础上加上本身的头部信息(链路层还会加上尾部信息),觉得实现该层功能提供必要的信息。 发送端发送数据时,数据会从上层传输到下层,且每通过一层都会被打上该层的头部信息。而接收端接收数据时,数据会从下层传输到上层,传输前会把下层的头部信息删除。

为何要这样封装呢?

因为下层协议的头部信息对上层协议是没有实际的用途,因此在下层协议传输数据给上层协议的时候会把该层的头部信息去掉,这个封装过程对于上层协议来讲是彻底透明的。这样作的好处是,应用层只须要关心应用服务的实现,而不用管底层的实现。

与HTTP关系亲密的协议:IP、TCP、DNS

一、IP

按层此分,IP位于网络层。在TCP/IP族中IP指网际协议,不要与IP地址混淆。

IP地址:指明了节点被分配到的地址,

MAC地址:是指网卡所属的固定地址;

IP地址能够和MAC地址进行配对,IP地址可变换,但MAC地址基本上不会更改。IP间的通讯依赖MAC地址。

不在同一个局域网时,咱们会采用ARP协议(是一种用于解析地址的协议),根据通讯方的IP地址就能够反查出对应的MAC地址。

二、TCP

客户端和服务端进行信息发送,是须要建立一个TCP链接的。按层此分,TCP(Transimision Control Protocal)位于传输层。提供可靠的字节流服务(为了方便传输将大块数据分割成以报文段为单位的数据包进行管理)。可靠的传输服务是指,可以把数据准确可靠的传给对方。

TCP 慢启动

TCP 链接会随着时间进行自我「调谐」,起初会限制链接的最大速度,若是数据成功传输,会随着时间的推移提升传输的速度。这种调谐则被称为 TCP 慢启动。

2.一、TCP功能:

  • 链接创建 : 主要是指TCP/IP的三次握手来创建链接
  • 将数据进行分段打包传输: 主要是实在网络传输过程当中的MTU(最大传输单元)决定的,数据必须打包成段才能够传送 ;
  • 对每一个数据包编号控制顺序: 数据打包成段后,须要按序列号排序来发送,保证数据的连贯性
  • 运输中丢失、重发和丢弃处理
  • 流量控制: 经过滑动窗口来进行流量的控制
  • 避免拥塞: 解决拥塞控制的办法是:采用慢启动和拥塞避免算法结合使用来控制拥塞

2.二、TCP的状态

常见的TCP状态有:CLOSED, LISTEN, SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT1, CLOSE_WAIT, FIN_WAIT2, LAST_ACK, TIME_WAIT, CLOSED。tcp协议经过tcp状态来标记当前处于通讯过程的哪一个阶段。

2.三、TCP协议与UDP协议

  • TCP(Transimision Control Protocal)
    • 传输控制协议
    • 可靠的、面向链接的协议
    • 传输效率低
  • UDP(User Datagram Protocal)
    • 用户数据报协议
    • 不可靠的、无链接的服务
    • 传输效率高
  • TCP与UDP的区别:能够看出 TCP协议相对于UDP协议的特色是:TCP协议提供面向链接、字节流和可靠的传输。

2.四、UDP的应用

  • QQ
  • 视频软件
  • TFTP 简单文件传输协议(短信)

2.五、三次握手、数据传输、四次挥手

为了防止服务器开启无用的连接。

2.5.一、三次握手

为了准确无误地将数据传送到目标处,TCP才用了三次握手策略。

注意:

  • TCP是面向链接的协议,它在源点和终点之间创建虚拟链接,而不是物理链接
  • 在数据通讯以前,发送端与接收端要先创建链接,等数据发送结束后,双方再断开链接
  • TCP链接的每一方都是由一个IP地址和一个端口组成
  • http是不存在链接这个概念的,只有请求和响应,他们都是数据包

具体过程以下:

**第一次握手:**客户端发送带有SYN标志的数据段连接请求报文段给服务端, 经过该数据段告诉服务端但愿创建链接,须要服务端应答,并告诉服务端传输的起始序列号,而后进入SYN_SEND状态,等待服务端的确认。

**第二次握手:**服务端接收到客户端的SYN报文段后,须要发送ACK信息对这个SYN报文段进行确认。同时,还要发送本身的SYN请求信息。 一是发送ACK告诉客户端收到了数据段,二是通知客户端从哪一个序列号作标记。服务端会将上述的信息放到一个报文段(SYN+ACK报文段)中,ack等于seq的值+1,一并发送给客户端,此时服务端将会进入SYN_RECV状态。

第三次握手:客户端接收到服务端的SYN+ACK报文段后,会想服务端发送ACK确认报文段,这个报文段发送完毕后,客户端和服务端都进入ESTABLISHED状态,完成TCP三次握手。

当三次握手完成后,TCP协议会为链接双方维持链接状态。为了保证数据传输成功,接收端在接收到数据包后必须发送ACK报文做为确认。若是在指定的时间内(这个时间称为从新发送超时时间),发送端没有接收到接收端的ACK报文,那么就会重发超时的数据。

2.5.二、数据传输

  • 客户端先向服务器发送数据,该数据报是长度为159的数据。
  • 服务器收到报文后, 也向客户端发送了一个数据进行确认(ACK),而且返回客户端要请求的数据,数据的长度为111,将seq设置为1,ack设置为160(1 + 159)。
  • 客户端收到服务器返回的数据后进行确认(ACK),将seq设置为160, ack设置为112(1 + 111)。

2.5.三、四次断开

  • 客户端发送FIN控制位发出断开链接的请求
  • 服务器进行响应,确认收到断开链接请求
  • 服务器提出反方向的关闭要求
  • 客户端确认收到的主机B的关闭链接请求

** 三、DNS**

DNS是Domain Name Service的缩写,位于应用层,DNS服务器进行域名和与之对应的IP地址转换的服务器

一般咱们访问一个网站,使用的是主机名或者域名来进行访问的。由于相对于IP地址(一组纯数字),域名更容易让人记住。但TCP/IP协议使用的是IP地址进行访问的,因此必须有个机制或服务把域名转换成IP地址。DNS服务就是用来解决这个问题的,它提供域名到IP地址之间的解析服务。 即DNS协议提供统统过域名查找IP地址,或逆向从IP地址反查域名的服务。

DNS域名解析过程:

当用户在浏览器地址栏输入URL,回车后,咱们要找URL相应的IP地址,怎么找呢?

如上图,浏览器先找自身缓存,让其查找是否有缓存的记录,结果并无发现,此时找向系统缓存,主要去查找了系统中的hosts文件,一样没有,此时找向路由器缓存,查看路由器映射表,然而,并无!因而,计算机将域名发给了本地DNS服务器(提供本地链接的服务商),本地DNS服务器找不到会将域名发送给其余服务器,进行递归过程,首先会发送到根域名服务器去找,返回顶级域名服务器的IP地址,再请求顶级域名服务器IP返回二级域名服务器IP,再请求二级域名服务器IP返回三级域名服务器IP......直到找到对应的IP地址,返回给浏览器。

DNS负载均衡:

DNS负载均衡,又叫作DNS重定向。 CDN(Content Delivery Network)就是利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容。

DNS返回的IP地址是否每次都同样?若是每次都同样是否说明你请求的资源都位于同一台机器上面,那么这台机器须要多高的性能和储存才能知足亿万请求呢?

其实真实的互联网世界背后存在成千上百台服务器,大型的网站甚至更多。可是在用户的眼中,它须要的只是处理他的请求,哪台机器处理请求并不重要。DNS能够返回一个合适的机器的IP给用户,例如能够根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡。

四、TCP/IP族与HTTP相关协议关系

socket 通讯机制

Socket是IPC通讯的一种方式,用于实如今同一主机或者不一样主机之间的通讯。socket通讯在domain中实现,所谓的 domain 是识别一个socket的方法(socket地址格式)。

socket是一组实现TCP/UDP通讯的接口API,既不管TCP仍是UDP,经过对scoket的编程,均可以实现TCP/UCP。

一、常见的domain:

  • Unix Domain: 基于socket机制实现同一主机不一样进程间通讯的一种方式;AF_UNIX, AF_LOCAL,地址是一个路径名(文件)
  • IPv4 Domain: AF_INET, 基于socket机制借助于ipv4协议实现不一样主机(也能够是同一主机)上的进程间通讯的机制; 地址是32位的ipv4地址+16位的端口号
  • IPv6 Domain: AF_INET6, 地址是128位的Ipv6地址+16位的端口号

二、socket的类型:

  • TCP:流式socket,SOCK_STREAM 提供可靠、双向、面向字节流
  • UDP:数据报式socket, SOCK_DGRAM

三、相关的系统调用:

  • socket( ): 建立一个新的socket
  • bind( ):绑定于一个套按字地址和端口上
  • listen( ): 监听套接字
  • accept( ): 接收链接请求
  • connect( ): 发起链接请求
  • close( ): 关闭链接
  • read( ):从套接字向缓冲区读入数据
  • write( ): 从缓存区向套接字中写入数据

URL、URI

URI用字符串标识某一互联网资源,而URL表示资源的地点(互联网上所处的位置)。URL是URI的子集。

一、URI

URI(Uniform Resource Identifier)是统一资源标识符,在某个规则下能把这个资源独一无二标示出来,好比人的身份证号。

  • Uniform:规定统一的格式客房部处理多种不一样类型的资源,而不用根据上下文来识别资源指定的访问方式;
  • Resource:能够标识的任何东西
  • Identifier:表示可标识的对象

二、URL

URL(Uniform Resource Locator)统一资源定位符,表示资源的地点,URL正是使用浏览器访问WEB页面时须要输入的网页地址

  • Uniform 不用根据上下文来识别资源指定的访问方式
  • Resource 能够标识的任何东西
  • Location 定位

2.一、URL的格式

  • 协议类型:使用 http, https, file等协议方案名获取访问资源时要指定协议类型。也能够使用data:或者javascript:这类指定数据或者脚本程序的方案名。不区分大小写,最后附一个冒号。后面必须和://连在一块儿。
  • 登陆信息:可选项。指定用户名和密码做为从服务器端货物资源时必要的登陆信息。 很不安全,不推荐使用,也不经常使用。
  • 服务器地址:服务器地址
  • 服务器端口号:服务器端口号
  • 带层次的文件路径: 表示请求路径,标记资源所在位置。
  • 查询字符串: 表示查询参数,为key=val这种形式,多个键值对之间用&隔开。
  • 片断标识符: 表示 URI 所定位的资源内的一个锚点,浏览器能够根据这个锚点跳转到对应的位置

HTTP协议

HTTP简介

  • HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写。
  • HTTP协议可以明确区分哪端是客户端,哪端是服务器端。请求的一方叫客户端,响应的一方叫服务器端。
  • 经过请求和响应的交换达成通讯
  • HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议。它能够使浏览器更加高效,使网络传输减小。它不只保证计算机正确快速地传输超文本文档,还肯定传输文档中的哪一部分,以及哪部份内容首先显示(如文本先于图形)等。
  • HTTP是一个应用层的面向对象协议, 是一个基于TCP/IP通讯协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
  • HTTP是一个无状态的协议。
  • 默认HTTP的端口号为80,HTTPS的端口号为443。
  • HTTP协议一般承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了咱们常说的HTTPS。以下图:

HTTP特色

一、无链接:限制每次连接只处理一个请求。 服务器处理完客户的请求,并收到客户的应答后,即断开链接。采用这种方式能够节省传输时间。 早期这么作的缘由是请求资源少,追求快。后来经过Connection: Keep-Alive实现长链接 。

二、无状态: HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺乏状态意味着若是后续处理须要前面的信息,则它必须重传,这是为了更快的处理大量事务,确保协议的可伸缩性,而特地设计的。另外一方面,在服务器不须要先前信息时它的应答就较快。 协议对于发送过的请求或相应都不作持久化处理。HTTP/1.1虽然无状态,可是增长了cookie技术。有了cookie再用HTTP协议通讯,就能够管理状态了。以后会讲解。

三、简单快速: 客户向服务器请求服务时,只需传送请求方法和路径。请求方法经常使用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不一样。因为HTTP协议简单,使得HTTP服务器的程序规模小,于是通讯速度很快。

四、灵活: HTTP容许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。 主要体如今两个方面: 一个是语义上的自由,只规定了基本格式,好比空格分隔单词,换行分隔字段,其余的各个部分都没有严格的语法限制。另外一个是传输形式的多样性,不只仅能够传输文本,还能传输图片、视频等任意数据,很是方便。

六、支持客户端/服务器模式

七、HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据均可以经过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。

注意:!!!

一、HTTP是无状态的面向链接的协议,无状态不表明HTTP不能保持TCP链接,HTTP使用的不是UDP协议(无链接) 二、从HTTP/1.1起,默认都开启了Keep-Alive,保持链接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP链接不会关闭,若是客户端再次访问这个服务器上的网页,会继续使用这一条已经创建的链接 三、Keep-Alive不会永久保持链接,它有一个保持时间,能够在不一样的服务器软件(如Apache)中设定这个时间

HTTP版本

它的发展是万维网协会(World Wide Web Consortium)和Internet工做小组IETF(Internet Engineering Task Force)合做的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定义了今天广泛使用的一个版本——HTTP /1.1。

HTTP/0.9

1990年问世。并无做为正式的标准被创建。如今的HTTP其实含有HTTP/1.0以前版本的意思,所以被称为HTTP/0.9。只有一个命令GET

改版本特别简单,只有一个命令GET.

GET /index.html
复制代码

上面命令表示,TCP 链接(connection)创建后,客户端向服务器请求(request)网页index.html

协议规定,服务器只能回应HTML格式的字符串,不能回应别的格式,好比头部信息。

<html>
<body>Hello World</body>
</html>
复制代码

服务器发送完毕,就关闭TCP链接。

HTTP/1.0

1996年5月,HTTP/1.0 版本发布,内容大大增长。 增长了不少命令、增长status、code和header、多字符集支持、多部分发送、权限、缓存等。 描述HTTP 1.0规范的RFC 1945。

HTTP/1.0 新特性:

一、增长方法: 除了GET方法,还引入了POST方法和HEAD方法;

二、 任何格式的内容均可以发送。这使得互联网不只能够传输文字,还能传输图像、视频、二进制文件;

三、 HTTP请求和回应的格式也变了。除了数据部分,每次通讯都必须包括头信息(HTTP header),用来描述一些元数据。

四、 其余的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。

HTTP/1.0缺点:

缺点:每一个TCP连接只能发送一个请求。 发送数据完毕,链接就关闭,若是还要请求其余资源,就必须再新建一个链接。

解决方法:使用,Connection:keep-alive

HTTP/1.1:

1997年1月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了20年后的今天,直到如今仍是最流行的版本。

在HTTP/1.0的基础上,支持了持久链接、增长了pipeline、增长host和其余一些命令。

描述HTTP 1.1规范的RFC 2616。

HTTP/1.1 新特性

一、 引入了持久链接(persistent connection),即TCP链接默认不关闭,能够被多个请求复用,不用声明Connection: keep-alive

客户端和服务器发现对方一段时间没有活动,就能够主动关闭链接。不过,规范的作法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP链接。

Connection: close
复制代码

目前,对于同一个域名,大多数浏览器容许同时创建6个持久链接。

二、 HTTP管线化(HTTP pipelining)

引入了管道机制(pipelining),即在同一个TCP链接里面,客户端能够同时发送多个请求。这样就进一步改进了HTTP协议的效率。

三、与HTTP/1.0不一样,还有Content-Length 字段;

由于一个 TCP链接能够发多个请求,那如今就会传送多个回应,势必就要有一种机制,区分数据包是属于哪个回应的。因此这个字段用于声明本次回应的数据长度。

而HTTP/1.0版本中, 浏览器发现服务器关闭了TCP链接,就代表收到的数据包已经全了,因此 Content-Length字段 不是必须的。

四、相对于HTTP/1.0,1.1版还新增了许多动词方法:PUTPATCHHEADOPTIONSDELETE

另外,客户端请求的头信息新增了Host字段,用来指定服务器的域名。

http/1.1缺点:

一、"队头堵塞"(Head-of-line blocking): 1.1版容许复用TCP链接,可是同一个TCP链接里面,全部的数据通讯是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。

解决方法:

  • 将同一页面的资源分散到不一样域名下,提高链接上限。 Chrome有个机制,对于同一个域名,默认容许同时创建 6 个 TCP持久链接,使用持久链接时,虽然能公用一个TCP管道,可是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束以前,其余的请求只能处于阻塞状态。另外若是在同一个域名下同时有10个请求发生,那么其中4个请求会进入排队等待状态,直至进行中的请求完成。
  • Spriting合并多张小图为一张大图,再用JavaScript或者CSS将小图从新“切割”出来的技术。
  • 内联(Inlining)是另一种防止发送不少小图请求的技巧,将图片的原始数据嵌入在CSS文件里面的URL里,减小网络请求次数。
  • 拼接(Concatenation)将多个体积较小的JavaScript使用webpack等工具打包成1个体积更大的JavaScript文件,但若是其中1个文件的改动就会致使大量数据被从新下载多个文件。

二、HTTP头部巨大

三、明文传输--带来的不安全性

四、服务器不能主动推送

**SPDY **

上面咱们提到,因为HTTP/1.1的缺点,想解决的话,咱们会合并脚本和样式表、雪碧图、将图片嵌入CSS代码、域名分片(domain sharding)等等的方式来提升性能。不过这些优化都绕开了协议,直到2009年,谷歌公开了自行研发的 SPDY 协议,主要解决HTTP/1.1效率不高的问题。谷歌推出SPDY,才算是正式改造HTTP协议自己。下降延迟,压缩header等等,SPDY的实践证实了这些优化的效果,也最终带来HTTP/2的诞生。

HTTP/2:

简介:

2015年,HTTP/2 发布。它不叫 HTTP/2.0,是由于标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。 全部数据以二进制传输、同一个链接里面发送多个请求再也不须要按照顺序来了、头信息压缩以及推送(服务端能够主动发起请求了)等提升了效率的功能

  • HTTP/2是现行HTTP协议(HTTP/1.x)的替代,但它不是重写;
  • HTTP方法/状态码/语义都与HTTP/1.x同样。
  • HTTP/2基于SPDY,专一于性能,最大的一个目标是在用户和网站间只用一个链接(connection)
  • 从目前的状况来看,国内外一些排名靠前的站点基本都实现了HTTP/2的部署,使用HTTP/2能带来20%~60%的效率提高。

HTTP/2由两个规范(Specification)组成:

  1. Hypertext Transfer Protocol version 2 - RFC7540
  2. HPACK - Header Compression for HTTP/2 - RFC7541

HTTP/2新特性:

一、二进制协议

HTTP/2基于SPDY的,是一个二进制协议,而HTTP/1.x是一个超文本协议; HTTP/1.1 版的头信息确定是文本(ASCII编码),数据体能够是文本,也能够是二进制。HTTP/2 则是一个完全的二进制协议,头信息和数据体都是二进制,而且统称为"帧"(frame):头信息帧和数据帧。

HTTP/2 将请求和响应数据分割为更小的帧,而且它们采用二进制编码

二、多路复用

HTTP/2能够避免 "队头堵塞" ,由于HTTP/2 复用TCP链接,在一个链接里,客户端和浏览器均可以同时发送多个请求或回应,并且不用按照顺序一一对应; 双向的、实时的通讯,就叫作多工;

你们能够经过 该连接 直观感觉下 HTTP/2 比 HTTP/1 到底快了多少。

三、 HTTP/2 引入了头信息压缩机制(header compression)

四、 HTTP/2 容许服务器未经请求,主动向客户端发送资源,这叫作服务器推送(server push)

HTTP报文

用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文叫作请求报文,响应端(服务端)的叫作响应报文。一定包含HTTP首部

HTTP报文构成:报文首部、空行、报文主体。一般,并不必定要有报文主体。

请求报文和响应报文的构成

从上边图能够看出,请求报文:请求行、各类首部字段、空行;响应报文:状态行、各类首部字段、报文主体;

通常有四种首部:通用首部、请求首部、响应首部和实体首部;

请求报文的构成:

请求行:包括用于请求的方法,请求URI和HTTP版本。以下图请求报文的构成:POST方法、请求URI:/form/entry 、协议版本:HTTP/1.1

请求首部字段:包含请求各类条件和属性的各种首部。

响应报文:

状态行:包含代表响应结果的状态码,缘由短语和HTTP版本;

响应首部字段:表示响应的各类条件和属性的各种首部;

响应体:具体的数据,以下图返回的html

ps:注意事项

一、在起始行(请求行和状态行)中,每两个部分之间用空格隔开,最后一个部分后面应该接一个换行,严格遵循ABNF语法规范;

二、首部字段:

  • 字段名不区分大小写
  • 字段名不容许出现空格,不能够出现下划线_
  • 字段名后面必须紧接着:

三、空行

很重要,用来区分开头部实体

问: 若是说在头部中间故意加一个空行会怎么样?

那么空行后的内容所有被视为实体。

利用浏览器来查看网页的报文

咱们使用 Chrome浏览器的开发者工具中的Network 来查看浏览器和服务器之间的通讯;

step1:在浏览器地址栏中输入www.baidu.com,在ctrl+f12或在菜单中选择“视图”,“开发者”,“开发者工具”,就能够显示开发者工具 ;

step2: 咱们点Network,确保第一个小红灯亮着(抓包工具),Chrome就会记录全部浏览器和服务器之间的通讯:

step3: 在Network中,定位到第一条记录,点击,右侧将显示Request Headers,点击右侧的view source,咱们就能够看到浏览器发给百度服务器的请求:

step4:一样你还能够看Response Headers,点击view source,显示服务器返回的原始响应数据

Content-Type指示响应的内容,这里是text/html表示HTML网页。 浏览器就是依靠Content-Type来判断响应的内容是网页仍是图片,是视频仍是音乐。浏览器并不靠URL来判断响应的内容, 因此,即便URL是http://example.com/abc.jpg,它也不必定就是图片。

step5:点击Response是响应体的内容是HTML源码。

当浏览器读取到百度首页的HTML源码后,它会解析HTML,显示页面,而后,根据HTML里面的各类连接,再发送HTTP请求给新浪服务器,拿到相应的图片、视频、Flash、JavaScript脚本、CSS等各类资源,最终显示出一个完整的页面。因此咱们在Network下面能看到不少额外的HTTP请求。

利用curl工具查看报文

step1: 在命令行工具中输入下面命令

curl -v www.baidu.com
复制代码

固然还能够使用其余的抓包工具查看,在这就不一一列举了。

HTTP请求方法:

注意方法名要大写。

方法 说明 支持版本
GET 获取资源。请求指定的页面信息,并返回实体主体。 HTTP/1.0以上版本都支持
POST 向服务器发送数据,传输实体主题。请求服务器接受所指定的文档做为对所标识的URI的新的从属实体。 HTTP/1.0以上版本都支持
PUT 传输文件。HTTP/1.1的PUT不带验证机制,因此通常的web网站也不会使用此方法。 HTTP/1.0以上版本都支持
HEAD 只请求页面的首部。 HTTP/1.0以上版本都支持
DELETE 请求服务器删除指定的页面。与PUT相反的方法。HTTP/1.1的DELETE也不带验证机制,因此通常的web网站也不会使用此方法。 HTTP/1.0以上版本都支持
OPTIONS 询问支持的方法。此方法用来查询针对请求URI指定的资源支持的方法。(跨域时,有可能会用到,复杂请求也可会用到) HTTP/1.1以上版本都支持
TRACE 追踪路径。此方法让web服务器将以前的请求通讯返回给客户端的方法。此方法不经常使用,容易引起XST(跨站追踪)攻击。 HTTP/1.1以上版本都支持
CONNECT 要求用隧道协议链接代理。主要使用SSL(安全套接层)和TLS(传输层安全)协议把通讯内容加密后经网络隧道传输。 HTTP/1.1以上版本都支持
LINK 请求服务器创建连接关系。 HTTP/1.0版本支持,HTTP/1.1已经废除
UNLINK 断开连接关系。 HTTP/1.0版本支持,HTTP/1.1已经废除

GET和POST的区别

后又有这样一些具体的差异:

  • 缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
  • 从**编码**的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
  • 从**参数**的角度,GET 通常放在 URL的后面拼接 上,所以不安全,POST 放在请求体中,更适合传输敏感信息。
  • 从**安全**角度, POST的安全性要比GET的安全性高。
  • 长度限制的角度,GET请求有具体长度限制,通常不超过1024KB,而POST理论上没有,可是浏览器自己都有一个界限。
  • 从**幂等性的角度,GET幂等**的,而POST不是。(幂等表示执行相同的操做,结果也是相同的)
  • 从**TCP**的角度,GET和POST都是TCP链接,并没有实质的区别.可是因为HTTP/浏览器的限定,致使它们在应用过程当中体现出了一些不一样.GET产生一个数据包,POST产生两个数据包.对于GET请求,浏览器会把http header 和 data 一并发出去,服务器响应200(返回数据).而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok (火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

HTTP状态码及含义

状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户能够知道服务器端是正常处理请求,仍是出现了错误。

响应码 含义、应用
1** 表示临时的响应。客户端在收到常规响应以前,应准备接收一个或多个 1xx 响应。
100 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其他部分。
101 切换协议。请求者已要求服务器切换协议,服务器已确认并准备切换。针对请求头的Upgrade返回的信息。代表服务器正在切换到指定的协议。好比websocket、升级到http2
2** 代表服务器成功的接受了客户端请求
200 成功。客户端请求已成功。一般,这表示服务器提供了请求的网页。
201 已建立。请求成功而且服务器建立了新的资源。经常使用于POST,PUT 请求,代表请求已经成功,并新建了一个资源。并在响应体中返回路径。
202 已接受。请求已经接收到,但没有响应,稍后也不会返回一个异步请求结果。 该状态码适用于等待其余进程处理或者批处理的场景。
203 非权威性信息。服务器已成功处理了请求,但返回的信息可能来自另外一来源。主要用于其余资源的镜像和备份。除了前面的状况,首选仍是200。
204 无内容。服务器成功处理了请求,没有返回任何内容,可是头信息有用。用户代理(浏览器)会更新缓存的头信息。用户代理: 代替用户运行的软件,如web浏览器,或者邮件阅读器。
205 重置内容。告诉用户代理(浏览器)重置发送该请求的文档。
206 部份内容。代表已部分下载了一个文件。能够续传损坏的下载,或者将下载拆分为多个并发的流。服务器成功处理了部分 GET 请求。当客户端使用Range请求头时,返回该状态码。curl -v --header "Range:bytes=0-3",经过curl发起http请求-->响应行为:HTTP/1.1 206 Partial Content
207 多状态(WebDAV)。此消息以前应该还有一条 XML 消息,其中可能包含几个单独的响应代码,具体取决于发出了多少个子请求。
3** 重定向。例如,浏览器可能不得不请求服务器上的不一样页面,或经过代理服务器重复该请求。
301 已永久移动。此请求和以后全部的请求都应该转到指定的 URI。由于有些客户端会把请求方式method改为GET。因此该状态码建议GET和HEAD方法中使用。搜索引擎会更新地址到资源的连接(SEO中‘link-judge’被发送到新的URL)。
302 对象已移动。将来可能还会有新的修改。对于基于表单的身份验证,此消息一般表示为“对象已移动”。请求的资源临时驻留在不一样的 URI。因为重定向有时可能会改变,客户端未来在请求时应该继续使用 RequestURI。只有在 CacheControl 或 Expires 标题字段中指示,此响应才可以缓存。搜索引擎不会更改URL到资源的。应用:负载均衡。
304 未修改。客户端请求的文档已在其缓存中,文档自缓存以来还没有被修改过。客户端使用文档的缓存副本,而不从服务器下载文档。若是想使用200状态码达到相同304效果,须要强制缓存,须要额外的请求头:Cache-Control, Expires, Vary
305 使用代理。
307 临时重定向。基本和302相同。惟一的区别是这个状态码严格禁止浏览器到新URL请求资源时修改原来的请求方式和请求体。好比,原来使用POST,此次仍是要使用POST。若是想要用PUT方法去修改一个服务器上没有的资源,能够用303状态码。若是想要把一个POST方法改成GET,请使用303。
308 永久重定向。基本和301相同。可是严格禁止修改请求方式和请求体。
4** 客户端错误,域名已中止加速服务。。例如,客户端请求不存在的页面,客户端未提供有效的身份验证信息。
400 请求语法有问题,服务器没法识别。例如,没有host请求头字段,或者设置了超过一个的host请求头字段。
401 访问请求验证失败。缺少有效的身份认证凭证,通常多是未登录。登录后通常都解决问题。
401.1 用户名或密码无效致使登陆失败。
401.2 服务器配置致使登陆失败。
401.3 因为 ACL 对资源的限制而未得到受权。表示存在 NTFS 权限问题。即便您对试图访问的文件具有相应的权限,也可能发生此错误。例如,若是 IUSR 账户无权访问 C:WinntSystem32Inetsrv 目录,您会看到这个错误。
401.4 筛选器受权失败。
401.5 ISAPI/CGI 应用程序受权失败。
401.7 由 Web 服务器上的 URL 验证策略拒绝访问。这个错误代码为 IIS 6.0 所专用。
402 保留,未来使用
403 服务器拒绝响应。权限不足。
404 URL无效或者URL有效可是没有资源。
405 方法禁用。请求方式Method不容许。可是GET和HEAD属于强制方式,不能返回这个状态码。
406 不接受。资源类型不符合服务器要求。
407 须要代理受权。要求进行代理身份验证。
408 请求超时。服务器等候请求时发生超时。
409 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 已删除。若是请求的资源已永久删除,服务器就会返回此响应。410不一样于404,若是资源之前有如今被永久删除了可以使用410代码,网站设计人员可经过301代码指定资源的新位置。
411 须要有效长度。服务器不接受不含有效内容长度Content-Length标头字段的请求。
412 未知足前提条件。客户端请求信息的先决条件错误。
413 请求实体过大。因为请求的实体过大,服务器没法处理,所以拒绝请求。为防止客户端的连续请求,服务器可能会关闭链接。若是只是服务器暂时没法处理,则会包含一个Retry-After的响应信息。
414 请求的 URI 过长。请求的 URI(一般为网址)过长,服务器没法处理。
415 不支持的媒体类型。服务器没法处理请求附带的媒体格式
416 客户端请求的范围无效。
417 服务器没法知足Expect的请求头信息。
5** 服务器错误。
500 服务器内部错误。未捕获。
501 服务器不具有完成请求的功能。 例如,服务器没法识别请求方法时可能会返回此代码。
502 错误网关。Web 服务器做为网关或代理服务器时,从上游服务器收到了无效响应。此类错误通常与服务器自己有关(与请求无关)、负载均衡。
503 服务不可用。目前服务器没法使用,通常是由于服务器超载或中止维护。一般,这只是暂时状态。通常还会伴随着返回一个响应头Retry-After: 说明恢复服务的估计时间。
504 网关超时。服务器做为网关或者代理,不能及时从上游服务器获取响应返回给客户端。
505 HTTP 版本不受支持。发出的请求http版本服务器不支持。若是请求经过http2发送,服务器不支持http/2,就会返回该状态码。

这么多你们可能记不住,不过下边常见的状态码,跟咱们前端是息息相关的,须要记住。

常见状态码可见问题部分:HTTP响应码你都知道哪些?都是什么意思?

HTTP首部字段

HTTP首部字段有首部字段名和首部字段值构成,中间用冒号:分割

通常有四种首部:通用首部、请求首部、响应首部和实体首部;

首部字段:

  • 字段名不区分大小写

  • 字段名不容许出现空格,不能够出现下划线_

  • 字段名后面必须紧接着:

  • 字段值对应单个HTTP首部字段能够有多个值

    Keep-Alive: timeout=15,max=100
    复制代码

如下是HTTP\1.1规范定义的首部字段

1 、通用首部字段

首部字段名 说明
Cache-Control 控制缓存行为
Connection 连接的管理
Date 代表建立 HTTP 报文的日期和时间
Pragma 报文指令
Trailer 报文尾部的首部
Trasfer-Encoding 指定报文主体的传输编码方式
Upgrade 升级为其余协议,
首部字段 Upgrade 用于检测 HTTP 协议及其余协议是否可以使用更高的版本进行通讯,
其参数值能够用来指定 一个彻底不一样的通讯协议。
Via 代理服务器信息
使用首部字段 Via 是为了追踪客户端与服务器之间的请求和响应报文的传输路径。
Warning 错误通知

二、 请求首部字段

首部字段名 说明
Accept 用户代理可处理的媒体类型
Accept-Charset 优先的字符集
Accept-Encoding 优先的编码
Accept-Langulage 优先的语言
Authorization Web认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求资源所在的服务器
If-Match 比较实体标记
If-Modified-Since 比较资源的更新时间
If-None-Match 比较实体标记
If-Range 资源未更新时发送实体Byte的范围请求
If-Unmodified-Since 比较资源的更新时间(和If-Modified-Since相反)
Max-Forwards 最大传输跳数
Proxy-Authorization 代理服务器须要客户端认证
Range 实体字节范围请求
Referer 请求中的URI的原始获取方
TE 传输编码的优先级
User-Agent HTTP客户端程序的信息

三、 响应首部字段

首部字段名 说明
Accept-Ranges 是否接受字节范围
Age 资源的建立时间
ETag 资源的匹配信息
Location 客户端重定向至指定的URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Retry-After 再次发送请求的时机
Server 服务器的信息
Vary 代理服务器缓存的管理信息
www-Authenticate 服务器对客户端的认证

四、 实体首部字段

首部字段名 说明
Allow 资源可支持的HTTP方法
Content-Encoding 实体的编码方式
Content-Language 实体的天然语言
Content-Length 实体的内容大小(字节为单位)
Content-Location 替代对应资源的URI
Content-MD5 实体的报文摘要
Content-Range 实体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体过时时间
Last-Modified 资源的最后修改时间

五、非HTTP/1.1首部字段

还有使用频率比较高的首部字段有:CookieSetCookieContene-Disposition

六、End-to-end 首部和 Hop-by-hop 首部

HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分红 2 种类型。

端到端首部(End-to-end): 分在此类别中的首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规 定它必须被转发。

逐跳首部(Hop-by-hop):分在此类别中的首部只对单次转发有效,会因经过缓存或代理而再也不转发。HTTP/1.1 和以后版本中,若是要使用 hop-by-hop 首部,需提供 Connection 首部字段。

下面列举了 HTTP/1.1 中的逐跳首部字段。除这 8 个首部字段以外,其余全部字段都属于端到端首部。

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • Trailer
  • TE
  • Transfer-Encoding
  • Upgrade

常见的报文头的属性

字段 说明 示例
Accept 可接收的响应内容类型 Accept:text/plain (文本类型)
Accept-Charset 可接收的字符集 Accept-Charset: utf-8
Accept-Encoding 可接受的响应内容的编码方式 Accept-Encoding: gzip, deflate
Accept-Language 可接受的响应内容语言列表 Accept-Language: en-US
Accept-Datetime 可接受的按照时间来表示的响应内容版本 Accept-Datetime: Sat, 26 Dec 2015 17:30:00 GMT
Authorization HTTP协议中须要认证资源的认证信息 Authorization: Basic OSdjJGRpbjpvcGVuIANlc2SdDE==
Cache-Control 请求/回复中的,是否使用缓存机制 Cache-Control: no-cache
Connection 客户端想要优先使用的链接类型 Connection: keep-alive Connection: Upgrade
Content-Length 以8进制表示的请求体的长度 Content-Length: 348
Content-Type 请求体的MIME类型 Content-Type: application/x-www-form-urlencoded
Date 发送该消息的日期和时间 Date: Dec, 26 Dec 2015 17:30:00 GMT
Expect 表示客户端要求服务器作出特定的行为 Expect: 100-continue
From 发起此请求的用户的邮件地址 From: user@a.com
Host 服务器域名和端口号,默认端口可省略 Host: www.a.com:80 or www.a.com
If-Match 主要用于PUT,实体匹配才能够操做 If-Match: "9jd00cdj34pss9ejqiw39d82f20d0ikd"
If-Modified-Since 资源未被修改的状况下返回304未修改 If-Modified-Since: Dec, 26 Dec 2015 17:30:00 GMT
User-Agent 浏览器的身份标识字符串 User-Agent: Mozilla/
Upgrade 要求服务器升级到一个高版本协议 Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
Via 告诉服务器,这个请求是由哪一个代理发出的 Via: 1.0 fred, 1.1 a.com.com (Apache/1.1)
Referer 表示跳转到当前页面的以前的页面 Referer: a.com/nodejs
Origin 发起一个针对跨域资源共享的请求 Origin: www.a.com

Connection

Connection 首部字段具有以下两个做用。

一、控制再也不转发给代理的首部字段

二、管理持久链接

Connection: close
复制代码

HTTP/1.1 版本的默认链接都是持久链接。为此,客户端会在持久链接上连续发送请求。当服务器端想明确断开链接时,则指定Connection 首部字段的值为 close

Pragma

Pragma 是 HTTP/1.1 以前版本的历史遗留字段,仅做为与 HTTP/1.0 的向后兼容而定义。 规范定义的形式惟一,以下所示。

Pragma: no-cache
复制代码

该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求全部的中间服务器不返回缓存 的资源。

全部的中间服务器若是都能以 HTTP/1.1 为基准,那直接采用Cache-Control: no-cache指定缓存的处理方式 是最为理想的。但要总体掌握所有中间服务器使用的 HTTP 协议版本倒是不现实的。所以,发送的请求会同 时含有下面两个首部字段。

Cache-Control: no-cache
Pragma: no-cache
复制代码

Cache-Control

经过指定首部字段 Cache-Control的指令,就能操做缓存的工做机制。

语法格式:

指令的参数是可选的,多个指令之间经过','分隔。

Cache-Control:private,max-age=0,no-cache
复制代码

缓存请求指令

指令 参数 说明
no-cache 强制向源服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age = [ 秒] 必需 响应的最大Age值
max-stale( = [ 秒]) 可省略 接收已过时的响应
min-fresh = [ 秒] 必须 指望在指定时间内的响应仍有效
no-transform 代理不可更改媒体类型
cache-extension - 新指令标记(token)

缓存响应指令

指令 参数 说明
public 可向任意方提供响应的缓存
private 可省略 仅向特定用户返回响应
no-cache 可省略 缓存前必须先确认其有效性
no-store 不缓存请求或响应的任何内容
no-transform 代理不可更改媒体类型
must-revalidate 可缓存但必须再向源服务器进行确认
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行 确认
max-age = [ 秒] 必须 响应的最大Age值
s-maxage = [ 秒] 必须 公共缓存服务器响应的最大Age值,max-age长得比较像,可是区别在于s-maxage是针对代理服务器的缓存时间
cache-extension - 新指令标记(token)

Content-Type

Content-Type(内容类型), 通常是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。

Content-Type 标头告诉客户端实际返回的内容的内容类型。

关于字符的编码,1.0版规定,头信息必须是 ASCII 码,后面的数据能够是任何格式。所以,服务器回应的时候,必须告诉客户端,数据是什么格式,这就是Content-Type字段的做用。

语法格式:

Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something
复制代码

常见的媒体格式类型以下:

媒体格式类型 说明
text/html HTML格式
text/plain 纯文本格式
text/xml XML格式
image/gif gif图片格式
image/jpeg jpg图片格式
image/png png图片格式

以application开头的媒体格式类型:

以application开头的媒体格式类型 说明
application/xhtml+xml XHTML格式
application/xml XML数据格式
application/atom+xml Atom XML聚合格式
application/json JSON数据格式
application/pdf pdf格式
application/msword Word文档格式
application/x-www-form-urlencoded 最多见的post提交数据的方式。
中默认的encType,浏览器原生的form表单,若是不设置enctype属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据 。form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
application/octet-stream 二进制流数据(如常见的文件下载)

另一种常见的媒体格式是上传文件之时使用的

媒体格式类型 说明
multipart/form-data 须要在表单中进行文件上传时,就须要使用该格式

Cookie

管理服务器与客户端之间状态的 Cookie,虽然没有被编入标准化 HTTP/1.1 的 RFC2616 中,但在 Web 网 站方面获得了普遍的应用。 Cookie 的工做机制是用户识别及状态管理。Web 网站为了管理用户的状态会经过 Web 浏览器,把一些数据 临时写入用户的计算机内。接着当用户访问该Web网站时,可经过通讯方式取回以前发放的 Cookie。

为 Cookie 服务的首部字段

首部字段名 说明 首部类型
Set-Cookie 开始状态管理所使用的Cookie信息 响应首部字段
Cookie 服务器接收到的Cookie信息 请求首部字段

Cookie的处理流程:

一、 客户端第一次访问服务器的时候服务器经过响应头向客户端发送Cookie,属性之间用分号空格分隔

二、 客户端接收到Cookie以后保存在本地

三、 之后客户端再请求服务器的时候会把此Cookie发送到服务器端

Set-Cookie

语法格式:

Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT; path=/; domain=.a.com;
复制代码

当服务器准备开始管理客户端的状态时,会事先告知各类信息。下面的表格列举了 Set-Cookie 的字段值。

Set-Cookie 字段的属性

属性 说明
NAME=VALUE 赋予 Cookie 的名称和其值(必需项)
expires=DATE Cookie的有效期(若不明确指定则默认为浏览器关闭前为止)
max-age = [ 秒] Cookie多少秒后过时(若不明确指定则默认为浏览器关闭前为止)
path=PATH 将服务器上的文件目录做为Cookie的适用对象(若不指定则默认为文档 所在的文件目录)
domain=域名 做为 Cookie 适用对象的域名 (若不指定则默认为建立 Cookie 的服务 器的域名)
Secure 仅在 HTTPS 安全通讯时才会发送 Cookie
HttpOnly 加以限制,使 Cookie 不能被 JavaScript 脚本访问,防止XSS攻击产生

expires 属性

Cookie 的 expires 属性指定浏览器可发送 Cookie 的有效期。 当省略 expires 属性时,其有效期仅限于维持浏览器会话(Session)时间段内。这一般限于浏览器应用程序被关闭以前。 另外,一旦 Cookie 从服务器端发送至客户端,服务器端就不存在能够显式删除 Cookie 的方法。但可经过覆盖已过时的 Cookie,实现对客户端 Cookie 的实质性删除操做。

Cookie

Cookie: status=enable
复制代码

首部字段 Cookie 会告知服务器,当客户端想得到 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个 Cookie 时,一样能够以多个 Cookie 形式发送。

Cookie使用注意事项:

  • 可能被客户端篡改,使用前验证合法性
  • 不要存储敏感数据,好比用户密码,帐户余额
  • 使用httpOnly保证安全
  • 尽可能减小cookie的体积
  • 设置正确的domain和path,减小数据传输

session

session是另外一种记录客户状态的机制,不一样的是Cookie保存在客户端浏览器中,而session保存在服务器上

客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是session。客户端浏览器再次访问时只须要从该Session中查找该客户的状态就能够了

cookie与session区别

  1. cookie数据存放在客户的浏览器上,session数据放在服务器上。
  2. cookie不是很安全,别人能够分析存放在本地的COOKIE并进行COOKIE欺骗 考虑到安全应当使用session
  3. session会在必定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能 考虑到减轻服务器性能方面,应当使用COOKIE
  4. 单个cookie保存的数据不能超过4K,不少浏览器都限制一个站点最多保存20个cookie

将登录信息等重要信息存放为session、其余信息若是须要保留,能够放在cookie中

缓存

经过⽹络获取内容既速度缓慢⼜开销巨⼤。较⼤的响应须要在客户端与服务器之间进⾏屡次往返通讯,

这会延迟浏览器得到和处理内容的时间,还会增长访问者的流量费⽤。所以,缓存并重复利⽤以前获取

的资源的能⼒成为性能优化的⼀个关键⽅⾯。

缓存做用

  • 减小了冗余的数据传输,节省了网费。
  • 减小了服务器的负担, 大大提升了网站的性能
  • 加快了客户端加载网页的速度

缓存分类

⼴义的缓存,能够分为这四个

    1. Http Cache
    1. Service Worker Cache:

      Service Worker 借鉴了 Web Worker的 思路,即让 JS 运行在主线程以外,因为它脱离了浏览器的窗体,所以没法直接访问DOM。虽然如此,但它仍然能帮助咱们完成不少有用的功能,好比离线缓存消息推送网络代理等功能。其中的离线缓存就是 Service Worker Cache

    1. Memory Cache:

      内存缓存,从效率上讲它是最快的。可是从存活时间来说又是最短的,当渲染进程结束后,内存缓存也就不存在了。

    1. Push Cache:(HTTP/2中的服务器推送)

HTTP缓存

HTTP缓存有多种规则,根据是否须要从新向服务器发起请求来分类,可将其分为强制缓存,对比缓存。

  • 强制缓存若是生效,不须要再和服务器发生交互,而对比缓存无论是否生效,都须要与服务端发生交互
  • 两类缓存规则能够同时存在,强制缓存优先级高于对比缓存,也就是说,当执行强制缓存的规则时,若是缓存生效,直接使用缓存,再也不执行对比缓存规则

一、强缓存

浏览器中的缓存做用分为两种状况,一种是须要发送HTTP请求,一种是不须要发送。

首先是检查强缓存,这个阶段不须要发送HTTP请求。

那么浏览器是如何检查的呢?

咱们知道,在没有缓存数据的时候,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。

注意:

HTTP/1.0HTTP/1.1当中,这个字段是不同的。在早期,也就是HTTP/1.0时期,使用的是Expires,而HTTP/1.1使用的是Cache-Control。当ExpiresCache-Control同时存在的时候,Cache-Control会优先考虑。

Expires

Expires:即过时时间,存在于服务端返回的响应头中,告诉浏览器在这个过时时间以前能够直接从缓存里面获取数据,无需再次请求。

好比下面这样:

Expires: Wed, 22 Apr 2020 08:41:00 GMT
复制代码

表示资源在2020年4月22号8点41分过时,过时了就得向服务端发请求。

这个方式看上去没什么问题,合情合理,但其实潜藏了一个坑,那就是服务器的时间和浏览器的时间可能并不一致,那服务器返回的这个过时时间可能就是不许确的。所以这种方式很快在后来的HTTP/1.1版本中被抛弃了。

Cache-Control

Cache-Control: 在HTTP/1.1中,请求/响应头,缓存控制字段,精确控制缓存策略。

它和Expires本质的不一样在于它并无采用具体的过时时间点这个方式,而是采用过时时长来控制缓存,对应的字段是max-age。好比这个例子:

Cache-Control:max-age=3600
复制代码

表明这个响应返回后在 3600 秒,也就是一个小时以内能够直接使用缓存。它其实能够组合很是多的指令,完成更多场景的缓存判断, 将一些关键的属性列举以下:

public: 客户端和代理服务器均可以缓存。由于一个请求可能要通过不一样的代理服务器最后才到达目标服务器,那么结果就是不只仅浏览器能够缓存数据,中间的任何代理节点均可以进行缓存。

private: 这种状况就是只有浏览器能缓存了,中间的代理服务器不能缓存。

no-cache: 跳过当前的强缓存,发送HTTP请求,即直接进入协商缓存阶段

no-store:很是粗暴,不进行任何形式的缓存。

s-maxage:这和max-age长得比较像,可是区别在于s-maxage是针对代理服务器的缓存时间。

must-revalidate: 是缓存就会有过时的时候,加上这个字段一旦缓存过时,就必须回到源服务器验证。

代码测试:

server.js

const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=20'
    })
    response.end('console.log("script loaded")')
  }
}).listen(8888)

console.log('server listening on 8888')
复制代码

cache.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>测试缓存</title>
</head>
<body>
    
</body>
<script src="/script.js"></script>
</html>
复制代码

执行server.js能够用命令node server.js,在浏览器中的打开http://localhost:8888

当超过咱们设置的时间max-age=20超过20s后,页面又会像咱们第一次打开时同样。

二、协商缓存

当资源缓存时间超时了,也就是强缓存失效了 ,就进入协商缓存了。

  • 对比缓存,顾名思义,须要进行比较判断是否能够使用缓存。
  • 浏览器第一次请求数据时,服务器会将缓存标识与数据一块儿返回给客户端,客户端将两者备份至缓存数据库中。
  • 再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,能够使用缓存数据。

强缓存失效以后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个tag,来决定是否使用缓存。 这样的缓存tag分为两种: Last-ModifiedETag

Last-Modified

Last-Modified:响应头,即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。

浏览器接收到后,若是再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间。

If-Modified-Since: 请求头,资源最近修改时间,由浏览器告诉服务器。

服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:

  • 若是请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程同样。
  • 不然返回304,告诉浏览器直接用缓存。

ETag

ETag:响应头,资源标识,由服务器告诉浏览器。

ETag 是服务器根据当前文件的内容,给文件生成的惟一标识,只要里面的内容有改动,这个值就会变。服务器经过响应头把这个值给浏览器。

浏览器接收到ETag的值,会在下次请求时,将这个值做为If-None-Match这个字段的内容,并放到请求头中,而后发给服务器。

If-None-Match: 请求头,缓存资源标识,由浏览器告诉服务器。

服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:

  • 若是二者不同,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程同样。
  • 不然返回304,告诉浏览器直接用缓存。

二者对比

  1. 精准度上,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,所以能准确感知资源的变化。而 Last-Modified 就不同了,它在一些特殊的状况并不能准确感知资源变化,主要有两种状况:
    • 编辑了资源文件,可是文件内容并无更改,这样也会形成缓存失效。
    • Last-Modified 可以感知的单位时间是秒,若是文件在 1 秒内改变了屡次,那么这时候的 Last-Modified 并无体现出修改了。
  2. 在性能上,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 Etag须要根据文件的具体内容生成哈希值。

另外,若是两种方式都支持的话,服务器会优先考虑ETag

Last-Modified存在问题

  1. 某些服务器不能精确获得文件的最后修改时间, 这样就没法经过最后修改时间来判断文件是否更新了。
  2. 某些文件的修改很是频繁,在秒如下的时间内进行修改. Last-Modified只能精确到秒
  3. 一些文件的最后修改时间改变了,可是内容并未改变。 咱们不但愿客户端认为这个文件修改了。
  4. 若是一样的一个文件位于多个CDN服务器上的时候内容虽然同样,修改时间不同。

代码测试

咱们添加协商缓存:

server.js

const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=20000000,no-cache',
      'Last-Modified':'123',
      'Etag':'666'
    })
    response.end('console.log("script loaded")')
  }
}).listen(8888)

console.log('server listening on 8888')
复制代码

从新启动服务node server.js,打开浏览器http://localhost:8888/;

咱们发现,虽然设置了max-age='20000000',可是刷新页面的时候,仍是发送了请求,没有走缓存,由于还设置了no-cache,会进入协商缓存,咱们设置了EtagLast-Modified,在第二次刷新页面的时候,请求头增长了If-None-MatchIf-Modified-Since且值跟EtagLast-Modified相对应;

缓存致使的静态资源等更改页面不改变问题

http/1.x中浏览器没法主动得知服务器上的静态资源变化没有,且 ExpiresCache-Control,他们都只可以控制缓存是否过时,可是在缓存过时以前,浏览器也是没法得知服务器上的资源是否变化的。只有当缓存过时后,浏览器才会发请求询问服务器。 那么这个时间(缓存没有过时的时间)咱们上线了更改的静态资源,浏览器仍是访问缓存的旧的资源,怎么解决呢?

解决方案:就是每次上线时,给静态资源文件名命名不同;

通常个人处理方式是:

step1:咱们不让 html 文件缓存,每次访问 html 都去请求服务器。因此浏览器每次都能拿到最新的html资源。 step2:将原来的文件名加上每次打包的版本号,或者时间戳、指纹(不要产生新文件, < script src="/script.js?_h=1.6wee1" > )、加哈希(),这样的好处是,能够知道静态资源时哪次打包的,哪些资源时此次更改的,若是出现错误,须要回溯版本,也能够快速回溯。

简单案例部分代码:

第一次时:咱们在html使用的script.js

<script src="http://www.localhost:8888/script.js?version=1.0.1"></script>
复制代码

ps: 浏览器下载1.0.1版本的script.js文件。 浏览器再次访问 html,发现仍是1.0.1版本的script.js文件,则使用本地缓存。

某天咱们须要更改script.js, 咱们的html文件也相应变化以下:

<script src="http://www.localhost:8888/script.js?version=1.0.2"></script>
复制代码

ps: 经过设置html不缓存,html引用资源内容变化则改变资源路径的方式,就解决了没法及时得知资源更新的问题。

其实这仍是须要优化,为何呢? 好比:页面引用了3个css,a.css、b.css、c.css;而某次上线只改了其中的a.css,若是全部连接都更新版本,就会致使b.css,c.css的缓存也失效,那岂不是又有浪费了?!那怎么办呢? 有人想到了将文件名和url联系起来,使用数据摘要要算法 对文件求摘要信息,摘要信息与文件内容一一对应,就有了一种能够精确到单个文件粒度的缓存控制依据了。可是这在大公司的项目中也是不能够的,不是最优的。 为了进一步提高网站性能,会把静态资源和动态网页分集群部署,静态资源会被部署到CDN节点上,好比七牛或者本身公司的CND上,这时候是否是你们都有一个问号了?对静态资源和html放在不一样的服务器了,那该先上线哪一个呢???好难!!! 访问量不大的项目,可让研发同窗苦逼一把,等到半夜偷偷上线,先上静态资源,再部署页面,看起来问题少一些。

大公司的静态资源优化方案,基本上要实现这么几个东西:

  • 配置超长时间的本地缓存 —— 节省带宽,提升性能
  • 采用内容摘要做为缓存更新依据 —— 精确的缓存控制
  • 静态资源CDN部署 —— 优化网络请求
  • 更资源发布路径实现非覆盖式发布 —— 平滑升级

另外,使用webpack打包的话,借助插件能够很方便的处理,使用哈希。

缓存判断顺序

  • 一、先判断Cache-Control,在Cache-Control的max-age以内,直接返回200 from cache;
  • 二、没有Cache-Control再判断Expires,再Expires以内,直接返回200 from cache;
  • 三、Cache-Control=no-cache或者不符合Expires,浏览器向服务器发送请求;
  • 四、服务器同时判断ETag和Last-Modified,都一致,返回304,有任何一个不一致,返回200。

HTTP数据协商(内容协商)

在HTTP协议中,内容协商是这样一种机制,经过为同一URL指向的资源提供不一样的展示形式,能够使用户代理选择与用户需求相适应的最佳匹配(例如: 文档使用的天然语言,图片的格式,文件格式,json、表单、或则内容编码形式)

当一项资源被访问的时候,特定展示形式的选取是经过内容协商机制来决定的,而且客户端和服务端之间存在多种协商方式。

请求声明Accept:

Accept: 声明我想要怎么样的数据,声明数据类型
Accept-Encoding: 表明数据是怎么样的编码方式,能够使用压缩
Accept-Language: 判断返回的信息是什么语言
User-Agent: 表示浏览器的一些相关的信息
复制代码

与之对应的就是服务端Content:

Content-Type: 对应Accept,Accept能够接收不少种数据格式,Content-Type会在里面选择一种数据格式返回,在返回的时候声明返回的数据格式
Content-Encoding: 对应Accept-Encoding,告诉客户端,我究竟用了什么样的压缩数据的方式
Content-Language: 是否根据请求返回对应的语言
复制代码

代码测试:

server.js

const http = require('http')
const fs = require('fs')
const zlib = require('zlib') // 引入包

http.createServer(function (request, response) {
  console.log('request come', request.url)

  const html = fs.readFileSync('test.html') // 这里不加 utf8,加了返回的就是字符串格式了
  response.writeHead(200, {
    'Content-Type': 'text/html',
    // 'X-Content-Options': 'nosniff'
    'Content-Encoding': 'gzip'
  })
  response.end(zlib.gzipSync(html)) // 压缩
}).listen(8888)

console.log('server listening on 8888')
复制代码

test.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <form action="/form" id="form" enctype="application/x-www-form-urlencoded">
    <input type="text" name="name">
    <input type="password" name="password">
    <input type="submit">
  </form>
</body>
</html>
复制代码

执行server.js能够用命令node server.js,在浏览器中的打开http://localhost:8888

将test.html中form提交方式改成POST

<form action="/form" method="POST" id="form" enctype="application/x-www-form-urlencoded">
复制代码

服务端根据 content-type 是 application/x-www-form-urlencoded来对body 中的数据进行转化便可

在刷新浏览器,填写表单内容,提交

增长文件的传输, 经过表单上传文件时,必需要把文件部分单独拆分出来,文件不能做为字符串进行传输的,要做为二进制的数据进行传输; multipart/form-data

test.html更改:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <form action="/form" method="POST" id="form" enctype="multipart/form-data">
    <input type="text" name="name">
    <input type="password" name="password">
    <input type="file" name="file">
    <input type="submit">
  </form>
  <script>
    var form = document.getElementById('form')
    form.addEventListener('submit', function (e) {
      e.preventDefault()
      var formData = new FormData(form)
      fetch('/form', {
        method: 'POST',
        body: formData
      })
    })
  </script>
</body>
</html>
复制代码

提交文件格式咱们表单的格式为:enctype="multipart/form-data"

浏览器中抓包的请求头中Content-Type

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

请求体为:

------WebKitFormBoundarydHvHzymplSP4CAMk
Content-Disposition: form-data; name="name"

111
------WebKitFormBoundarydHvHzymplSP4CAMk
Content-Disposition: form-data; name="password"

222
------WebKitFormBoundarydHvHzymplSP4CAMk
Content-Disposition: form-data; name="file"; filename="16ba0ae535359e94.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarydHvHzymplSP4CAMk--
复制代码

boundary=----WebKitFormBoundarybwAbNlPF2bBcTLuA用来分割表单提交数据的各个部分

服务端拿到表单数据后,根据这个分割字符串,进行数据分割。

压缩

能够使用zlib模块进行压缩及解压缩处理,压缩文件之后能够减小体积,加快传输速度和节约带宽

accept-encoding:gzip //开启gzip
复制代码

HTTP 压缩就是以缩⼩体积为⽬的,对 HTTP 内容进⾏从新编码的过程 Gzip 压缩背后的原理,是在⼀个⽂本⽂件中找出⼀些重复出现的字符串、临时替换它们,从⽽使整个⽂ 件变⼩。根据这个原理,⽂件中代码的重复率越⾼,那么压缩的效率就越⾼,使⽤ Gzip 的收益也就越 ⼤。反之亦然。

基本上来讲,Gzip都是服务器⼲的活,⽐如nginx

压缩对象

压缩和解压缩对象都是一个可读可写流

  • zlib.createGzip:返回Gzip流对象,使用Gzip算法对数据进行压缩处理
  • zlib.createGunzip:返回Gzip流对象,使用Gzip算法对压缩的数据进行解压缩处理
  • zlib.createDeflate:返回Deflate流对象,使用Deflate算法对数据进行压缩处理
  • zlib.createInflate:返回Deflate流对象,使用Deflate算法对数据进行解压缩处理

代码案例:

var zlib = require('zlib');
var fs = require('fs');
var http = require('http');

var request = http.get({
    host: 'localhost',
    path: '/index.html',
    port: 9090,
    headers: {
        'accept-encoding': 'gzip,deflate'
    }
})

request.on('response', function (response) {
    var output = fs.createWriteStream('test.txt');
    switch (response.headers['content-encoding']) {
        case 'gzip':
            response.pipe(zlib.createGunzip()).pipe(output);
            break;
        case 'deflate':
            response.pipe(zlib.createInflate()).pipe(output);
            break;
        default:
            response.pipe(output);
            break;
    }
});
request.end();
复制代码

href与src的区别

href (Hypertext Reference)指定网络资源的位置,从而在当前元素或者当前文档和由当前属性定义的须要的锚点或资源之间定义一个连接或者关系。(目的不是为了引用资源,而是为了创建联系,让当前标签可以连接到目标地址。)

src source(缩写),指向外部资源的位置,指向的内容将会应用到文档中当前标签所在位置。

href与src的区别

一、请求资源类型不一样:href 指向网络资源所在位置,创建和当前元素(锚点)或当前文档(连接)之间的联系。在请求 src 资源时会将其指向的资源下载并应用到文档中,好比 JavaScript 脚本,img 图片;

二、做用结果不一样:href 用于在当前文档和引用资源之间确立联系;src 用于替换当前内容;

三、浏览器解析方式不一样:当浏览器解析到src ,会**暂停其余资源的下载和处理,**直到将该资源加载、编译、执行完毕,图片和框架等也如此,相似于将所指向资源应用到当前内容。这也是为何建议把 js 脚本放在底部而不是头部的缘由。

HTTP Redirect

重定向, 在response Header中增长Location,responseCode能够是3xx

原理:

在 HTTP 协议中,重定向操做由服务器经过发送特殊的响应(即 redirects)而触发。HTTP 协议的重定向响应的状态码为 3xx 。浏览器在接收到重定向响应的时候,会采用该响应提供的新的 URL ,并当即进行加载;大多数状况下,除了会有一小部分性能损失以外,重定向操做对于用户来讲是不可见的。

不一样类型的重定向映射能够划分为三个类别:

  • 永久重定向: 30一、308, 它表示原 URL 不该再被使用,而应该优先选用新的 URL。搜索引擎机器人会在遇到该状态码时触发更新操做,在其索引库中修改与该资源相关的 URL 。 多用于网站重构。
  • 临时重定向:30二、30三、307, 有时候请求的资源没法从其标准地址访问,可是却能够从另外的地方访问。在这种状况下能够使用临时重定向。搜索引擎不会记录该新的、临时的连接。在建立、更新或者删除资源的时候,临时重定向也能够用于显示临时性的进度页面。
  • 特殊重定向:300、304, 304(Not Modified,资源未被修改)会使页面跳转到本地陈旧的缓存版本当中(该缓存已过时(?)),而 300(Multiple Choice,多项选择) 则是一种手工重定向:以 Web 页面形式呈如今浏览器中的消息主体包含了一个可能的重定向连接的列表,用户能够从中进行选择。

优先级:

  1. HTTP 协议的重定向机制永远最早触发,即使是在没有传送任何页面——也就没有页面被(客户端)读取——的状况下。
  2. HTML 的重定向机制 (``) 会在 HTTP 协议重定向机制未设置的状况下触发。
  3. JavaScript 的重定向机制老是做为最后诉诸的手段,而且只有在客户端开启了 JavaScript 的状况下才起做用。

任何状况下,只要有可能,就应该采用 HTTP 协议的重定向机制,而不要使用 `` 标签。假如开发人员修改了 HTTP 重定向映射而忘记修改 HTML 页面的重定向映射,那么两者就会不一致,最终结果或者出现无限循环,或者致使其余噩梦的发生。

设定方法:

一、HTML重定向机制: 这种机制会使浏览器的回退按钮失效:能够返回含有这个头部的页面,可是又会当即跳转。

<head> 
  <meta http-equiv="refresh" content="0;URL=http://www.a.com/" />
</head>
复制代码

二、JavaScript设置重定向

window.location = "http://www.a.com/";
复制代码

三、在服务器中响应

例如咱们在客服端发出一个请求

const http = require('http')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    response.writeHead(302, {  
      'Location': '/new' 
    })
    response.end()
  }
  if (request.url === '/new') {
    response.writeHead(200, {
      'Content-Type': 'text/html',
    })
    response.end('<div>this is content</div>')
  }
}).listen(8888)

console.log('server listening on 8888')

复制代码

ps:使用 永久性重定向 要慎重,一旦使用,服务端更改路由设置,用户若是不清理浏览器缓存,就会一直重定向。

HTTP工做流程

通常的通讯流程:首先客户端发送一个请求(request)给服务器,服务器在接收到这个请求后将生成一个响应(response)返回给客户端。

一次HTTP操做称为一个事务,其工做过程可分为四步:

1)首先客户端与服务器须要创建链接。只要单击某个超级连接,HTTP的工做开始。

2)创建链接后,客户端发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户端信息和可能的内容。

3)服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。

4)客户端接收服务器所返回的信息经过浏览器显示在用户的显示屏上,而后客户端与服务器断开链接。

若是在以上过程当中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来讲,这些过程是由HTTP本身完成的,用户只要用鼠标点击,等待信息显示就能够了。

HTTPS

HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL/TLS层。其所用的端口号是443。

HTTPS = HTTP+TLS/SSL
复制代码

https通讯的优势:

  • 1)客户端产生的密钥只有客户端和服务器端能获得;
  • 2)加密的数据只有客户端和服务器端才能获得明文;
  • 3)客户端到服务端的通讯是安全的。

HTTPS和HTTP的区别主要以下:

  1. HTTPS协议须要到CA(证书颁发机构)申请证书,通常免费证书不多,须要交费。
  2. HTTP协议运行在TCP之上,全部传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,全部传输的内容都通过加密的。
  3. HTTP和HTTPS使用的是彻底不一样的链接方式,用的端口也不同,前者是80,后者是443。
  4. http的链接很简单,是无状态的;HTTPS协议是由HTTP+SSL协议构建的可进行加密传输、身份认证的网络协议,能够有效的防止运营商劫持,解决了防劫持的一个大问题,比http协议安全。

HTTPS 协议的主要功能基本都依赖于 TLS/SSL 协议,TLS/SSL 的功能实现主要依赖于三类基本算法:

  • 散列函数 散列函数验证信息的完整性

  • 对称加密:对称加密算法采用协商的密钥对数据加密,密钥只有一个,加密解密为同一个密码,且加解密速度快,典型的对称加密算法有DES、AES,RC5,3DES等;

    对称加密主要问题是共享秘钥,除你的计算机(客户端)知道另一台计算机(服务器)的私钥秘钥,不然没法对通讯流进行加密解密。解决这个问题的方案非对称秘钥。

  • 非对称加密:非对称加密实现身份认证和密钥协商,使用两个秘钥:公共秘钥和私有秘钥。私有秘钥由一方密码保存(通常是服务器保存),另外一方任何人均可以得到公共秘钥。

    这种密钥成对出现(且根据公钥没法推知私钥,根据私钥也没法推知公钥),加密解密使用不一样密钥(公钥加密须要私钥解密,私钥加密须要公钥解密),相对对称加密速度较慢,典型的非对称加密算法有RSA、DSA等。

代码案例:

一、对称加密:

const crypto = require('crypto');
function encrypt(data, key, iv) {
    let decipher = crypto.createCipheriv('aes-128-cbc', key, iv);
    decipher.update(data);
    return decipher.final('hex');
}

function decrypt(data, key, iv) {
    let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
    decipher.update(data, 'hex');
    return decipher.final('utf8');
}

let key = '1234567890123456';
let iv = '1234567890123456';
let data = "hello";
let encrypted = encrypt(data, key, iv);
console.log("数据加密后:", encrypted);
let decrypted = decrypt(encrypted, key, iv);
console.log("数据解密后:", decrypted);
复制代码

二、非对称加密:

let { generateKeyPairSync, privateEncrypt, publicDecrypt } = require('crypto');
let rsa = generateKeyPairSync('rsa', {
    modulusLength: 1024,
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
        cipher: 'aes-256-cbc',
        passphrase: 'server_passphrase'
    }
});
let message = 'hello';
let enc_by_prv = privateEncrypt({
    key: rsa.privateKey, passphrase: 'server_passphrase'
}, Buffer.from(message, 'utf8'));
console.log('encrypted by private key: ' + enc_by_prv.toString('hex'));


let dec_by_pub = publicDecrypt(rsa.publicKey, enc_by_prv);
console.log('decrypted by public key: ' + dec_by_pub.toString('utf8'));
复制代码

使用md5加密:

var crypto = require('crypto');
var content = '123456';
var result = crypto.createHash('md5').update(content).digest("hex")
console.log(result);//32位十六进制 = 128位二进制
复制代码

sha256加密:

const salt = '123456';
const sha256 = str => crypto.createHmac('sha256', salt)
    .update(str, 'utf8')
    .digest('hex')

let ret = sha256(content);
console.log(ret);//64位十六进制 = 256位二进制
复制代码

HTTPS 过程大体以下:

​ 1) SSL客户端经过TCP和服务器创建链接以后(443端口),而且在通常的tcp链接协商(握手)过程当中请求证书。

​ 即客户端发出一个消息给服务器,这个消息里面包含了本身可实现的算法列表和其它一些须要的消息,SSL的服务器端会回应一个数据包,这里面肯定了此次通讯所须要的算法,而后服务器向客户端返回证书。(证书里面包含了服务器信息:域名。申请证书的公司,公共秘钥)。

​ 2)Client在收到服务器返回的证书后,判断签发这个证书的公共签发机构,并使用这个机构的公共秘钥确认签名是否有效,客户端还会确保证书中列出的域名就是它正在链接的域名。

​ 3) 若是确认证书有效,那么生成对称秘钥并使用服务器的公共秘钥进行加密。而后发送给服务器,服务器使用它的私钥对它进行解密,这样两台计算机能够开始进行对称加密进行通讯。

ps:

SSL:安全套接层,是netscape公司设计的主要用于web的安全传输协议。这种协议在WEB上得到了普遍的应用。经过证书认证来确保客户端和网站服务器之间的通讯数据是加密安全的。

传输层安全性协议(Transport Layer Security,缩写TLS) 。

跨域

当一个资源从与该资源自己所在的服务器不一样的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不一样源服务器上的指定的资源。

可查看: juejin.im/post/5c9c38…

HTTP CSP(内容安全策略)

内容安全策略 (CSP, Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的攻击,包括跨站脚本 (XSS) 和数据注入等攻击。 这些攻击可用于实现从数据窃取到网站破坏或做为恶意软件分发版本等用途。

语法格式:

Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:
复制代码

支持的策略指令:

一、 default-src

default-src 指令定义了那些没有被更精确指令指定的(默认)安全策略。该指令包含了如下指令:

  • child-src
  • connect-src
  • font-src
  • img-src
  • media-src
  • object-src
  • script-src
  • style-src

内容源:

内容源有三种:源列表、关键字和数据

关键字:

'none' 表明空集;即不匹配任何 URL。两侧单引号是必须的。

'self' 表明和文档同源,包括相同的 URL 协议和端口号。两侧单引号是必须的。

'unsafe-inline' 容许使用内联资源,如内联的<script>元素、javascript: URL、内联的事件处理函数和内联的<style>元素,两侧单引号是必须的。

'unsafe-eval' 容许使用 eval() 等经过字符串建立代码的方法。两侧单引号是必须的。

代码例子

网站管理员但愿全部内容都来自网站自己(不包括子域名)。

Content-Security-Policy: default-src 'self'
复制代码

网站管理员但愿容许来自受信任域及其全部子域的内容(它没必要与CSP设置的域相同)。

Content-Security-Policy: default-src 'self' *.a.com
复制代码

网站管理员但愿容许Web应用程序的用户未来自任何来源的图像包含在本身的内容中,但要将音频或视频媒体限制为可信任的提供者,而且仅将全部脚本限制在承载受信任代码的特定服务器上。

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
复制代码

在此,默认状况下,仅容许来自文档来源的内容,但如下状况除外:

  • 图像可能从任何地方加载(请注意“*”通配符)。

  • 媒体只容许来自media1.com和media2.com(而不是来自这些网站的子域)。

  • 可执行脚本只容许来自userscripts.example.com。

更多内容可参考: developer.mozilla.org/zh-CN/docs/…

web攻击

防护这些劫持最好的方法仍是从后端入手,前端能作的实在太少。并且因为源码的暴露,攻击者很容易绕过咱们的防护手段。可是这不表明咱们去了解这块的相关知识是没意义的,本文的许多方法,用在其余方面也是大有做用。

HTTP为何不安全?有什么缺点?

通讯使用明文(不加密),内容可能会被窃听

不验证通讯方身份,所以有可能遭遇假装

没法证实报文的完整性,因此有可能已遭篡改

一、可能被窃听

  • HTTP 自己不具有加密的功能,因此也没法作到通讯总体(使用HTTP协议通讯的请求和响应的内容)进行加密。HTTP 报文使用明文方式发送。
  • 因为互联网是由联通世界各个地方的网络设施组成,全部发送和接收通过某些设备的数据均可能被截获或窥视。(例如你们都熟悉的抓包工具:Wireshark),即便通过加密处理,也会被窥视是通讯内容,只是可能很难或者没法破解出报文的信息而已

二、 认证问题

  • 没法确认你发送到的服务器就是真正的目标服务器(可能服务器是假装的)
  • 没法肯定返回的客户端是不是按照真实意图接收的客户端(多是假装的客户端)
  • 没法肯定正在通讯的对方是否具有访问权限,Web 服务器上某些重要的信息,只想发给特定用户即便是无心义的请求也会照单全收。没法阻止海量请求下的 DoS 攻击(Denial of Service,拒绝服务攻击)。

三、 可能被篡改

请求或响应在传输途中,遭攻击者拦截并篡改内容的攻击被称为中间人攻击(Man-in-the-Middle attack,MITM)。

HTTPS解决上述三个问题

HTTPS基于HTTP协议,经过SSL或TLS(能够看做SSL3.0)提供加密处理数据、验证对方身份以及数据完整性保护。特色以下:

  • 内容加密:采用混合加密技术,中间者没法直接查看明文内容
  • 验证身份:经过证书认证客户端访问的是本身的服务器
  • 保护数据完整性:防止传输的内容被中间人冒充或者篡改

HTTP协议Content Lenth限制漏洞致使拒绝服务攻击

使用POST方法时,能够设置ContentLenth来定义须要传送的数据长度,例如ContentLenth:999999999,在传送完成前,内 存不会释放,攻击者能够利用这个缺陷,连续向WEB服务器发送垃圾数据直至WEB服务器内存耗尽。这种攻击方法基本不会留下痕迹。

利用HTTP协议的特性进行拒绝服务攻击的一些构思

服务器端忙于处理攻击者伪造的TCP链接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率很是之小),此时从正常客户的角度看来,服务器失去响应,这种状况咱们称做:服务器端受到了SYNFlood攻击(SYN洪水攻击)。

而Smurf、TearDrop等是利用ICMP报文来Flood和IP碎片攻击的。本文用“正常链接”的方法来产生拒绝服务攻击。

19端口在早期已经有人用来作Chargen攻击了,即Chargen_Denial_of_Service,可是!他们用的方法是在两台Chargen 服务器之间产生UDP链接,让服务器处理过多信息而DOWN掉,那么,干掉一台WEB服务器的条件就必须有2个:1.有Chargen服务2.有HTTP 服务

方法:攻击者伪造源IP给N台Chargen发送链接请求(Connect),Chargen接收到链接后就会返回每秒72字节的字符流(实际上根据网络实际状况,这个速度更快)给服务器。

HTTP头注入

替换HTTP头字符值中的换行符。

CSRF 攻击

CSRF中文名为跨站请求伪造。假如http://a.com网址上有个加关注的GET接口,id参数是关注人Id,以下:

http://a.com?id=12
复制代码

那我只须要在个人一个页面里面写一个img标签:

<img src="http://a.com?id=12" />
复制代码

那么只要有已经登陆http://a.com网址的用户打开我这个页面,就会自动关注我。 就算是改成POST请求,也能够经过在页面使用form表单提交的方式自动关注。 CSRF攻击是源于Web的隐式身份验证机制!Web的身份验证机制虽然能够保证一个请求是来自于某个用户的浏览器,但却没法保证该请求是用户批准发送的。CSRF攻击的问题通常是由服务端解决,防范 CSRF 攻击能够遵循如下几种规则:

  1. Get 请求不用于对数据进行修改
  2. Cookie设置HTTP Only
  3. 接口设置禁止跨域
  4. 请求时附带验证信息,好比验证码或者 Token

CSRF 攻击的防范

一、验证码, 验证码被认为是对抗 CSRF 攻击最简洁而有效的防护方法。

二、Referer Check, 根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。经过 Referer Check,能够检查请求是否来自合法的"源"。 Referer Check 不只能防范 CSRF 攻击,另外一个应用场景是 "防止图片盗链"。

咱们能够建立一个白名单记录咱们的请求网址,当浏览器器发出请求的referer不在这个白名单内的网址,就认为是收到了csrf攻击,是不合法的请求,要拒绝该请求。

服务端代码:

if (req.headers.referer !== 'http://www.c.com:8002/') {
    res.write('csrf 攻击');
    return;
}
复制代码

三、添加 token 验证

要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,而且该信息不存在于 Cookie 之中。能够在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端创建一个拦截器来验证这个 token,若是请求中没有 token 或者 token 内容不正确,则认为多是 CSRF 攻击而拒绝该请求。

XSS攻击

XSS跨站脚本(Cross-site scripting) ,指的是攻击者利用漏洞,向 Web 页面中注入恶意代码,当用户浏览该页之时,注入的代码会被执行,从而达到攻击的特殊目的。

XSS攻击能够分为3类:反射型(非持久型)、存储型(持久型)、基于DOM。

常见的注入方式

<a href="javascript:alert(1)"></a>
复制代码
<iframe src="javascript:alert(1)" />
复制代码
<img src='x' onerror="alert(1)" />
复制代码
<video src='x' onerror="alert(1)" ></video>
复制代码
<div onclick="alert(1)" onmouseover="alert(2)" ><div>
复制代码

XSS 攻击的防范

如今主流的浏览器内置了防范 XSS 的措施,例如 CSP。但对于开发者来讲,也应该寻找可靠的解决方案来防止 XSS 攻击。

一、HttpOnly 防止劫取 Cookie:

response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")
复制代码

二、输入检查,由于用户可能输入的内容就是注入的脚本,当保存到服务器后,在返显示到页面就会被执行以前用户输入的注入内容;

解决方案: 对于用户的任何输入要进行检查、过滤和转义。创建可信任的字符和 HTML 标签白名单,对于不在白名单之列的字符或者标签进行过滤或编码。

在 XSS 防护中,输入检查通常是检查用户输入的数据中是否包含 <> 等特殊字符,若是存在,则对特殊字符进行过滤或编码,这种方式也称为 XSS Filter。

// 在 vuejs 中,若是输入带 script 标签的内容,会直接过滤掉
const decodingMap = {
  '&lt;': '<',
  '&gt;': '>',
  '&quot;': '"',
  '&amp;': '&',
  '&#10;': '\n'
}
复制代码

三、输出检查, 服务端的输出也会存在问题。通常来讲,除富文本的输出外,在变量输出到 HTML 页面时,能够使用编码或转义的方式来防护 XSS 攻击。例如利用 sanitize-html 对输出内容进行有规则的过滤以后再输出到页面中。

防止文件注入型攻击

防范:

一、文件上传目录设置成不可执行

二、判断文件类型。结合MIME type与文件扩展名,设置文件类型白名单。对于图片文件,能够利用图片库函数深层次检查是否真是图片。

三、重命名文件名。

四、文件服务器使用独立的域名。

SQL注入

防范:数据与代码分离,即不用字符串拼凑SQL语句,使用SQL预处理方法(参数使用占位符 ?)。

XST处理

XST(跨站追踪)攻击,防范:关闭Web 服务器的TRACE方法。

问题回答总结

简述TCP三次握手

  • 第一次握手: 创建链接。客户端发送链接请求,发送SYN报文,将seq设置为X(某个值)。而后,客户端进入SYN_SEND状态,等待服务器的确认。
  • 第二次握手: 服务器收到客户端的SYN报文段。须要对这个SYN报文段进行确认,发送ACK报文,将ack设置为X+1。同时,本身还要发送SYN请求信息,将seq为Y。服务器端将上述全部信息一并发送给客户端,此时服务器进入SYN_RECV状态。
  • 第三次握手: 客户端收到服务器的ACK和SYN报文后,进行确认,而后将ack设置为Y+1,seq设置为X+1,向服务器发送ACK报文段,这个报文段发送完毕之后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

第三次握手的缘由是为了防止已失效的链接请求报文段忽然又传回给服务器进程从而产生错误。假设客户端发送第一次链接请求因为网络滞留了,因而客户端又发送了一次请求并成功创建链接,数据传输完毕后就释放了链接。在释放链接后的某个时间段内客户端的第一次报文段又到达了服务器并被服务器进程确认,若是没有第三次握手,则服务器会一直等待客户端发送数据,从而浪费许多资源。

从输入URL到页面加载完成,发生了什么?

可参考:how browers work

一、用户输入URL;

二、 浏览器首先依次查询自身缓存,系统缓存和路由器缓存的记录,若是没有则查询本地host文件,尚未就向DNS服务器发送域名解析请求;

三、浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;

四、解析出 IP 地址后,根据该 IP 地址和默认端口 80(若是输入的URL中有端口号就用你输入的), 向服务器指定端口发起TCP链接请求,经过运输层,网络层,数据链路层,物理层到达服务器,通过三次握手后创建TCP链接 ;

五、三次握手后,就能够传输数据了,客户端将要发送的内容构建成HTTP请求报文并封装在TCP包中,经过TCP协议发送到服务器指定端口;

六、 服务器解析HTTP请求并按照报文格式封装成须要的HTTP对象,返回给浏览器。

七、数据传输完毕后,就经过四次分手将客户端和服务器的链接释放。

八、 浏览器根据拿到的响应报文进行页面的解析和渲染

ps:浏览器解析和渲染

浏览器根据拿到的响应报文进行解析和页面的渲染。 在渲染页面以前,须要构建DOM树和CSSOM树。 浏览器是一个边解析边渲染的过程。

一、构建DOM树

HTML文档会被解析成一棵以document为根的DOM树,解析过程当中若是遇到JavaScript,则会暂停解析并传输下载相应的文件形成阻塞,故推荐将JavaScript脚本放在HTML文件的后面。

二、构建CSSSOM树

浏览器根据外部样式,内部样式和内联样式来解析CSS,构建CSSSOM树。

三、构建渲染树和布局

DOM树和CSSOM树构建完毕后会融合成渲染树,而后浏览器会确认页面各元素的位置。

四、页面绘制和优化

浏览器根据布局结果进行页面的绘制,并优化页面内容,减少CPU消耗。

渲染结束后整个页面就呈如今咱们面前了。

如何实现浏览器内多个标签页之间的通讯?

一、WebSocket:由于websokect是全双工通讯,因此能够实现多个标签页以前的通讯;

二、SharedWorker: html5浏览器的新特性, 能够多个标签页、iframe共同使用的 三、 localstorage:是浏览器多个标签共用的存储空间,因此能够用来实现多标签之间的通讯;

思路: onstorage以及storage事件,针对都是非当前页面对localStorage进行修改时才会触发,当前页面修改localStorage不会触发监听函数。

window.onstorage = (e) => {console.log(e)}
复制代码

或者

window.addEventListener("storage",function(event){
   &emsp;$("#name").val(event.key+”=”+event.newValue);
}); 
复制代码

注意quirks:Safari 在无痕模式下设置localstorge值时会抛出 QuotaExceededError 的异常

四、 使用cookie+setInterval

这个方法使用定时器不断栓下,是至关浪费资源的,虽然能实现方案,可是不够优雅。

思路:

在页面A设置一个使用 setInterval 定时器不断刷新,检查 Cookies 的值是否发生变化,若是变化就进行刷新的操做。

因为 Cookies 是在同域可读的,因此在页面 B 审核的时候改变 Cookies 的值,页面 A 天然是能够拿到的。

TCP与UDP的区别

TCP提供面向链接的,可靠的数据传输服务。以报文段的形式传输;

UDP提供无链接的,尽最大努力的数据传输服务。以用户数据报的形式传输。

TCP与UDP的区别: TCP协议相对于UDP协议的特色是:TCP协议提供面向链接、字节流和可靠的传输。

HTTP响应码你都知道哪些?都是什么意思?

常见状态码

200 - OK 请求成功,客户端发过来的数据被正常处理
    
    204 - Not Content 正常响应,没有实体
    
    206 - Partial Content 范围请求,返回部分数据,响应报文中由Content-Range指定实体内容

    301 - Moved Permanently 请求永久重定向,转移到其它URL

    302 - Found 请求临时重定向
    
    303 - See Other 和302相似,但必须用GET方法

    304 - Not Modified) 状态未改变, 配合(If-Match、If-Modified-Since、If-None_Match、If-Range、If-Unmodified-Since) 
    
    307 - Temporary Redirect 临时重定向,和302相似,不应改变原请求方法

    400 - Bad Request 客户端请求报文存在语法错误

    401 - unauthorized 客户端请求没有通过受权

    403 - Forbidden 客户端的请求被服务器拒绝,通常为客户端没有访问权限

    404 - Not Found 服务器上没法找到请求的资源

    500 - Internal Server Error 服务器内部错误
    
    503 - Service Unavailable 服务器处于超负载或正在停机维护
复制代码

HTTP协议的工做流程?

  • 一、地址解析

  • 二、封装HTTP请求数据包

  • 三、封装TCP包,创建TCP连接(TCP的三次握手)

  • 四、客户端发送请求命令

  • 五、服务器响应

  • 六、服务器关闭TCP连接

什么是长连接,为何须要长链接?

长链接也能够成为持久连接,HTTP/1.1默认开启长链接(持久连接), 数据传输完成了保持TCP链接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据(一个TCP链接上能够传送多个HTTP请求和响应);

为何须要长链接?

TCP链接的新建成本很高,由于须要客户端和服务器三次握手,而且开始时发送速率较慢(slow start)。 随着网页加载的外部资源愈来愈多,这个问题就愈发突出了。

因此, HTTP 1.0版本的性能比较差。 解决方法:在发送请求时,设置字段:

Connection: keep-alive
复制代码

这个字段要求服务器不要关闭TCP链接,以便其余请求复用。服务器一样回应这个字段。 一个能够复用的TCP链接就创建了,直到客户端或服务器主动关闭链接。可是,这不是标准字段,不一样实现的行为可能不一致,所以不是根本的解决办法。

而HTTP/1.1默认开启的, 不用声明Connection: keep-alive

HTTP/2的信道复用又为何能提升性能?

在 HTTP/2 中,四大特性:头部压缩、二进制流、服务器推送、多路复用。

为何说HTTP /2 的信道复用能提升性能呢?

  • 同个域名只须要占用一个 TCP 链接,使用一个链接并行发送多个请求和响应,这样整个页面资源的下载过程只须要一次慢启动,同时也避免了多个TCP链接竞争带宽所带来的问题。
  • 并行交错地发送多个请求/响应,请求/响应之间互不影响。
  • 在HTTP/2中,每一个请求均可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就能够在处理不一样的流时采起不一样的策略,以最优的方式发送流、消息和帧。

针对HTTP/1.1的优化有哪些HTTP/2不在适用?

  • JS文件的合并。咱们如今优化的一个主要方向就是尽可能的减小HTTP的请求数, 对咱们工程中的代码,研发时分模块开发,上线时咱们会把全部的代码进行压缩合并,合并成一个文件,这样无论多少模块,都请求一个文件,减小了HTTP的请求数。可是这样作有一个很是严重的问题:文件的缓存。当咱们有100个模块时,有一个模块改了东西,按照以前的方式,整个文件浏览器都须要从新下载,不能被缓存。如今咱们有了HTTP/2了,模块就能够单独的压缩上线,而不影响其余没有修改的模块。
  • 多域名提升浏览器的下载速度。以前咱们有一个优化就是把css文件和js文件放到2个域名下面,这样浏览器就能够对这两个类型的文件进行同时下载,避免了浏览器6个通道的限制,这样作的缺点也是明显的,1.DNS的解析时间会变长。2.增长了服务器的压力。有了HTTP/2以后,根据上面讲的原理,咱们就不用这么搞了,成本会更低。

HTTP1.0 和 1.1 现存的一些问题

  1. HTTP1.x 在传输数据时,每次都须要从新创建链接,无疑增长了大量的延迟时间,特别是在移动端更为突出。
  2. HTTP1.x 在传输数据时,全部传输的内容都是明文,客户端和服务器端都没法验证对方的身份,这在必定程度上没法保证数据的安全性。
  3. HTTP1.x 在使用时,header 里携带的内容过大,在必定程度上增长了传输的成本,而且每次请求 header 基本不怎么变化,尤为在移动端增长用户流量。
  4. 虽然 HTTP1.x 支持了 keep-alive,来弥补屡次建立链接产生的延迟,可是 keep-alive 使用多了一样会给服务端带来大量的性能压力,而且对于单个文件被不断请求的服务 (例如图片存放网站),keep-alive 可能会极大的影响性能,由于它在文件被请求以后还保持了没必要要的链接很长时间。

HTTPS和HTTP的区别

  1. HTTPS协议须要到CA(证书颁发机构)申请证书,通常免费证书不多,须要交费。
  2. HTTP协议运行在TCP之上,全部传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,全部传输的内容都通过加密的。
  3. HTTP和HTTPS使用的是彻底不一样的链接方式,用的端口也不同,前者是80,后者是443。
  4. http的链接很简单,是无状态的;HTTPS协议是由HTTP+SSL协议构建的可进行加密传输、身份认证的网络协议,能够有效的防止运营商劫持,解决了防劫持的一个大问题,比http协议安全。

如何将HTTP变为HTTPS?

若是一个网站要全站由 HTTP 替换成 HTTPS,可能须要关注如下几点:

  1. 安装 CA 证书,通常的证书都是须要收费的,
  2. 在购买证书以后,在证书提供的网站上配置本身的域名,将证书下载下来以后,配置本身的 web 服务器,同时进行代码改造。
  3. HTTPS 下降用户访问速度。SSL 握手,HTTPS 对速度会有必定程度的下降,可是只要通过合理优化和部署,HTTPS 对速度的影响彻底能够接受。在不少场景下,HTTPS 速度彻底不逊于 HTTP,若是使用 SPDY,HTTPS 的速度甚至还要比 HTTP 快。
  4. 相对于 HTTPS 下降访问速度,其实更须要关心的是服务器端的 CPU 压力,HTTPS 中大量的密钥算法计算,会消耗大量的 CPU 资源,只有足够的优化,HTTPS 的机器成本才不会明显增长。

什么是缓存?

缓存HTTP的仓库,使经常使用页面的副本能够保存在离客户端更近的地方。

HTTP的缓存机制

HTTP的缓存分为强缓存和协商缓存(对比缓存)。

HTTP缓存有多种规则,根据是否须要从新向服务器发起请求来分类,可将其分为强制缓存,对比缓存。

  • 强制缓存若是生效,不须要再和服务器发生交互,而对比缓存无论是否生效,都须要与服务端发生交互
  • 两类缓存规则能够同时存在,强制缓存优先级高于对比缓存,也就是说,当执行强制缓存的规则时,若是缓存生效,直接使用缓存,再也不执行对比缓存规则

如何高效利用缓存,上线前端代码?

一、缓存时间过长,发布上线了,用户端还用缓存,会有bug

二、缓存时间太短,重复加载文件过多,浪费带宽

通常个人处理方式是:

step1:咱们不让 html 文件缓存( 静态资源(css、js 、image、audio等) ),每次访问 html 都去请求服务器。因此浏览器每次都能拿到最新的html资源。

step2:将 静态资源(css、js 、image、audio等)原来的文件名加上每次打包的版本号,或者时间戳、指纹,这样的好处是,能够知道静态资源时哪次打包的,哪些资源时此次更改的,若是出现错误,须要回溯版本,也能够快速回溯。其实这样仍是不是最优的方法;

对于大公司的静态资源优化方案是: 用文件的摘要信息来对资源文件进行重命名,把摘要信息放到资源文件发布路径中,这样,内容有修改的资源就变成了一个新的文件发布到线上,不会覆盖已有的资源文件。上线过程当中,先全量部署静态资源,再灰度部署页面,整个问题就比较完美的解决了。

因此,大公司的静态资源优化方案,基本上要实现这么几个东西:

配置超长时间的本地缓存 —— 节省带宽,提升性能 采用内容摘要做为缓存更新依据 —— 精确的缓存控制 静态资源CDN部署 —— 优化网络请求 更资源发布路径实现非覆盖式发布 —— 平滑升级

step3:先上线静态资源,在上线html

咱们能够利用webpack工程化工具解决。

HTTP 如何处理大文件的传输?

HTTP针对大文件的传输场景,能够使用范围请求来解决,客户端将资源一部分一部分传输。

通常是:压缩、分块、范围请求、多端数据的流程。

那范围请求是怎么处理的呢?

响应头使用:Accept-Ranges 用来告知客户端这边是支持范围请求的;

请求头使用: Rang来制定请求哪一部分。Range: bytes=x-y

bytes=x-y 表示范围格式有:

  • 0-y表示从开始到第 y 个字节。
  • y- 表示从第 y 字节到文件终点。
  • -y表示文件的最后y个字节。
  • x-y 表示文件第x-y字节范围的内容

服务器收到请求以后,首先验证范围是否合法,若是越界了那么返回416错误码,不然读取相应片断,返回206状态码。

同时,服务器须要添加Content-Range字段,这个字段的格式根据请求头中Range字段的不一样而有所差别。

对于单段数据的请求,返回的响应以下:

HTTP/1.1 206 Partial Content
Content-Length: 10
Accept-Ranges: bytes
Content-Range: bytes 0-9/100

。。。
复制代码

值得注意的是Content-Range字段,0-9表示请求的返回,100表示资源的总大小,很好理解。

多段数据

接下来咱们看看多段请求的状况。获得的响应会是下面这个形式:

HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=00000010101
Content-Length: 189
Connection: keep-alive
Accept-Ranges: bytes


--00000010101
Content-Type: text/plain
Content-Range: bytes 0-9/96


--00000010101
Content-Type: text/plain
Content-Range: bytes 20-29/96

eex jspy e
--00000010101--
复制代码

这个时候出现了一个很是关键的字段Content-Type: multipart/byteranges;boundary=00000010101,它表明了信息量是这样的:

  • 请求必定是多段数据请求
  • 响应体中的分隔符是 00000010101

所以,在响应体中各段数据之间会由这里指定的分隔符分开,并且在最后的分隔末尾添上--表示结束。

什么是代理?

代理是位于客户端和服务器之间的HTTP中间实体。接收全部客户端的HTTP请求,并将这些请求转发给服务器(可能会对请求进行修改以后转发)。

什么是Agent代理?

用户Agent代理是表明用户发起HTTP的客户端程序。好比Web浏览器。另外有些自动发送HTTP请求并获取内容的代理,好比“网络蜘蛛”或者“Web机器人”。

如何理解 HTTP 代理?

在web中,http代理是一种客户端和web服务器之间的一种实体。它既具有客户端的发起请求功能,还能够像web服务器同样返回响应。

代理和网关之间的首要差别是代理只能转发同一种协议,而网关可以转发多种协议。

HTTP 代理存在两种形式,分别简单介绍以下:

第一种是 RFC 7230 - HTTP/1.1: Message Syntax and Routing(即修订后的 RFC 2616,HTTP/1.1 协议的第一部分)描述的普通代理。这种代理扮演的是「中间人」角色,对于链接到它的客户端来讲,它是服务端;对于要链接的服务端来讲,它是客户端。它就负责在两端之间来回传送 HTTP 报文。

第二种是 Tunneling TCP based protocols through Web proxy servers(经过 Web 代理服务器用隧道方式传输基于 TCP 的协议)描述的隧道代理。它经过 HTTP 协议正文部分(Body)完成通信,以 HTTP 的方式实现任意基于 TCP 的应用层协议代理。这种代理使用 HTTP 的 CONNECT 方法创建链接,但 CONNECT 最开始并非 RFC 2616 - HTTP/1.1 的一部分,直到 2014 年发布的 HTTP/1.1 修订版中,才增长了对 CONNECT 及隧道代理的描述,详见 RFC 7231 - HTTP/1.1: Semantics and Content。实际上这种代理早就被普遍实现。

什么是网关?

网关是一种特殊的服务器,做为其余服务器的中间实体使用。一般用于将HTTP流量转换成其余的协议。

什么是隧道?

隧道是创建起来以后,就会在两条链接之间对原始数据进行盲转发的HTTP应用程序。常见用途是经过HTTP链接承载加密的安全套接字层(SSL)流量,这样SSL流量就能够穿过只容许Web流量经过的防火墙了。

———————————————————————————————————

本文解析或者答案仅供参考,内容参考如下资料~~

参考资料:

《图解HTTP》

《HTTP权威指南》

taligarsiel.com/Projects/ho…

cloud.tencent.com/document/pr…

httpwg.org/specs/rfc75…

www.runoob.com/http/http-c…

ye11ow.gitbooks.io/http2-expla…

github.com/creeperyang…

www.cnblogs.com/coco1s/p/57…

developer.mozilla.org/zh-CN/docs/…

developer.mozilla.org/zh-CN/docs/…

相关文章
相关标签/搜索