HTTP超全详解

HTTP协议简介

超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
HTTP协议永远都是客户端发起请求,服务器回送响应。见下图:
在这里插入图片描述

HTTP工作流程

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

  1. 客户机与服务器建立TCP连接。只要单击某个超级链接/输入网址/提交表单等。
  2. 建立连接后,客户机发送http请求给服务器.
  3. 服务器接到请求后,响应信息。
  4. 客户端接收服务器所返回的信息,然后客户机与服务器断开TCP连接。

HTTP发展及各版本

版本产生时间内容发展现状
HTTP/1.11997年持久连接(长连接)、节约带宽、HOST域、管道机制、分块传输编码2015年前使用最广泛
HTTP/22015年多路复用、服务器推送、头信息压缩、二进制协议等逐渐覆盖市场
  • HTTP1.1 版本

HTTP 1.1 新增了delete options 等几种请求数据的方式,客户端和服务端三次握手后,建立tcp链接,一个tcp链接可以传送多个请求和响应,这样就减少了握手和建立tcp和关闭tcp链接的消耗,传输更快
HTTP 1.1 支持持久链接 请求头有一个connection 参数,参数值是close/keep-alive 意思是本次请求处理完后,服务器是关闭该tcp链接还是继续使用该链接

  • HTTP 2.0 版本

HTTP2.0使用了多路复用的技术,做到同一个链接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。

在这里插入图片描述

HTTP主要特点

  • 简单快速
    客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  • 灵活
    HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  • 无连接
    无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

1. 无连接?有连接?
HTTP不是字面意义上的没有连接,事实上,这个定义也符合HTTP短连接的定义,但无连接强调的是HTTP的特性,短连接可理解为一种实现。
无连接的含义也可以结合HTTP无状态的含义在应用层面上去理解:每一个请求都拥有自己的请求体,期望接收到唯一的对应的响应体,而每一次的请求都相互独立,与上一次或下一次的请求毫无关系,哪怕是在同一条连接中(后面说的长连接)。
> 2. 什么是长连接、短连接?
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
在这里插入图片描述在这里插入图片描述

  • 无状态
    无状态是指协议对于事务处理没有记忆能力。也就是说,打开一个服务器上的网页和上一次打开这个服务器上的网页之间没有任何联系。HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接)。
    在这里插入图片描述加粗样式

  • 支持B/S及C/S模式

TCP三次握手

HTTP属于应用层协议,传输层使用TCP协议。HTTP协议是建立在TCP协议之上的一种应用。
为什么要三次握手?
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
比如:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段,但是server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求,于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了,由于client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据,但server却以为新的运输连接已经建立,并一直等待client发来数据。所以没有采用“三次握手”,这种情况下server的很多资源就白白浪费掉了。

【1】seq:序号,占4个字节,由于TCP是面向字节流的,在一个1个TCP连接中传送字节流中国的每一个字节都按照顺序编号,此外序号是循环使用的
【2】ACK:仅当ACK=1时确认字段才有效,当ACK=0时确认字段无效,并且TCP规定,在连接建立后所有的传送报文段都必须要把ACK置为1
【3】SYN:同步序列号,用来发起一个连接。当SYN=1而ACK=0时表明这是一个请求报文段;若对方同意连接,则响应报文中SYN=1,ACK=1

在这里插入图片描述

  1. 第一次握手:
    服务器端处于LISTEN(收听)状态,等待客户端连接请求。
    客户端发送连接请求报文段,将SYN=1,初始序号seq=x。(SYN报文段不能携带数据,但消耗一个序号)
    客户端进入SYN_SENT(同步已发送)状态,等待服务器的确认;
  2. 第二次握手:
    服务器收到客户端请求的SYN报文段。需要对这个SYN报文段进行确认,确认号ack=x+1(seq+1);
    服务器发送SYN请求信息,将SYN=1,ACK=1,并为自己选择一个初始序号seq=y;
    服务器端发送确认报文段(SYN+ACK报文段)给客户端(报文段不能携带数据,但消耗一个序号)
    服务器进入SYN_RECV(同步收到)状态;
  3. 第三次握手:
    客户端收到服务器的SYN+ACK报文段。将确认号ack设置为y+1,序列号为seq=x+1。
    客户端向服务器发送ACK报文段(ACK报文段可以携带数据,如果不携带数据则不消耗序号)。
    TCP连接建立,客户端和服务器端都进入ESTABLISHED(已建立连接)状态,完成TCP三次握手。

