一、HTTP定义
HTTP是Hyper Text Transfer Protocol 超文本传输协议 的缩写。用于从WWW服务器传输超文本到本地浏览器的传送协议,是一个无状态的协议。
通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。
默认HTTP的端口号为80,HTTPS的端口号为443。
一般情况:
- HTTP协议永远都是客户端发起请求,服务器回送响应,客户端将内容拿到之后就和服务器断开来连接。这就决定了,如果客户端没有发起请求,服务器是没法推送数据给客户端的。
- 另外,因为是无状态的协议,所以上一次的连接和下一次的连接没有关系。
问题1:为什么说http协议是无状态的,影响?
Http协议本身就是一个 传输 协议,理解这个意思,更加广义一些就是支持资源的传输,那么在客户端浏览器向HTTP服务器发送请求,继而HTTP服务器将相应的资源发回给客户端这样一个过程中因为每一次请求和响应都是相对独立的。但是随着时间推移,HTML的语法在不断膨胀,其中最重要的是增加了表单,就有了很多带着数据的请求,有来有回的这么些动态交互的程序,HTTP无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie,而另一个则是Session。
问题2:http和TCP的区别,如何基于tcp实现http呢?
区别:
从上面的图中不难看出区别,TCP协议对应于运输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性。但是可以看到,http是基于tcp实现的,那么既然tcp是可靠的长连接,为什么http还存在短连接这一说呢?答案是,Http就是在每次请求完成后就把TCP连接关了,所以是短连接。而如果直接通过Socket编程使用TCP协议的时候,通过代码区控制什么时候打开连接、什么时候关闭,只要我们不通过代码把连接关闭,这个连接就会在客户端和服务端的进程中一直存在。
如何实现:
可以看到,其实http就是在tcp的传输之上加了一些内容,我们模拟这些思路就可以。
设定一个规则之后,开始处理:
1、实现两个主机不同进程之间的TCP通信。
2、分析请求方法(比如GET和POST方法)。
3、方法确定后,应该拿到请求的URL,
4、判断资源是否存在,如果存在,GET方法:如果没有参数,就直接将请求的资源返回(即进入非cgi模式运行);否则,进行对应的处理。
二、http报文格式
浏览器输入baidu.com,可以检查看到发出的请求报文头部格式
2.1 客户端请求消息格式
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:
- 请求行(request line)
- 请求头部(header)
- 空行
- 请求数据
四个部分组成。
- 请求行 包括请求方法(常用的有GET和POST),请求的URL,和协议版本(例如HTTP1.1);
- 请求头部 的格式就是字段名+值组成,一般有:
- User-Agent(用户代理):产生请求的浏览器类型
- Accept:客户端希望接受的数据类型,比如text/xml;
- Content-Type:发送端发送的实体数据的类型,比如text/html;
- Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
- 空行;
- 请求体(数据):GET没有请求数据,POST有。
其中,User-Agent用户代理,User-Agent会告诉网站服务器,访问者是通过什么工具来请求的,如果是爬虫请求,一般会拒绝,如果是用户浏览器,就会应答,另外服务器可以通过判断User-Agent来给不同的操作系统、不同的浏览器发送不同的页面。
他的格式一般是:Mozilla/5.0+(平台)+引擎版本+浏览器版本号。
更详细的字段解释可以看看这篇博客:https://www.cnblogs.com/xy51/p/12974945.html
比如上面我截图的部分:
- 向百度首页发送的请求,请求方法是get,协议版本是1.1,请求的URL没有写;
- 请求头部里面的User-Agent就说明了,平台是Windows、引擎版本就是从AppleWebKit到Safari那么长一段,浏览器版本号就是Chrome后面跟的那一串;
- Content-Type是text/html(谷歌浏览器的检查里没有显示这个);
- Accept就是很多数据类型;
- Host就是百度官网的域名。
2.2 服务端响应报文格式
HTTP响应报文和请求报文的结构类似,也是由四个部分组成:状态行、消息报头、空行、响应体。
- 状态行也由三部分组成:服务器HTTP协议版本,响应状态码,状态码的文本描述;
- 消息报头:Date时间,Content-Type,Content-Encoding编码格式,Content-Length内容长度等等,和请求报文的请求头部类似,也是字段+值的形式;
- 空行;
- 响应体:响应体就是对应的html加上别的各类资源数据的内容了。
三、HTTP请求方法类型
上面我们提到,http请求报文的请求行里会先写上请求方法。
HTTP 协议中共定义了八种方法或者叫“动作”:
- OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送 '*' 的请求来测试服务器的功能性。
- HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
- GET:向特定的资源发出请求。
- POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。
- PUT:向指定资源位置上传其最新内容。
- DELETE:请求服务器删除 Request-URI 所标识的资源。
- TRACE:回显服务器收到的请求,主要用于测试或诊断。
- CONNECT:HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
其中:OPTIONS, PUT, DELETE, TRACE, CONNECT这些方法都是http1.1新增的,在http1.0是没有的虽然 HTTP 的请求方式有 8 种,但是我们在实际应用中常用的也就是 get 和 post,其他请求方式也都可以通过这两种方式间接的来实现。
问题:常用的GET和POST请求的区别是什么?
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
- 请求次数不同(因而POST比GET更慢):
- GET产生一个TCP数据包;
- POST产生两个TCP数据包。
- 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
- 参数编码不同:
- GET仅支持URL编码,参数需要编码和解码;
- POST支持多种编码方式。
- 报文不同(因而POST能发送的数据更大):
- GET的参数放在了URL里面;
- POST参数在请求体中。
- 从这个层面来说,get请求更不安全,因为他把参数放在了url里(有了ssl,http变成https,就解决了这个问题)
- 缓存:
- GET会被浏览器缓存;
- POST不会。
- 以上几点带来的应用场景不同:
- post的目的是修改和写入数据;
- get一般用于搜索排序和筛选之类的操作(淘宝,支付宝的搜索查询都是get提交),目的是资源的获取,读取数据。
- 从5的层面总结来说,GET符合幂等性和安全性,POST不符合。
- 幂等性:对数据库的一次操作和多次操作获得的结果是一致的。
- GET操作是查询操作,不会改变数据库中原有的数据,只是类似于数据库的查询,大致认为符合幂等性和安全性。
- POST会往数据库中提交数据,会改变数据库中的数据;POST请求每次获得的结果都有可能不一样,因为POST作用在上一级的URL,每一次请求都会添加一份新资源,所以既不幂等也不安全。
注意事项:
- http协议从未规定get/post的请求长度限制是多少,所谓的请求长度限制是由浏览器和web服务器决定和设置的。
- 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
四、HTTP状态码常见的状态码:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它URL
- 404NotFound - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
- 400 Bad Request - 客户端请求有语法错误,不能被服务器所理解。此时需要分析客户端的代码,去看看请求为什么出现服务器无法理解的错误。
http的状态码三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。
状态码 | 含义 |
---|---|
1** | 信息。服务器收到请求,需要请求者继续执行操作 |
2** | 成功。操作被成功接收并处理 |
3** | 重定向。需要进一步的操作以完成请求 |
4** | 客户端错误。请求包含语法错误或无法完成请求 |
5** | 服务器错误。服务器在处理请求的过程中发生了错误 |
五、HTTP1.0, 1.1, 2.0的区别
版本 | 变化 |
---|---|
HTTP/0.9 | 仅支持GET请求,不支持请求头, 只能传输纯文本内容, 典型的无状态连接 |
HTTP/1.0 | 默认短连接(一次请求建议一次TCP连接,请求完就断开),但是增加了keep-alive关键字来由短链接变成长连接,就是请求报文里的字段指定Connection:keep-alive;支持GET、POST、 HEAD请求。 |
HTTP/1.1 | 默认长连接(一次TCP连接可以多次请求),同时也可以用请求报文Connection:close来把长连接变成短连接;新增了5种请求类型;请求头部增加了Host字段,在HTTP1.0中认为每台服务器都绑定一个唯一的ip地址,因此在URL中并没有传递主机名,但是随着虚拟机技术的发展,可能在一台物理机器上存在多个虚拟主机,并且他们共享了一个ip地址,http1.1中请求消息和响应消息都支持host头域;增加了100在内的一些状态响应码。 |
HTTP/2 | 多路复用,降低开销(一次TCP连接可以处理多个请求), 一个连接里面并发处理请求,不像http1.1在一个tcp连接中各个请求是串行的;解析基于二进制,解析错误少,更高效(HTTP/1.X解析基于文本);在1.0版本后增加了header头信息,2.0版本通过算法把header进行了压缩这样数据体积就更小,在网络上传输就更快。 |
其中,1.0和1.1最常用,0.9几乎不用(旧),2.0比较少用(更新代价大)
六、HTTP和HTTPS的区别
回到前面那张图:
前面说过,当http承载于TLS、SSL之上的时候,就变成https,那么到底有哪些区别,SSL又是干嘛的?
定义:(Hypertext Transfer Protocol Secure:超文本传输安全协议)
HTTPS协议可以理解为HTTP协议的升级,就是在HTTP的基础上增加了数据加密。在数据进行传输之前,对数据进行加密,然后再发送到服务器。这样,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。就算数据被第三者所截获,但是由于数据是加密的,所以你的个人信息让然是安全的。
TLS是传输层加密协议,前身是SSL协议,由网景公司1995年发布,有时候两者不区分。
SSL(Secure Socket Layer安全套接层)是基于HTTPS下的一个协议加密层,属于应用层和运输层之间,保障TCP-based的这些应用层协议的安全,所以不是http专用的。
TSL(Transport Layer Security 安全传输层协议)就是ssl的版本更新到后期换了一个名字。
所以对比两个协议的区别就是:
HTTP | HTTPS |
---|---|
明文传输,数据未加密,安全性较差 | 数据传输过程是加密的,安全性较好 |
不需要CA | 需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,要钱 |
三次握手,简单,速度快 | 除了 TCP 的三个包,还要加上 ssl 握手需要的很多个包,速度慢,更耗资源 |
有了加密机制之后,输入url到显示内容的过程就更加复杂了,因为传输数据的过程还加上了加密的过程,不是简单的请求、响应这么几个来回。
七、HTTPS的通信过程
首先,我们回顾http的通信过程,从发起一个请求,到传输数据,到最后断开连接。由于http是基于tcp协议,先建立连接,然后开始传输数据,大概过程可以分为如下步骤:
- http客户端(浏览器)与web服务器的http端口建立连接,这个过程是基于tcp的三次握手,完成后连接建立成功;
- 客户端发request报文,就包括前面说过的请求头、请求行、请求体、数据;
- 服务端回复response报文,同样包括状态行,消息头、响应体。
- 服务端主动发起四次挥手(tcp),结束连接。(这是一般情况下,如果说http报文指定了connection:keepalive之类的,那就不释放。
而HTTPS通信加了安全套接层,所以在建立了tcp连接之后,首先会进行ssl安全套接层的数据传输,来确定加密的一些东西。
- http客户端(浏览器)与web服务器的http端口建立连接,这个过程是基于tcp的三次握手,完成后连接建立成功(和http的第一步是一样的);
- 客户端以明文传输请求信息,包含版本信息,加密套件候选列表,压缩算法候选列表,随机数,扩展字段等信息;这一步的核心就是,给服务器一个”我支持哪些加密规则“;
- 服务器从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息;
- 客户端收到后,通过CA验证机构校验这个服务端的真伪,如果有问题会提示一个”证书过期“的危险,如果没有问题,那么客户端使用这个公钥进行加密,然后用约定的hash算法计算出随机数,用随机数对消息加密,将消息再发给服务端;
- 服务端用私钥解密,解密客户端的消息,看hash码是不是一致,然后再用密码加密一段握手消息,发给客户端;
- 客户端解密并看hash码是不是一致,如果一致,说明这个完整的验证过程正常了,接下来就可以正常通信了;
- 双方正常通信,和http的2、3步骤一样,不过每一次都要用随机密码并用对称加密算法进行加密再发送、解密再接收;
- 通信结束,和http的4一样。
可以总结一下,整个过程中,最开始基于tcp的连接不变,最后挥手不变。正式通信之前,先进行握手,确定和测试加密的规则,然后数据传输的时候都要经过加密再解密。
更详细的提前握手的过程如下:
- client_hello
- 第一次C -> S 客户端发起请求,以明文传输请求信息,包含版本信息,加密套件候选列表,压缩算法候选列表,随机数,扩展字段等信息,相关信息如下:
- 支持的最高TSL协议版本version,从低到高依次 SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2, 基本不再使用低于 TLSv1 的版本;
- 客户端支持的加密套件 cipher suites 列表, 每个加密套件对应前面 TLS 原理中的四个功能的组合:认证算法 Au (身份验证)、密钥交换算法 KeyExchange(密钥协商)、对称加密算法 Enc (信息加密)和信息摘要 Mac(完整性校验);
- 支持的压缩算法列表,用于后续的信息压缩传输;
- 随机数 ,用于后续的密钥的生成;
- 扩展字段。
- server_hello+server_certificate+sever_hello_done
- 第一次S -> C
- server_hello, 服务端返回协商的信息结果,包括选择使用的协议版本 version,选择的加密套件,选择的压缩算法、随机数等,其中随机数用于后续的密钥协商;
- server_certificates, 服务器端配置对应的证书链,用于身份验证与密钥交换;
- server_hello_done,通知客户端 server_hello 信息发送结束;
- 证书校验
- 客户端验证证书的合法性,如果验证通过才会进行后续通信,否则根据错误情况不同做出提示和操作
- client_key_exchange+change_cipher_spec+encrypted_handshake_message
- 第二次C -> S
- client_key_exchange,合法性验证通过之后,客户端计算产生随机数字并用证书公钥加密,发送给服务器。此时客户端已经获取全部的计算协商密钥需要的信息:两个明文随机数与自己计算产生的加密随机数字计算得到协商密钥。
- change_cipher_spec,客户端通知服务器后续的通信都采用协商的通信密钥和加密算法进行加密通信;
- encrypted_handshake_message,结合之前所有通信参数的 hash 值与其它相关信息生成一段数据,采用协商密钥与算法进行加密,然后发送给服务器用于数据与握手验证;
- change_cipher_spec+encrypted_handshake_message
- 第二次S -> C
- 服务器用私钥解密加密的数据,基于之前交换的两个明文随机数,计算得到协商密钥,计算之前所有接收信息的 hash 值,然后解密客户端发送的encrypted_handshake_message,验证数据和密钥正确性;
- change_cipher_spec, 验证通过之后,服务器同样发送 change_cipher_spec 以告知客户端后续的通信都采用协商的密钥与算法进行加密通信;
- encrypted_handshake_message, 服务器也结合所有当前的通信参数信息生成一段数据并采用协商密钥与算法加密并发送到客户端;
- 握手结束
- 客户端计算所有接收信息的 hash 值,并采用协商密钥解密 encrypted_handshake_message,验证服务器发送的数据和密钥,验证通过则握手完成;
- 加密通信
开始使用协商密钥与算法进行加密通信。
(Ref:https://www.cnblogs.com/fengting0913/p/13291326.html )
有些东西太详细,记起来也不容易,后来看到了一篇讲的更简单的过程:
- 客户端(通常是浏览器)先向服务器发出加密通信的请求,叫ClientHello请求;
(1) 支持的协议版本,比如TLS 1.0版。
(2) 一个随机数A,稍后用于生成"对话密钥"。
(3) 支持的加密方法,比如RSA公钥加密。
(4) 支持的压缩方法。 - 服务器回应(SeverHello)
(1) 确认加密通信协议版本,比如TLS 1.0版本。
(2) 一个随机数B,稍后用于生成"对话密钥"。
(3) 确认使用的加密方法,比如RSA公钥加密。
(4) 服务器证书。 - 客户端收到服务器回应以后,首先验证服务器证书。
如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。如果证书没有问题,客户端就会从证书中取出服务器的公钥,然后进行 4 。 - 客户端回应
(1) 一个随机数C。该随机数用服务器公钥加密,防止被窃听。
(2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
(3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。(1)的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数ABC,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。 - 服务器的最后回应
(1)编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。
至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
八、对称加密和非对称加密的区别
上面提到了对称加密和非对称加密:
在对称加密算法中,加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥要做好保密,只能让使用的人知道,不能对外公开。
在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。前面所说的https的公钥密码体制就是一种非对称加密算法,他的公钥和是私钥是不能相同的,也就是说加密使用的密钥和解密使用的密钥不同,因此它是一个非对称加密算法。( RSA就是一种公钥密码体制,现在使用得很广泛。)
九、cookie和session
既然http是无状态的协议,前面也说了,需要他有状态。引出了cookie和session,二者的区别是什么?
1.cookie:Cookie就是由服务器发给客户端的特殊信息,存放在客户端,客户端每次向服务器发送请求的时候都会带上这些特殊的信息。这些信息并不是存放在HTTP响应体中的,而是存放于HTTP响应头。
2.Session:是通过服务器来保持状态的。在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建,创建的同时,服务器会为该Session生成唯一的id,而这个id在随后的请求中会被用来重新获得已经创建的Session,在Session被创建之后,可以在其中增加内容,而这些内容只会保存在服务器中,发到客户端的只有id;当客户端再次发送请求的时候,会将这个id带上,显然id是在cookie里的,服务器根据id找到相应的Session。
区别:
session保存在服务器,cookie保存在客户端;
session中保存的时对象,cookie保存的是字符串;
session不能区分路径,同一个用户访问一个网站期间,所有的session在任何一个地方都可以访问,cookie如果设置路径,则在某些地方不能访问;
session需要借助cookie才能正常工作,如果禁用cookie,session则失效;
客户端会在发送请求的时候,自动将本地存活的cookie封装在信息头发送给服务器。
应用场景:
重要状态走session,不重要走cookie,登陆信息用session,购物车用cookie