去评论
海欣资源

HTTP协议 和 HTTPS-介绍及区别

xx5678
2022/05/05 14:52:13
1. HTTP 协议介绍
1.1 HTTP 是什么
HTTP (HyperText Transfer Protocol, 超文本传输协议) 是一种应用非常广泛的 应用层协议.
    所谓 “超文本” 的含义, 就是传输的内容不仅仅是文本(比如 html, css 这个就是文本), 还可以是一些
    其他的资源, 比如图片, 视频, 音频等二进制的数据
1.2 抓包工具的使用
1. Fiddler 的下载
① 可以直接在官网下载 Fiddler官网地址
② 也可以直接进入 fiddler搜索页

2. Fiddler 基本的设置
① 首先设置 点击 Tools -> Options


② 点击 HTTPS 将下面能勾选的勾上


3. Fillder 的使用
将左边的内容清空,然后再进入一个网站,找到对应的那个


按照图片的顺序进行点击,右上就是请求,右下就是响应


1.3 观察一个抓包结果
HTTP 请求



2. HTTP 协议的报文格式
2.1 请求报文格式
首行: [方法] [URL] [版本]
Header: 请求的属性.
空行
Body: 空行后面的内容为 Body.
2.2 响应报文格式
首行: [版本号] [状态码] [状态码的解释]
Header: 请求的属性.
空行
Body: 空行后面的内容为 Body.
2.3 报文格式的注意事项
    首行的内容之间有一个空格.


请求的属性是使用冒号分割的键值对.
每组属性之间使用\n分割
遇到空行表示Header部分结束
Body 允许为空.
如果Body存在,Header中会有一个Content-Length属性来标识Body的长度
协议格式总结


3. 认识 URL
3.1 URL 基本格式


3.2 分析一个具体的 URL:
https://dict.youdao.com/result?word=1&lang=en
        https: 协议方案名.
        user:pass: 登录信息. 目前一般会省略
        dict.youdao.com: 服务器地址. 此处是一个 “域名”, 域名会通过 DNS 系统解析成一个具体的 IP 地址
        端口号: 目前一般会省略. http协议默认使用 80 端口. https协议默认使用 443 端口
        /result 带层次的文件路径
        word=1&lang=en: 查询字符串(query string). 本质是一个键值对结构,键值对之间使用&分割,键和值之间使用=分割
        片段标识: 此 URL 中省略了片段标识. 片段标识主要用于页面内跳转.
3.3 URL 中的可省略部分
        协议名: 可以省略, 省略后 默认为 http://
        ip 地址 / 域名: 在 HTML 中可以省略(比如 img, link, script, a 标签的 src 或者 href 属性). 省略后表示服务器的 ip / 域名与当前 HTML 所属的 ip / 域名一致.
        端口号: 可以省略. 省略后如果是 http 协议, 端口号自动设为 80; 如果是 https 协议, 端口号自动设为 443.
        带层次的文件路径: 可以省略. 省略后相当于 / . 有些服务器会在发现 / 路径的时候自动问/index.html
        查询字符串: 可以省略
        片段标识: 可以省略
3.4 关于 URL encode 和 URL decode
像 / ? : = & 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现
把特殊字符,转换成转义字符 => URL encode
把转义字符,还原成原来的字符 => URL decode


4. HTTP 请求(Request)
4.1 HTTP 方法


4.1 GET 方法
① 构造 HTTP GET 请求的情况
    直接在浏览器中输入 URL
    HTML 中的 link,img,a,script 标签等
    form 表单
    ajax
    使用 java代码/其他的库
    通过 linux 下的 wget / curl
    通过第三方工具,postman 这类工具
② 使用 Fiddler 观察 GET请求
在浏览器中输入sogou.com


GET 请求的特点
    首行的第一部分为 GET
    URL 的 query string 可以为空, 也可以不为空.
    header 部分有若干个键值对结构.
    body 部分为空.(可以不为空)
    关于 GET 请求的 URL 长度问题
    HTTP 协议由 RFC 2616 标准定义.没有对 URL 的长度有任何的限制