HTTP协议安全机制

HTTPS (Secure Hypertext Transfer Protocol)安全超文本传输协议。HTTPS是在HTTP上建立SSL加密层,并对传输数据进行加密,是HTTP协议的安全版。HTTPS提供的安全通信,应用了对称加密,非对称加密,数据签名等技术。
HTTP缺点:不够安全——明文传输,不做加密,易被中间人攻击(中间人截获甚至篡改信息)
HTTPS主要作用:
(1)对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全;
(2)对网站服务器进行真实身份认证。
在这里插入图片描述

HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

GET        请求指定的页面信息,并返回实体主体。
HEAD       类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
POST       向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
PUT        从客户端向服务器传送的数据取代指定的文档的内容。
DELETE     请求服务器删除指定的页面。
CONNECT    HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS    允许客户端查看服务器的性能。
TRACE      回显服务器收到的请求,主要用于测试或诊断。

POST与GET请求方式

get是从服务器上获取数据、post是向服务器传送数据。
get服务器端用Request.QueryString获取变量的值、post用Request.Form获取提交的数据。
get传送数据量小,不大于2KB、post默认为不受限制。但理论上IIS4中最大量为80KB,IIS5中为100KB。
get安全性非常低、post安全性较高。(如果没有加密,安全级别是一样) get请求只能进行url编码,post支持多种编码方式。
get请求参数会被完整保留在浏览器历史记录里,post中的参数不会被保留。 get参数通过URL传递,post放在Request body中
建议 包含机密信息的话,做数据添加、修改或删除时,建议用post数据提交方式;在做数据查询时,建议用get方式

HTTP之状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1xx: 指示信息--表示请求已接收,继续处理
2xx: 成功--表示请求已被成功接收、理解、接受
3xx: 重定向--要完成请求必须进行更进一步的操作
4xx: 客户端错误--请求有语法错误或请求无法实现
5xx: 服务器端错误--服务器未能实现合法的请求

常见状态码:

200  OK 
你最希望看到的,即处理成功! 
303  See Other 
我把你redirect到其它的页面,目标的URL通过响应报文头的Location告诉你。
304  Not Modified 
告诉客户端,上次请求之后没有任何修改,你直接用你本地的缓存吧,我很忙哦! 
400  Bad Request    
客户端请求有语法错误,不能被服务器所理解
401  Unauthorized  
请求未经授权,必须和WWW-Authenticate报头域一起使用 
403  FORBIDDEN
客户端未能获得授权。服务器收到请求,但是拒绝提供服务。
404  Not Found 
你最不希望看到的,即找不到页面。eg:输入了错误的URL
500  Internal Server Error
看到这个错误,你就应该查查服务端的日志了,肯定抛出了一堆异常,别睡了,起来改BUG去吧!
503  Server Unavailable    
服务器当前不能处理客户端的请求,一段时间后可能恢复正常

HTTP消息结构

HTTP请求格式(请求协议)
在这里插入图片描述
在这里插入图片描述

HTTP响应格式(响应协议)

在这里插入图片描述
在这里插入图片描述

什么是Cookie?

Cookie意为“甜饼”是服务器给客户端颁发的一个通行证。无论谁访问都必须携带自己通行证。服务器能确认客户身份。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
Cookie 主要应用

1.会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
2.个性化设置(如用户自定义设置、主题等)
3.浏览器行为跟踪(如跟踪分析用户行为等)

操作Cookie

获取Cookie
通过docuemnt.cookie可以设置和获取Cookie的值

document.cookie

创建Cookie
可以使用 document.cookie 属性来创建 、读取、及删除 cookie。

