HTTP-

发布于:2025-02-26 ⋅ 阅读:(21) ⋅ 点赞:(0)

一.HTTP

1.什么是HTTP

HTTP(超文本传输协议)是一种工作在应用层的协议.主要用于网站,就是浏览器和服务器之间的数据传输.

小知识:什么是超文本传输协议

文本:是字符串.(能在utf8/gbk码表上找到合法字符)

超文本:不仅可以传输字符串,也可以传输图片,html等

富文本:word文档

2.HTTP的发展

HTTP在3.0版本之前,都是基于TCP实现的,而在3.0版本之后是基于UDP实现的.提升了传输效率,安全性也提到了明显的改善.而我们当前使用的是HTTP1.1版本.是基于TCP实现的,也是当前使用较多的.

3.HTTP的交互

HTTP的交互是一问一答的形式

而有些场景下,HTTP也是很难胜任的

比如我们用脑袋疼举例,此时就会弹出广告,我们点进去会主动先给你发一条消息

像把QQ这样的聊天窗口搬到网页上来,对方发来消息我们这边还有提示,这种情况HTTP的不能胜任了

上述场景是服务器主动给浏览器发消息,就称为消息推送.

上述是怎么实现的呢?

应用层这里还补充了一个websoket协议,用来给HTTP做补充

4.HTTP的报文格式

首先介绍HTTP的报文格式之前我们要先介绍一下专门用来抓HTTP的数据包的软件--fidder

下载完成之后我们还要对软件进行一些设置

我们需要获取证书,所谓的获取证书就是将fideer的公钥放置在系统内部,这个我们后边再解释.

这里的抓包工具其实就是一种"代理"程序.能够获取网络上的数据并显示出来给我们一些参考

代理分成两种

1.正向代理(客户端的代言人):比如我会求室友帮我带一份饭,此时室友就是我的代理

2.反向代理(服务器的代言人):比如食堂大妈今天也不想动弹,此时会让他的儿子来卖饭,此时他的儿子就是反向代理

而我们所谓的翻墙效果也是这样:有的境外的服务器我们不能直接访问.但是也有一些可以访问的,此时我们就会通过可以访问的服务器来访问不能访问的服务器,达到所谓的翻墙效果

此时按照上述的配置完成操作后,我们就可以进行抓包操作了.

上面蓝色的表示的是返回一个html,表示一个网站的入口请求.

我们可以双击查看明细

我们先看请求:

此时我们需要点击Raw,就可以查看请求的原始数据

接下来看响应:

我们可以发现红框中出现了乱码,这是因为为了减少网络带宽的消耗,对数据进行了压缩,要是想看到响应的正文,我们需要点击

此时我们就可以看到响应的原始数据

通过抓包我们来分析下HTTP请求的报文格式

HTTP请求的报文格式分为4个部分

1.首行

GET https://www.sogou.com/ HTTP/1.1

首行又包括三个部分:

GET:表示方法

https://www.sogou.com/:表示URL

HTTP/1.1:表示的是HTTP的版本号

2.请求头(采用键值对的方式)

此处的请求头的键值对内容都是HTTP协议规定的,具体我们后续介绍

3.空行

请求头结束会有一个空行,就是用来表示请求头结束

4.正文:body(也就是载荷)

有的请求有载荷

有的则没有

HTTP的响应报文格式也分为4个部分

1.首行

HTTP/1.1 200 OK

HTTP/1.1:表示的是HTTP的版本号

200:状态码,后续也会介绍

OK:状态码描述

2.响应头(同样也是键值对)

关于响应头的内容我们后面也会介绍

3.空行(标志着响应头结束)

4.正文body(载荷部分)

这里我们是第一次访问,所以服务器返回了页面的HTML代码.

5.认识URL

URL就是用来描述一个网络资源的位置.

URL的组成:

协议:就是当前使用的是什么协议(HTTP/HTTPS...)

登录信息:现在不常用,因为不安全

IP地址:用域名访问,更方便.通过地址知道服务器是哪个

端口:通过端口知道具体访问服务器的哪个程序

路径:通过路径知道访问的是哪个资源(此处可以是一个文件,也可以是一个虚拟文件)

查找字符串(quary string):针对请求做出的补充

片段标识符:标识当前页面的某个部分,通过不同的标识可以完成页面的跳转

URL就类似上面

6.关于URL encode

在quary string(查找字符串)中有很多程序员自定义的键值对

在URL中很多字符都有特殊的含义:/    :  @等,如果quary string中也有相同的符号怎么办

此时我们就需要转义,当然对于汉字我们也需要转义.

7.请求头中的方法

GET:从服务器获取一个资源(读操作)

POST:往服务器放一个东西(写操作)

上述标准文档只是作者一厢情愿,我们也可以不用遵守

GET的使用场景:GET https://www.sogou.com/ HTTP/1.1

从服务器获取一个数据

POST的使用场景:

常见用于上传,登录

登录:

我们可以看到登录操作使用的是POST方法,登录的用户名使用的是json数据格式组织登录的,密码并不是我们自己设置的密码,而是进行了base64编码,将编码传输到服务器

小知识:

密码后面有  ==  就是base64编码,Base64 是一种将二进制数据编码为 ASCII 字符串的编码方式,常用于在文本协议(如 HTTP、电子邮件)中安全传输二进制内容。

上传:

8.GET和POST的区别(经典面试题)

本质上GET和POST没有区别,使用GET的场景也能用POST,使用POST的场景也能使用GET.

但是在使用习惯上二者还是有区别的:

1.GET习惯把数据放到URL中,POST习惯把数据放到body(载荷)中

同样GET也可以把数据放到body中,但是有的浏览器会有限制

POST也可以放到URL中,大多数是没有限制

2.语义上的区别

标准文档中GET适用于读取数据,POST用于传输数据

3.关于幂等性

标准文档中,建议GET是幂等的,POST无要求

小知识:

幂等性就是每次输入的结果一定,输出的结果也一定,就是幂等

每次输入的内容一定输出的结果不一定,就不是幂等

就像牛吃的是草,挤的是奶,而不是吃的是草挤的是bb.

4.GET可以被浏览器收藏夹收藏,POST不可以

网络上一些关于GET和POST的解释也不是很准确,大家理性看待

1.POST比GET更加安全

依据:GET传输的数据是放在URL中的,而POST存放的数据是放在body中的.

登录场景中,如果密码放到URL中可能会被看到,所以不安全,但是POST也是可以被心怀叵测的人抓包得到body.

辟谣:真正保证安全的,不是使用什么方法,而是对数据进行加密

2.GET传输的数据量很小,POST传输的数据量很大

以前确实是这样的,但是现在标准文档明确指出对GET的URL不做长度的限制

3.GET只能携带文本数据,POST只能携带二进制数据

这个说法不一定完全错,URL是通过quary string来保存数据,quary string是只能包含文本数据的,但是urlencode可以对二进制文件进行编码,自然也就成了文本了

POST请求中也不是经常携带二进制数据,而是对二进制文件进行base654/urlencode进行转码

9.认识"报头" 

1.Host:表示服务器主机的IP地址和端口号

2.Content_Length:表示body(正文)的数据长度,因为HTTP1.1是基于TCP实现的,可能会出现粘包问题(具体粘包问题关注TCP章节),所以用规定数据长度来避免粘包问题

3.Content_Type:表示正文的类型

请求中会有的格式:

(a).application/json --body就是json的数据格式

(b)application/x-www-form-urlencode,通过form表单,特点就是把quary string放到body里了

(c)multipart/form-data;上传文件使用

不拘泥于上述三种格式,程序员自己也可以定义

响应中的格式

(a)text/plain:纯文本

(b)text/html:返回HTML

(c)text/css:返回css

(d)application/Javascript:返回js

(e)application/json:返回json

(f)image/png

(g)image/jpg:最后两个都是返回图片

4.User-Agent(UA):

描述了当前访问的操作系统的信息以及浏览器信息

UA在以前是非常常用的,由于用户的设备存在差异,就可以通过UA区别设备,从而正确返回用户想要的数据

5.Refer

表示当前的页面是由哪个页面跳转而来.

以前HTTPS的并没有得到普及的时候,运营商通过篡改Refer来获取不菲的收益,广告公司看到Refer都是运营商那边投来的流量,自然就把钱分走了.这就是运营商劫持.

6.Cookie:

最重要的属性,Cookie就是持久化的保存一些信息.

关于Cookie的几个结论:

1.Cookie是首次通信,服务器返回给客户端的

2.Cookie会存储到客户端的硬盘上,后续每次访问都会带上Cookie,存储到硬盘就达到了持久化存储.不同的客户端保存的Cookie保存的内容是不同的

3.Cookie中保存的是键值对,是程序员自己定义的,我们无从得知

4.Cookie在硬盘本地保存,是按照不同域名为维度分别存储

5.Cookie最主要的就是保存用户的身份标识,这样数据传输到服务器,服务器就可以区别出用户

10.状态码

在响应中上述的200就是一个状态码.HTTP中的状态码都是约定好的.

接下来我们认识几个常见的状态码:

1.200  OK  表示一切顺利

2.404  NOT FOUND 访问的资源没有找到

3.403  Forbidden 表示请求的资源没有权限访问

4.405 Method Not Allowed  你的服务器只支持GET,但是你发了个POST

5.500 Interal Server Error 服务器内部错误,可能是服务器挂了

6.504 Geteway Timeout 访问服务器超时

7.302 Move temporarily 临时重定向.如果一个网站更换了新的域名,但是老用户并不知道,此时访问原来的域名就可以跳转到新的域名.

8.301 永久重定向.浏览器会把重定向的结果记录下来.后续再访问就会直接访问重定向的目标地址即可,不用跳转

11.如何构造一个HTTP请求

两种方法:使用代码构造

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");
 // 发送数据
 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 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", 8080);
 String getResp = httpClient.get("/AjaxMockServer/info");
 System.out.println(getResp);
 String postResp = httpClient.post("/AjaxMockServer/info", "this is body"
 System.out.println(postResp);
 }
}

2.使用第三方工具(postman)

关于HTTP我们就介绍这里