4.2 POST 方法
① 构造 HTTP POST 请求的情况
    form表单
    ajax
    第三方工具
② 使用 Fiddler 观察 POST 请求


POST 请求的特点
    首行的第一部分为 POST
    URL 的 query string 一般为空 (也可以不为空)
    header 部分有若干个键值对结构.
    body 部分一般不为空. body 内的数据格式通过 header 中的 Content-Type 指定. body 的长度由header 中的 Content-Length 指定.
4.3 面试题: 谈谈 GET 和 POST 的区别
GET 和 POST 之间没有本质的区别
    数据位置: GET 把自定义数据放到 query string, POST 把自定义数据放到 body
    语义区别: GET 一般用于"获取数据",POST 一般用于提交数据
    幂等性: GET 请求一般会设计成"幂等". POST 请求一般不要求设计成"幂等"(如果多次请求得到的结果一样, 就视为请求是幂等的)
    可缓存: GET 请求一般会被缓存 POST 请求一般不能被缓存
4.4 其他相关方法
    PUT 与 POST 相似,只是具有幂等特性,一般用于更新
    DELETE 删除服务器指定资源
    OPTIONS 返回服务器所支持的请求方法
    HEAD 类似于GET,只不过响应体不返回,只返回响应头
    TRACE 回显服务器端收到的请求,测试的时候会用到这个
    CONNECT 预留,暂无使用
这些方法都可以使用ajax来构造.(也可以通过第三方工具).
4.2 认识请求报头 (header)
header 的整体的格式也是 “键值对” 结构
每个键值对占一行. 键和值之间使用分号分割
① Host
    表示服务器主机的地址和端口
② Content-Length
    表示 body 中的数据长度
③ Content-Type
    表示 body 中的数据格式的类型
1) application/x-www-form-urlencoded
在 form 表单提交的时候会出现的数据格式类型.



2) multipart/form-data:
通常用于提交图片/文件


body的格式

3) application/json


④ User-Agent
字段User-Agent会将创建请求的浏览器和用户代理名称等信息传达给服务器


这里的 Windows NT 10.0;WOW64 表示操作系统的信息
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 表示浏览器信息
⑤ Referer
表示这个页面是从哪个页面跳转过来的.


如果直接在浏览器中输入URL, 或者直接通过收藏夹访问页面时是没有 Referer 的
⑥ Cookie
因为HTTP是无状态的协议,无法根据之前的状态进行本次的请求处理
为了保留无状态协议这个特征,于是引入了 Cookie 信息来控制客户端的状态.
Cookie会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie.当下次再给该服务器发送请求的时候,客户端会自动在请求报文中加入Cookie值后发送出去.
服务器端发现客户端发送来的 Cookie 后,会去检查是哪一个客户端发来的连接请求,对比服务器上的记录,最后得到之前的状态信息.


4.3 认识请求正文 (body)
① application/x-www-form-urlencoded



② multipart/form-data

③ application/json

5. HTTP 响应(Response)
5.1 认识状态码 (status code)


① 200 OK
    这是一个最常见的状态码, 表示访问成功.


② 404 Not Found
    没有找到资源.


③ 403 Forbidden
    表示访问被拒绝. 有的页面通常需要用户具有一定的权限才能访问(登陆后才能访问). 如果用户没有登陆直接访问, 就容易见到 403.



④ 500 Internal Server Error
服务器出现内部错误. 一般是服务器的代码执行过程中遇到了一些特殊情况(服务器异常崩溃)会产生这个
状态码
⑤ 302 Move temporarily
    临时重定向.
    重定向就和呼叫转移一样,
    就是换了个手机号,别人呼叫你旧手机号,会自动转到新手机号上


5.2 认识响应正文 (body)
正文的具体格式取决于 Content-Type.
① text/html
    body中的数据格式是 HTML


② text/css
    body中的数据格式是css
③ application/javascript
    body中的数据格式是javascript
④ application/json
    body中的数据格式是json