document.cookie="username=John Doe";

为 cookie 添加一个过期时间(以 UTC 或 GMT 时间)。默认情况下,cookie 在浏览器关闭时删除:

document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT";

使用 path 参数告诉浏览器 cookie 的路径。默认情况下,cookie 属于当前页面。

document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";

修改 Cookie
修改 cookie 类似于创建 cookie

document.cookie="username=John Smith; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";

旧的 cookie 将被覆盖。

删除 Cookie
删除 cookie 非常简单。只需要设置 expires 参数为以前的时间即可

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";

注意,当删除时不必指定 cookie 的值。

Cookie常用属性

  • name
    Cookie的名称。Cookie一旦创建,名称便不可更改

  • value
    Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码

  • maxAge
    Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1。不设置的话默认值是Session,意思是cookie会和session一起失效。当浏览器关闭(不是浏览器标签页,而是整个浏览器)
    后,此cookie失效。

  • secure
    Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false

  • path
    Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”
    domain
    可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”

  • comment
    该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明

  • version
    该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

Session机制

除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。
什么是Session?
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器再次访问时只需要从该Session中查找该客户的状态。
如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表。
Cookie与Session的区别

  1. 使用方式:
    cookie机制:如果不在浏览器中设置过期事件,cookie被保存在内存中,生命周期随浏览器的关闭而结束,这种cookie简称为会话cookie。如果在浏览器中设置了cookie的过期事件,cookie会被保存在硬盘中,关闭浏览器后,cookie数据仍然存在,直到过期事件结束才消失。
    session机制:当服务器收到请求需要创建session对象时,首先会检查客户端请求中是否包含sessionid。如果有sessionid,服务器将根据该id返回对应session对象。如果客户端请求中没有sessionid,服务器会创建新的session对象,并把sessionid在本次响应中返回给客户端。通常使用cookie方式存储sessionid到客户端,在交互中浏览器按照规则将sessionid发送给服务器。
  2. 保持状态:
    cookie保存在浏览器端,session保存在服务器端
  3. 存储的大小:
    单个cookie保存的数据不能超过4kb;session大小没有限制。
  4. 存储内容:
    cookie只能保存字符串类型,以文本的方式。session通过类似与Hashtable的数据结构来保存,支持任何类型的对象
  5. 安全性:
    session的安全性大于cookie。

原因如下:

(1)sessionid存储在cookie中,若要攻破session首先要攻破cookie;
(2)sessionid是要有人登录,或者启动session_start才会有,所以攻破cookie也不一定能得到sessionid;
(3)第二次启动session_start后,前一次的sessionid就是失效了,session过期后,sessionid也随之失效。
(4)sessionid是加密的。

综上所述,攻击者必须在短时间内攻破加密的sessionid,这很难。

  1. 应用场景:
    cookie:
    (1)判断用户是否登录过网站,以便下次登录时能够实现自动登录(或者记住密码)。
    (2)保存上次登录的事件等信息。
    (3)保存上次查看的页面
    (4)浏览计数
    session:
    (1)网上商城中的购物车
    (2)保存用户登录信息
    (3)将某些数据放入session中,供同一用户的不同页面使用
    (4)防止用户非法登录

WebStorage

WebStorage的目的是克服由cookie所带来的一些限制,当数据需要被严格控制在客户端时,不需要持续的将数据发回服务器。
WebStorage两个主要目标:

1.提供一种在cookie之外存储会话数据的路径
2.提供一种存储大量可以跨会话存在的数据的机制

HTML5的WebStorage提供了两种API:localStorage(本地存储)sessionStorage(会话存储)
localStorage和sessionStorage的区别

