HTTP协议

目录

关于HTTP

理解HTTP协议工作过程

HTTP协议格式

HTTP请求

认识URL

认识方法(method)

认识请求报头(header)

认识请求正文

HTTP响应

状态码

响应报头

响应正文

构造HTTP请求

通过form表单构造HTTP请求

通过ajax构造HTTP请求

通过Java socket构造HTTP请求

HTTPS

HTTPS工作过程

HTTPS和HTTP的区别


关于HTTP

HTTP (全称为 "超文本传输协议") 是一种应用非常广泛的 应用层协议.

理解HTTP协议工作过程

网络通信中,主要涉及几个核心概念

1.服务器vs客户端

2.请求vs响应

服务器和客户端之间存在多种模型

1.一发一收(web中最常见)

        http协议就是这种传输模型

2.多发一收(多个请求对应一个响应)

        比如上传大文件

3.一发多收

        比如看直播

4.多发多收

        比如串流

HTTP协议格式

使用抓包工具Fiddler

抓包工具的原理

对于抓包工具Fiddler来说,相当于是一个代理

传输数据过程中,服务器会以为他是客户端,客户端会以为他是服务器,进行HTTP通信的详细信息,都会被fiddler获取到。

对于客户端来说,是正向代理

HTTP协议格式

(1)HTTP请求

1.首行 first line

2.首部(请求头) header

header就是一堆键值对,键值对和键值对之间用换行分割,键和值之间用冒号加空格来分割

3.空行

通过空行表示header部分结束了

4.正文body

有的请求有正文,有的没有

(2)HTTP响应

1.首行 first line

2.首部(协议头) header

也是一堆键值对,键值对和键值对之间用换行分割,键和值之间用冒号加空格来分割

3.空行

通过空行表示header部分结束了

4.正文body

有的请求有正文,有的没有

HTTP请求

认识URL

URL基本格式

URL中所有部分都可以省略

1.协议方案名

        有HTTP,HTTPS,FTP

2.登录信息

        现在基本见不到了,现在的登录都是登陆页面

3.服务器地址

        域名(本质是ip地址),也可以是ip地址

4.服务器端口号

        地址后的冒号+数字表示要访问的服务器的端口,如果不写就是默认

        HTTP:80

        HTTPS:443

5.带层次的文件路径

        表示访问服务器上的具体的哪个的资源

6.查询字符串

        URL中的参数,也叫查询字符串(query string)

        这些参数以键值对来组织,键值对之间使用&分割,键和值之间使用=分割

        整体使用?来作为起始标志

        这些键值对表达的意思是程序员自己约定的

7.片段标识符

        不常见,表示定位HTML页面的一个具体位置,常见于文档类网站

关于URLencode

URL中用户自定义的query string中,可能存在一些特殊符号

:    /    ?    =    &    .

这些需要进行转义,就是把特殊字符里面的值,按照十六进制来表示,每个字节在前面放一个%

如 ? 转义为 %3F

认识方法(method)

GET方法

常用于获取服务器上的某个资源.

在浏览器中直接输入 URL, 此时浏览器就会发送出一个 GET 请求.

另外, HTML 中的 link, img, script 等标签, 也会触发 GET 请求

GET请求的特点

1.首行的第一部分为 GET

2.URL的query string一般不为空

3.header 部分有若干个键值对结构.

4.body 部分通常为空.

POST方法

多用于提交用户输入的数据给服务器(例如登陆页面).

通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求.

POST请求的特点

1.首行的第一部分为 POST

2.URL的query string一般为空

3.header 部分有若干个键值对结构.

4.body 部分通常不为空.

GET和POST的区别?

首先没有本质区别

1.数据位置

        GET把自定义数据放到query string,POST把自定义数据到body

2.语义区别

        GET一般用于获取数据,POST一般用于提交数据

3.幂等性

        GET请求一般会设计成幂等(某个请求,执行一次和执行多次,没啥区别,取决于程序员的设计),POST一般不要求设计成幂等

4.可缓存

        GET请求一般会被缓存,POST请求一般不能被缓存