6. 构造 HTTP 请求
6.1 通过 form 表单构造 HTTP 请求
① 构造 GET 请求
代码:
    <form action="http://www.baidu.com" method="GET">
        <input type="text" name="user">
        <input type="password" name="password">
        <input type="submit" value="提交">
    </form>


② 构造 POST 请求
    <form action="http://www.baidu.com" method="POST">
        <input type="text" name="user">
        <input type="password" name="password">
        <input type="submit" value="提交">
    </form>
同样的输入 wwww zzzzz 进行抓包


6.2 通过 ajax 构造 HTTP 请求
① 发送 GET 请求
    <script>
        // 1. 创建 XMLHttpRequest 对象
        let httpRequest = new XMLHttpRequest();
        // 2. 默认异步处理响应. 需要挂在处理响应的回调函数.
        httpRequest.onreadystatechange = function () {
            // readState 表示当前的状态.
            // 0: 请求未初始化
            // 1: 服务器连接已建立
            // 2: 请求已接收
            // 3: 请求处理中
            // 4: 请求已完成,且响应已就绪
            if (httpRequest.readyState == 4) {
                // status 属性获取 HTTP 响应状态码
                console.log(httpRequest.status);
                // responseText 属性获取 HTTP 响应 body
                console.log(httpRequest.responseText);
            }
        }
        // 3. 调用 open 方法设置要访问的 url
        httpRequest.open('GET', 'http://42.192.83.143:8080/AjaxMockServer/info');
        // 4. 调用 send 方法发送 http 请求
        httpRequest.send();
    </script>

② 发送 POST 请求

    <script>
        // 1. 创建 XMLHttpRequest 对象
        let httpRequest = new XMLHttpRequest();
        // 2. 默认异步处理响应. 需要挂在处理响应的回调函数.
        httpRequest.onreadystatechange = function () {
            // readState 表示当前的状态.
            // 0: 请求未初始化
            // 1: 服务器连接已建立
            // 2: 请求已接收
            // 3: 请求处理中
            // 4: 请求已完成,且响应已就绪
            if (httpRequest.readyState == 4) {
                // status 属性获取 HTTP 响应状态码
                console.log(httpRequest.status);
                // responseText 属性获取 HTTP 响应 body
                console.log(httpRequest.responseText);
            }
        }
        // 3. 调用 open 方法设置要访问的 url
        httpRequest.open('POST', 'http://42.192.83.143:8080/AjaxMockServer/info');
        // 4. 调用 setRequestHeader 设置请求头
        httpRequest.setRequestHeader('Content-Type', 'application/x-www-formurlencoded');
        // 5. 调用 send 方法发送 http 请求
        httpRequest.send('name=zhangsan&age=18');
    </script>

③ 通过第三方库来封装 ajax

    <script src="https://releases.jquery.com/git/jquery-git.min.js"></script>
    <script>
        $.ajax({
            type: 'GET',
            url:'http://www.baidu.com/index.html',
            success: function(data, status){
                // data 是响应body status 是状态码描述
                console.log(status);
                console.log(data);
            }
        })
    </script>

