HTTP
文章目录
1.HTTP协议是什么
-
HTTP——应用层协议,描述业务,非OS代码,基于TCP,超文本传输协议(Hyper Text Transmission Protocal)
首先,应用层协议?:
应用层主要用于 处理业务逻辑,不再考虑数据传输通信问题,而是对数据的加工处理或者使用规则的制定。即相当于一堆零件快递(TCP/IP数据跨网传输)到家了,但是还需要按照说明方法(应用层协议)将零件组装拼接成可使用的物体
其次,基于TCP?:
其实,HTTP/1.0 1.1版本(基于TCP),但后来的HTTP/3.0版本(引入UDP,既可基于TCP,也可基于UDP)
不过,目前主要使用的还是1.1,2.0版本,所以,我们下面的内容以1.1版本为例,暂不考虑基于UDP的
最后,超文本?:
超文本就是就是传输的内容不仅仅是文本(比如 text,html, css 这个就是文本), 还可以是一些其他的资源, 比如图片, 视频, 音频等二进制的数据.
-
HTTP协议是文本协议(不像之前的TCP那些,报头是二进制啦,而HTTP直接就是文本,所以,方便人查看,但是对程序而言还要解读是性能差的)
-
平时,我们打开一个网站,应用的就是http(或者https)协议
当我们在浏览器中输入一个 “网址”, 此时浏览器就会给对应的服务器发送一个 HTTP 请求. 对方服务器收到这个请求之后, 经过计算处理, 就会返回一个 HTTP 响应.
客户端——浏览器进程
服务端——Web服务器进程
-
HTTP以资源为基本单位,一次请求响应就是请求一个Web资源然后响应回来一个Web资源内容内容
所以,经常,打开一个网页,实际上涉及不止一次请求与响应
2.HTTP协议格式:
2.1请求包含信息
(1)哪种操作——Post、Get、delete等
浏览器输入url地址——Get请求
(2)请求的哪个资源
请求的是哪个资源——>统一规范资源名称,统一资源标识符URI,实际中,应用的是统一资源定位符URL(其实就是我们通常说的网址)(URL属于URI)
(3)关于本次请求的元信息
(4)可能存在的内容部分
URL具体格式:
protocol——本次资源对应的协议(不一定全部是HTTP协议,所以需要标识一下是哪个协议)
域名或IP——主机host(资源在哪台主机上)
端口——资源在这个主机的哪个进程上获取
资源路径——具体定位到是哪个资源
其他特殊要求(查询字符串(?name=‘aaa’&password=123)、文档片段(#……))
可以省略的:
协议可省略:省略后等同于请求的协议
主机也可以省略:省略后也等同于请求的主机
端口可省略:省略后是协议默认端口号,如http协议默认80端口,https协议默认443端口
查询字符串和文档片段也可以省略
文件路径是index系列也可以省略,比如我们日常登百度,就把index.html省略了
2.2响应包含信息
(1)请求结果(成功了失败了还是咋)——状态码,状态码解释
200——成功
301——永久重定向
302——临时重定向
403——表示访问被拒绝,一般是用户权限不够
404——请求的资源路径不存在
405——请求的资源不支持该方法
500——内部服务器错误,如服务器异常崩溃
504——超时,当服务器负载比较大的时候, 服务器处理单条请求的时候消耗的时间就会很长,比如双十一秒杀场景
(2)本次响应的元信息
(3)本次资源的内容
2.3请求响应格式
(1)如下,是一个HTTP请求的抓包结果:
可以得到,请求格式为:
请求行+请求头们+【请求体】
请求行=请求方法+URL(一般省略为路径)+协议版本
请求头:请求的属性, key:value的形式,每组属性之间使用\n分隔;遇到空行表示Header部分结束
请求体:请求的内容,无格式要求,没有可省略,如果存在, 则在Header中会有一个Content-Length属性来标识Body的长度;
(2)如下,是一个HTTP响应的抓包结果:
可以得到,响应格式为:
响应行+响应头们+响应体
响应行:版本号+状态码+状态解释
响应头们:请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束Body: 空行后面的内容都是Body.
响应体:允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中.
空行存在的意义?
空行表示Header的结束,是一个分界线,因为HTTP基于TCP,面向字节流,如果没有空行,会出现粘包问题
2.4模拟发送请求打印响应结果
import java.io.*;
import java.net.Socket;
public class HTTPClient {
public static void main(String[] args) throws IOException {
// 1. HTTP 客户端,要发送 HTTP 请求,先建立 TCP 连接
Socket socket = new Socket("www.baidu.com", 80);
OutputStream os = socket.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
// 请求格式:方法为post,URL地址,版本1.0,其他请求头,请求体没有我就省略
String request = "GET / HTTP/1.0\r\n\r\n";
writer.print(request);
writer.flush();
// 读取百度返回的 HTTP 响应
InputStream is = socket.getInputStream();
byte[] buf = new byte[10240]; // 我们知道响应不会超过 1024 字节的
int n = is.read(buf);
String response = new String(buf, 0, n, "UTF-8");
System.out.println(response);
}
}
打印结果:(没打印完)
2.5请求响应头中的Content
(1)Content-Type——body内容格式
可以是html,js,json,图片等
- html——Content-Type:text/html;charset=utf-8
- css——Content-Type:text/css
- JavaScript——Content-Type:application/javascript或者Content-Type:text/javascript
- 纯文本——Content-Type:text/plain
- 图片——Content-Type:image/png
- Json——Content-Type:text/json或者Content-Type:application/json
(2)Content-Length——请求体或者响应体的长度
【TCP是面向字节流的,需要考虑解包信息,所以我们可以看到,请求行和请求头之间用\r\n换行分割,请求头和请求体之间则是用Content-Length标识长度来分界】
2.6模拟响应服务器
实现服务器这端
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class HTTPServer {
public static void main(String[] args) throws IOException {
// 我们使用短连接
ServerSocket serverSocket = new ServerSocket(80);
while (true) {
try {
Socket socket = serverSocket.accept();
// 不管对方发给我们的 请求 是什么,一律使用统一的响应回复对方
OutputStream os = socket.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
String html = "<a href='https://www.baidu.com/'>百度一下</a>"; // 我们的响应体
byte[] bytes = html.getBytes("UTF-8");
int contentLength = bytes.length;
// Content-Type: application/octet-stream以二进制文件夹的形式
String response = "HTTP/1.0 200 OK\r\n" +
"Content-Type: text/html; charset=utf-8\r\n" +
"Content-Length: 49\r\n" +
"\r\n" +
html;
writer.print(response);
writer.flush();
socket.close();
} catch (IOException exc) {
exc.printStackTrace();
}
}
}
}
运行这段代码,相当于我们主机的80端口会提供响应,所以我们在浏览器那里输入URL请求:http://localhost:80
会弹出我们的响应内容:
同样,对于我们刚刚写的客户端代码,只需改为本地主机[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
即可得到响应:
3.HTTP优缺点
3.1 优点
-
简单、灵活、易扩展
(HTTP协议比较简单,且是文本协议,便于查看和理解)
(HTTP协议中的每一个核心组成要素都没有被写死,允许开发者任意定制)
(HTTP并不限定某种编程语言或者操作系统,所以天然跨平台、跨语言)
-
应用广泛
-
无状态——无需额外的资源记录状态信息,减轻服务器负担,能够把更多的CPU和内存用于对外提供服务
无状态就相当于没有记忆功能,就是默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系. 就是我可以会话,但不知道在和谁会话
(无状态既是优点也是缺点)
3.2 缺点
- 无状态——每次都得问一次身份信息,不仅麻烦,而且增加了不必要的数据传输量;无法支持需要连续多个步骤的事务操作——》由此出现了Cookie技术
- 明文传输不安全
- HTTP性能不算差,但并不完全适应现在的互联网,还有提升空间。比如“队头阻塞”(Head-of-line blocking)问题,因为HTTP使用的是 “请求 - 应答”模式,当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据 ……
HTTPS
HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中极度不安全(试想,进行登录操作时,登录名和密码是明文传输的……)
所以,就有了HTTPS, 是在 HTTP 协议的基础上引入了一个加密层.
这个加密层,目前主要使用两种技术:SSL(安全套接字层)和TLS(传输层安全性)
HTTP + SSL(TLS)= HTTPS
接下来,就让我们来分析一哈究竟是如何加密的
加密原理
-
请求、响应都用密文传输
-
加解密怎么来的呢?我们这里应用 对称加密技术
-
对称加密的密钥哪里来的呢?也需要客户端和服务端协商好,所以,密钥也需要加密传输
-
密钥的加密传输如果也是对称加密技术,那么问题陷入了无限循环,所以,引入非对称加密技术
-
非对称加密——公钥加密,私钥解密[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
-
由于对称加密的效率比非对称加密高很多, 因此只是在开始阶段协商密钥的时候使用非对称加密, 后续的传输仍然使用对称加密.
-
还有最后一个问题,公钥私钥哪里来的?——数字证书
-
客户端与服务器第一次建立连接时,服务器会发给浏览器一个证书,证书里面就包含了有效期,签名,以及公钥等信息
-
客户端收到证书后,会对证书进行校验判断
判定证书的有效期是否过期
判定证书的发布机构是否受信任(操作系统中已内置的受信任的证书发布机构).
验证证书是否被篡改: 从系统中拿到该证书发布机构的公钥, 对签名解密, 得到一个 hash 值(称为数据摘要), 设为 hash1. 然后计算整个证书的 hash 值, 设为 hash2. 对比 hash1 和 hash2 是否相等. 如果相等, 则说明证书是没有被篡改过的.
证书签名验证过程:
常见的生成签名的算法:MD5
MD5特点:
- 定长——无论多长的字符串, 计算出来的 MD5 值都是固定长度 (16字节版本或者32字节版本)
- 分散——源字符串只要改变一点点, 最终得到的 MD5 值都会差别很大
- 不可逆——通过源字符串生成 MD5 很容易, 但是通过 MD5 还原成原串理论上是不可能的
总结:
(1)服务器端申请证书,获得CA机构的私钥1,同时,客户端系统内置了CA机构的公钥1
(2)当客户端和服务器端第一次建立连接时,服务器端生成一对非对称密钥(公钥2,私钥2),同时会给客户端发一个证书,证书里面包含了公钥2,这个证书使用CA机构的私钥1加密传输
(3)客户端收到证书后,用CA机构的公钥1进行解密,解密得到证书中的数字签名,通过数字签名验证证书合法性
(4)验证通过,得到证书中包含的公钥2
(5)客户端生成对称密钥3,将这个密钥用公钥2加密传输给服务端
(6)服务端收到后,用私钥2解密,得到对称密钥
(7)至此,服务器端与客户端协商好了对称密钥,并都知晓
(8)然后,双方用对称密钥进行加解密传输数据
一共用到了三组密钥:
-
第一组(非对称加密): 用于校验证书是否被篡改. 服务器持有私钥(私钥在注册证书时获得), 客户端持有公钥(操作系统包含了可信任的 CA 认证机构有哪些, 同时持有对应的公钥). ——服务器使用这个私钥对证书的签名进行加密. 客户端通过这个公钥解密获取到证书的签名, 从而校验证书内容是否是篡改过.
-
第二组(非对称加密): 用于协商生成对称加密的密钥. 服务器生成这组 私钥-公钥 对, 然后通过证书把公钥传递给客户端. 然后客户端用这个公钥给生成的对称加密的密钥加密, 传输给服务器, 服务器通过私钥解密获取到对称加密密
-
第三组(对称加密): 客户端和服务器后续传输的数据都通过这个对称密钥加密解密.
第二组非对称加密的密钥是为了让客户端把这个对称密钥传给服务器.
第一组非对称加密的密钥是为了让客户端拿到第二组非对称加密的公钥.