GET的长度限制是多少?

        RFC标准中没有描述URL的长度,也没有描述body的长度,更何况GET中可以有body,POST也可以有URL

其他方法

PUT,一般用于更新

DELETE,删除服务器特定资源

OPTIONS,返回服务器所支持的请求方法

HEAD,类似于GET,不过只返回响应头,不返回响应体

TRACE,主要用于测试

CONNECT,让服务器代理用户进行访问

认识请求报头(header)

Host

        描述了主机的地址/端口号

Content-Length

        表示body的长度,单位是字节

Content-Type

        表示body中数据格式的类型

User-Agent

        描述了浏览器+系统的版本信息

Referer

        表示这个页面是从哪个页面跳转过来的

Cookie

        Cookie的值是一个字符串,相当于浏览器的本地存储的一种机制

一般用来保存用户的身份信息

认识请求正文

正文中的内容格式和 header 中的 Content-Type 密切相关.

1.application/x-www-form-urlencoded

        图片是一个二进制的数据,HTTP协议是文本协议,不能直接传输二进制数据。

此处看到的图片数据,是针对图片内容进行了base64编码(把二进制数据转换成文本数据)

2.multipart/form-data

        主要是用来上传文件

3.application/json

        json是一种非常常用的数据组织的格式

比如登录

HTTP响应

状态码

200 OK

        表示访问成功

404 Not Found

        每次请求带有一个URL,URL里面有路径,表示这次请求想要的资源是啥

        如果请求的资源服务器没有,那就404

403 Forbidden

        访问被拒绝,一般是因为没有权限,比如密码错误

405 Method Not Allowed

        HTTP 所支持的方法, 有 GET, POST, PUT, DELETE 等.

        但是对方的服务器不一定都支持所有的方法(或者不允许用户使用一些其他的方法).

500 Internal Server Error

        表示服务器挂了,一般都是服务器代码执行时崩溃

504 Gateway Timeout

        当服务器负载比较大的时候, 服务器处理单条请求的时候消耗的时间就会很长, 就可能会导致出现超时的情况

302 Move temporarily

        先来理解重定向

        类似于“呼叫转移”,在登陆页面中经常会见到 302. 用于实现登陆成功后自动跳转到主页.

301 Moved Permanently

        永久重定向. 当浏览器收到这种响应时, 后续的请求都会被自动改成新的地址

状态码小结

响应报头

响应报头的基本格式和请求报头的格式基本一致.

Content-Type

text/html : body 数据格式是 HTML

text/css : body 数据格式是 CSS

application/javascript : body 数据格式是 JavaScript

application/json : body 数据格式是 JSON

响应正文

正文的具体格式取决于 Content-Type. 观察上面几个抓包结果中的响应部分.

1.text/html

2.text/css

3.application/javascript

4.application/json

构造HTTP请求

如何构造HTTP请求

1.直接在浏览器输入URL(GET)

2.使用form表单(GET和POST)

3.使用ajax(各种请求)

4.socket构造

通过form表单构造HTTP请求

form发送GET请求

<form action="http://abcdef.com/myPath" method="GET">
    <input type="text" name="userId">
    <input type="text" name="classId">
    <input type="submit" value="提交">
</form>

form发送POST请求

<form action="http://abcdef.com/myPath" method="GET">
    <input type="text" name="userId">
    <input type="text" name="classId">
    <input type="submit" value="提交">
</form>

通过ajax构造HTTP请求

当浏览器在发送请求的过程中,同时也是在进行其他工作的异步,当响应回来了之后,浏览器才处理刚才请求的响应

发送GET或者POST请求

// 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();

这个方法实在是太麻烦了,所以我们建议使用封装ajax方法

封装ajax方法

https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        $.ajax({
            type: 'GET',
            url: 'http://42.192.83.143:8089/AjaxMockServer/info',
            success: function(data,status){
                console.log(status);
                console.log(data);
            }
        });
    </script>
</body>
</html>

效果

ajax中的跨域问题

ajax为了保证安全性,要求发起ajax请求的页面,和接受ajax请求的服务器,应该是在同一个域名下