6.3 通过 Java socket 构造 HTTP 请求

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class HttpClient {
    private Socket socket;
    private String ip;
    private int port;

    public HttpClient(String ip,int port) throws IOException {
        socket = new Socket(ip,port);
        this.port = port;
        this.ip = ip;
    }

    public String get(String url) throws IOException {
        StringBuilder request = new StringBuilder();
        // 构造首行
        request.append("Get " + url + " HTTP/1.1\n");
        // 构造 header
        request.append("Host: " + ip + ":" + port + "\n");
        // 构造空行
        request.append("\n");
        // GET 不需要 body, 构造完毕
        OutputStream outputStream = socket.getOutputStream();
        // outputStream 是一个字节流,以字节为单位进行写入,因此需要把 StringBuilfer 转换乘byte[]
        outputStream.write(request.toString().getBytes());

        // 读取响应
        InputStream inputStream = socket.getInputStream();
        // 1M 大小的缓冲区,用来存放响应数据
        byte[] buffer = new byte[1024 * 1024];
        // n 表示实际上读到的字节数
        int n = inputStream.read(buffer);
        return new String(buffer,0,n,"utf-8");
    }

    public String post(String url,String body) throws IOException {
        StringBuilder request = new StringBuilder();
        // 构造首行
        request.append("POST" + url + "HTTP/1.1\n");
        // 构造header
        request.append("Host: " + ip + ":" + port + "\n");
        request.append("Content-Type: text/plain\n");
        request.append("Content-Length: " + body.getBytes().length + "\n");
        // 构造空行
        request.append("\n");
        // 构造 body
        request.append(body);

        // 发送请求
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(request.toString().getBytes());

        // 读取响应
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024 * 1024];
        int n = inputStream.read(buffer);
        return new String(buffer, 0, n, "utf-8");
    }

    public static void main(String[] args) throws IOException {
        HttpClient httpClient = new HttpClient("42.192.83.143",9090);
        String resp = httpClient.get("/AjaxMockServer/info");
        System.out.println(resp);
//        String resp = httpClient.post("/AjaxMockServer/info","这是正文");
//        System.out.println(resp);
    }
}

7. HTTPS
7.1 什么是 HTTPS
HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层(SSL/TLS).
7.2 为什么引入 HTTPS
因为HTTP是明文传输, 本来要传什么,实际上就传了什么,但是一旦这样传输,在传输的过程中, 被第三方截获到了,就可能造成信息泄露.
于是引入了 HTTPS在HTTP基础上进行了加密,进一步的保护了用户的信息安全.
    明文: 真正要传输的信息
    密文: 加密之后的消息
    加密: 就是把 明文 (要传输的信息)进行一系列变换, 生成 密文 .
    解密: 就是把 密文 再进行一系列变换, 还原成 明文 .
    在这个加密和解密的过程中, 往往需要一个或者多个中间的数据, 辅助进行这个过程, 这样的数据称为 密钥
7.3 HTTP 的工作流程
① 引入对称加密
对称加密其实就是通过同一个 “密钥” , 把明文加密成密文, 并且也能把密文解密成明文.
    例子: 现有 明文: 1111 密钥: 6666 加密解密过程通过: 按位异或
    A 将明文: 1111 通过 密钥: 6666 加密成 密文:2 发送给B
    B 通过密钥: 6666 对密文: 7773 进行解密 得到 明文: 1111
此时同时也引入了一个问题,当客户端把密钥进行明文传输的时候,也可能被别人截获,再次发送密文,别人就可以通过密钥获取到明文,那此时的加密就没什么作用了


解决办法: 对密钥进行加密传输.
② 引入非对称加密
非对称加密要用到两个密钥, 一个叫做 “公钥”, 一个叫做 “私钥”
公钥和私钥是配对的. 最大的缺点就是运算速度非常慢,比对称加密要慢很多
此时也有一个问题,可能在获取的公钥就是假的.


解决办法: 引入证书.
③ 引入证书
在客户端和服务器刚一建立连接的时候, 服务器给客户端返回一个 证书.
这个证书包含了刚才的公钥, 也包含了网站的身份信息


    当客户端获取到这个证书之后, 会对证书进行校验(防止证书是伪造的).
        判定证书的有效期是否过期
        判定证书的发布机构是否受信任(操作系统中已内置的受信任的证书发布机构).
        验证证书是否被篡改: 从系统中拿到该证书发布机构的公钥, 对签名解密, 得到一个 hash 值(称为数据摘要), 设为 hash1. 然后计算整个证书的 hash 值, 设为 hash2. 对比 hash1 和 hash2 是否相等.如果相等, 则说明证书是没有被篡改过的.
7.4 HTTPS 传输过程
    客户端先从服务器那边获取到证书.证书里包含了公钥.
    客户端对整数进行校检.
    客户端生成一个对称密钥,使用公钥对对称密钥进行加密,发送给服务器
    服务器得到这个请求后,使用私钥解密,得到对称密钥.
    客户端发出后续的请求,后续的请求都是使用这个对称密钥加密的.收到的数据也都是使用这个对称密钥解密的.