1.生命周期:
localStorage的生命周期是永久的,关闭页面或浏览器之后localStorage中的数据也不会消失。localStorage除非主动删除数据,否则数据永远不会消失。
sessionStorage的生命周期是仅在当前会话下有效。sessionStorage引入了一个“浏览器窗口”的概念,sessionStorage是在同源的窗口中始终存在的数据。只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源另一个页面,数据依然存在。但是sessionStorage在关闭了浏览器窗口后就会被销毁。同时独立的打开同一个窗口同一个页面,sessionStorage也是不一样的。
2.存储大小:
两者的存储数据大小一般都是:5MB
3.存储位置:
两者都保存在客户端,不与服务器进行交互通信
4.存储内容类型:
两者只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
5.获取方式:
localStorage:window.localStorage sessionStorage:window.sessionStorage
6.应用场景:
localStorage:长期登录(+判断用户是否已登录)适合长期保存在本地的数据 sessionStorage:敏感账号一次性登录 session和sessionStorage

1.session存储于服务器,也就是后端那;而sessionStorage存储于本地,也就是你一按F12就能看到。
2.session主要的作用是维持会话状态的key,而sessionStorage则是存储会话期间的数据。(有些人经常认为是sessionStorage中存session,这个理解也对,也不对。可以说成是:浏览器的window对象中的sessionStorage中存贮着后台的session。
3.session可以是在未关闭浏览器之前的或者服务器之前都是一个,但是 不同选项卡不同浏览器下的sessionStorage肯定不是一个!

跨域及解决方案

  • 什么是跨域?

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 广义的跨域:

  1. 资源跳转: A链接、重定向、表单提交
  2. 资源嵌入: link script img frame等dom标签,还有样式中background:url()、@font-face()等文件外链
  3. 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

在前端部分其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。

  • 什么同源策略?

同源策略/SOP(Same origin
policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制以下几种行为:
1.Cookie、LocalStorage 和 IndexDB 无法读取
2.DOM 和 Js对象无法获得
3.AJAX 请求不能发送

  • 常见的跨域场景

在这里插入图片描述

  • 跨域解决方案

1)通过jsonp跨域

–script、img、link、iframe ==> 不存在跨域限制 通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

html

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="./jsonp.js"></script>

jquery ajax:

$.ajax({
  url: "http://127.0.0.1:8001/list",
  type: "GET",
  dataType: "JSONP", //here
  success: (res) => {
    console.log(res);
  },
});

serverJSONP.js

let express = require("express");
app = express();
app.listen(8001, (_) => {
  console.log("ok!");
});
app.get("/list", (req, res) => {
  let { callback } = req.query;
  let data = {
    code: 0,
    message: "返回的数据",
  };
  res.send(`${callback}(${JSON.stringify(data)})`);
});

JSONP只能处理GET请求,GET请求通过URL传参可能会导致数据的劫持(不安全)。所以使用JSONP解决跨域不安全

2)postMessage跨域

postMessage是HTML5 XMLHttpRequest Level2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.)多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递
用法:postMessage(data,origin)方法接受两个参数 data:
html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

postMessage1.html

 <iframe
      id="iframe"
      src="http://127.0.0.1:1001/postMessage/postMessage2.html"
      style="display: none"
    ></iframe>
    <script>
      iframe.onload = function () {
        // 向postMessage2传送跨域数据
        iframe.contentWindow.postMessage("今天天气真不错", "*");
      };
      //监听postMessage2传递的信息
      window.onmessage = function (ev) {
        console.log(ev.data);
      };
    </script>

postMessage2.html

 <script>
      // 接收postMessage1发送的数据
      window.onmessage = function (ev) {
        console.log(ev.data);
        //ev.source:postMessage1
        ev.source.postMessage("postMessage2" + ev.data, ev.origin);
      };
    </script>

ServerPost1.js

let express = require("express");
app = express();
app.listen(1001, (_) => {
  console.log("servePost1 ok!");
});
app.use(express.static("./"));

serverPost2.js

let express = require("express");
app = express();
app.listen(1002, (_) => {
  console.log("servePost2 ok!");
});
app.use(express.static("./"));

3) 跨域资源共享(CORS)

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 

// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 

// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With")

4)window.name + iframe跨域
5)location.hash + iframe跨域
6)document.domain + iframe跨域
7)nginx反向代理跨域
8) WebSocket协议跨域