如果请求发起的页面和接收请求的服务器不在同一域名,就认为是一次跨域请求

也就是说ajax默认是不允许跨域访问的,在响应中,要加上这几个header,才可以允许请求跨域

// 配置跨域
private void setAccess(HttpServletResponse resp) {
    resp.setHeader("Access-Control-Allow-Origin", "*");
    resp.setHeader("Access-Control-Allow-Headers", "*");
    resp.setHeader("Access-Control-Allow-Methods", "*");
}

通过Java socket构造HTTP请求

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class HttpClient {
    private Socket socket;
    private String ip;
    private int port;
    public HttpClient(String ip, int port) throws IOException {
        this.ip = ip;
        this.port = port;
        socket = new Socket(ip, port);
    }
    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 是一个字节流,以字节为单位进行写入,因此需要把 StringBuilder 转换成 byte[]
        outputStream.write(request.toString().getBytes());
        // 读取响应数据
        InputStream inputStream = socket.getInputStream();
        // 创建一个 1M 大小的缓冲区,用来存放响应数据
        byte[] buffer = new byte[1024 * 1024];
        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-Length: " + body.getBytes().length + "\n");
        request.append("Content-Type: text/plain\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", 8089);
        String getResp = httpClient.get("/AjaxMockServer/info");
        System.out.println(getResp);
        String postResp = httpClient.post("/AjaxMockServer/info", "this is body");
        System.out.println(postResp);
    }
}

效果

HTTPS

HTTPS是什么

HTTP是一个明文传输协议,一旦传输过程中,数据被第三方获取到了,可能会造成一些重要信息的泄露

HTTPS就是在HTTP的基础上,引入了一个加密层(SSL/TLS)

加密是什么

明文:真正要传输的消息

密文:指的就是加密之后的消息

明文=>密文 称为加密

密文=>明文 称为解密

HTTPS工作过程

引入对称加密

加密:明文=>密文 使用同一个密钥

解密:密文=>明文 使用同一个密钥

客户端和服务器需要先约定好密钥是啥,但是密钥如果明文传输,也容易被黑客获取,因此密钥的传输也必须加密传输,这就行不通了,所以引入了非对称加密

引入非对称加密

加密:明文=>密文 使用密钥1

解密:密文=>明文 使用密钥2

通常会把其中一个密钥公开出去,别人就可以使用这个密钥加密,自己再用另一个密钥进行解密。

公开出去的密钥成为公钥

自己保留的密钥成为私钥

对称加密,成本是比较低(机器消耗资源小),速度也是很快的

非对称加密,成本比对称加密高很多(机器消耗资源多),速度也慢

引入证书

但是,如何保证客户端获取到的公钥是真实的,而不是黑客伪造的?

接下来客户端拿着pub2进行加密

所以要引入证书

客户端与服务器连接的时候,客户端直接索要一个证书,公钥就包含在这个证书里面,这个证书不是服务器自己生成的,是第三方机构颁发的,客户端拿到证书后,就可以根据证书中提供的信息(类似于营业执照上的编号),和第三方机构认证(类似于在工商局查营业执照是否合法),来校验证书是否合法,如果合法,就可以信任其中的公钥

完整流程

1.客户端先从服务器获取到证书,证书中包含了公钥

2.客户端对证书进行校验

3.客户端生成了一个对称密钥,使用公钥对对称密钥进行加密,发送给服务器

4.服务器得到这个请求之后,使用私钥解密,得到对称密钥

5.客户端发出后续的请求,后续的请求都是使用这个对称密钥加密的

6.收到的数据也都是使用这个对称密钥解密的

这个过程其实描述的就是SSL/TLS的握手过程

HTTPS和HTTP的区别

1.HTTP协议以明文的方式发送内容,数据都是未加密的,安全性较差,HTTPS数据传输过程是加密的,安全性较好

2.HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80端口,后者是443端口

3.HTTPS协议需要申请证书,要花钱的

4.HTTP页面响应比HTTPS快,主要因为HTTPS还要经历一个SSL协商的过程

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值