1.HTTP是什么
HTTP的全称为“超文本传输协议”,是一种应用非常广泛的一种应用层协议。
超文本是指传输的内容不仅是文本(比如html,css这些就是文本),还可以是一些其他类型的数据,比如图片,视频,音频等二进制数据。
HTTP协议是一种一问一答的协议,也就是客户端发送一个请求,服务器就返回一个请求。
我们平时打开一个网站,就是通过HTTP协议来传输数据。
比如我们在浏览器输入一个搜狗搜索的”网址”(url)时, 浏览器就会向搜狗服务器发送一个HTTP请求,搜狗的服务器在接收到请求之后,就会向客户端返回一个HTTP响应。
这个响应结果被浏览器解析之后,就会展示成我们所看到的页面。(这个过程中浏览器可能会给服务器发送多个http请求,服务器就会返回多个响应,这些响应里面就包含了HTML,CSS,JavaScript,图片,自提等信息)
2.HTTP协议格式
HTTP是一个文本格式的协议,我们可以通过Fiddler抓包,分析HTTP请求和响应的具体细节。
http请求由首行,请求头,空行和正文这四部分组成,其中有些http请求中有正文,有些http请求没有正文。
如下图
http响应由首行,响应头,空行和正文组成
如下图
3.HTTP请求
1.认识URL
1.URL的基本格式
URL是首行的一部分,平时我们俗称的网址,其实指的就是URL,互联网上每一个文件都有唯一一个URl,URL包含的信息指出了文件的位置以及浏览器如何处理它。
一个URL由协议名称,登录验证信息,服务器的ip地址或者域名,端口号,带层次的文件路径,查询字符串和片段标识符组成。
如下图
但是现在的URL中,会有一些信息被省略了,以下为一个具体的URL。
jdbc:mysql://127.0.0.1:3306/java113?chatacterEncoding=utf8&useSSL=false
分析上面这个URL
jdbc:mysql为协议名称,也可以是其他类型,比如http和https
上图中的user:pass为登录信息,但是现在的网站进行身份验证一般不再通过URL进行,一般都会省略。
127.0.0.1是一个服务器IP地址,是一个表示本地计算机的一个端口号,该信息表示要访问服务器的IP地址或者域名。但是由于MySQL是集服务器和客户端于一身的数据库,所以对于MySQL来说,本地计算机也可以是服务器,也可以是客户端。有时这里也会表示为域名,域名和IP地址之间可以通过DNS域名解析系统来转换(DNS也是一个应用层协议)
3306表示的是一个端口号。一个端口号对应唯一一个应用层序,所以在URL中,端口号表示的是哪个应用层序要访问服务器。端口号也有省略的时候,当端口号被省略的时候,浏览器就会根据协议类型自动决定使用一个默认端口号,比如http协议中默认使用的端口号为80,https默认使用的端口号为443。
通过IP地址定位到一台主机,同一台主机上有对个程序在使用网络,通过端口号来进一步区分是哪一个应用程序,每个应用层序使用网络的时候都会关联一个空闲的端口号。
/java113是一个带层次的文件路径,其表示要访问的是资源是,某个主机上的某个程序管理的某个资源。
chatacterEncoding=utf8&useSSL=false是查询字符串(Query String),插叙字符串是对要访问资源的补充说明,也是键值对结构,键值对之间用&分开,键和值之间用=分开。
比如上图我们想要在B站访问 知识 这个分类中的信息,当我么点击知识,URL就会补充一些关于知识这个分类里面内容的一些查询字符串。
片段标识符:此处的URL中省略了片段标识符,片段标识符主要用于页面跳转,现在主要用于文档类型的网站。
2. urlencode
在URL中本身就有一些特殊符号,比如:,/,?,#,&,= 等,这些符号在URL中有特殊含义,不能随意出现。
由于query string里面的内容是程序员自定义的,万一query string里面也包含了这些特殊符号,我们是怎么区分该特殊符号是属于URL中特殊的符号还是程序员在query string里面定义的内容呢?
解决方案就是对query string里面的这些特殊字符进行转义。
转义的规则
把需要转义的内容的二进制内容,以字节为单位提取出来,每个字节用16进制表示,接着从右向左,取4位16进制的内容(不足4位直接处理),每两位16进制数据前加%,编码成%XY的格式。
如下图
需要注意的是, 转义操作,不仅仅是针对于标点符号,对于中文其他非英语系的文字也是需要转义的,只不过很多浏览器为了方便,在显示这些文字之前会先转义一遍,所以显示的时候显示转义之前的。如下图
通过抓包,我们就可以看到转义后的数据
3.认识方法
下图是构造http请求时用到的方法
天下的方法有十斗,GET独占八斗,POST独占一斗,剩下的方法公分一斗
接下来,向大家重点介绍GET和POST方法
1.GET方法
GET方法是最常用的http方法,常用于用来获取html,获取css,获取js等操作,在浏览器中输入一个URL,此时浏览器就会发出一个GET请求。另外,HTML中的link,img,script等标签也会触发GET请求。后面我们也会学习使用JavaScript的ajax构造GET请求。
使用Fiddler抓包,访问搜狗主页,观察抓包结果
此时,有人可能就抓包就抓取不到html等类似的包,我们需要把鼠标放在刷新标志上,按Ctrl+F5刷新一下网页,这与浏览器的缓存机制有关。
浏览器的缓存机制
当我们使用浏览器首次访问一个网页时,所有的资源会先从服务器获取,但是不能每次都从服务器获取资源,如果服务器里的距离很远,如果每次够从服务器获取资源,就会降低网络的传输效率,所以,浏览器为了加快访问页面的速度,就会把页面依赖的一些静态资源(css,js,图片,字体,MP3......)缓存到硬盘上。
按Ctrl+F5 表示强制刷新,忽略本地缓存,所有资源从服务器重新获取。
选中蓝色的那条来观察详细的请求结果
2.POST方法
POST方法有两个典型的应用场景,分别为登录和上传资源。
POST请求是有正文的,正文就是为了保存当前上传的数据的内容。但是上传图片等特殊的的内容时,由于数据本质上是二进制,通过特殊的方式进行转码(base64,把二进制转成文本),但是POST请求中的body也是可以存储二进制数据的。
下图是我登录Gitee抓到的POST请求
3.经典面试题---GET和POST的区别
首先,我们先抛出一个结论,GET和POST没有本质区别,经常能够混着用。
但是我们还是可以从几个方面来介绍一下GET和POST方法的区别
1.语义上的区别:GET一般用于获取数据,POST一般用于提交数据
2.传递参数的区别:GET的body一般为空,传递的参数要通过URL的查询字符串来传输,POST的查询字符串一般为空,传递的参数会放在正文body中。
3.GET请求通常设计成幂等(如果请求一定,多次该请求得到的响应也一定)的,而POST无要求,GET通常被设计成幂等的只是http标准文档给的建议,不是强制要求。
4.GET被设计成幂等的,所以浏览器一般会对GET请求的结果进行缓存,由于POST不要求幂等,经常是不幂等的,通常默认不会被浏览器缓存。
有待商榷的说法
1.POST比GET安全
以登录场景为例,因为如果使用GET,用户名密码就会被放在url的query string中,就会显示在浏览器的地址栏上,这就导致了登录数据的不安全。但是,如果使用POST方法,也只是将用户名和密码放在body中,被人随便转个包也能获取到用户名和密码。所以只要明文传输,都谈不上安全的,保证安全的关键是“加密传输”。
2.GET传输数据有长度限制
长度限制的说法放在上古时期的IE浏览器的年代是对的,因为那时候确实对url的长度有限制,此时如果传输的数据太多,可能就会被截断。但是现在的主流浏览器中,早就没有这样的限制了。另外,在http协议的标准文档中,url和body是明确没有长度限制的。
3.GET只能传输文本数据,POST可以传输二进制数据
GET方法中,url确实只能存放文本数据,但是二进制可以通过base64转成文本的,但是GET也不是不能带body,这样GET也可以存放二进制数据了。
4.其他方法
PUT:与POST相识,只是具有幂等性,一般用于更新
DELETE:删除服务器指定的资源
OPTION:返回服务器所支持的请求方法
HEAD:类似于GET,只不过响应体不返回,只返回响应头
TRACE:回显服务器收到的请求,一般用于测试
CONNECT:预留,暂无使用
2.认识请求“报头”(header)
header的整体格式也是键值对结构,每个键值对占一行,键与值之间用分号划开。接下来,介绍报头中常见的几个属性。
1.HOST
HOST表示服务器主机的地址和长度,HOST的格式为IP地址(域名):端口号 ,绝大部分情况下,HOST中的IP地址和端口号是与URL中的IP地址和端口号是一致的,但是在一些特殊场景中这俩是不一样的。
注意,我们通过抓包来观察HOST的时候,往往只看到一个域名,因为此时使用了默认端口号,而在HOST中,默认端口号是可以省略的,http协议中默认端口号为80,https中默认的端口号为443.
2.Content-Length
Content-Length表示body中的数据长度,单位为字节。
在传输层中,版本号小于等于2.0版本的http协议是基于TCP实现的。
所谓的http协议,就是把字符串构造成http约定的格式。当我们使用http构造一个请求时,应用层的代码会将请求中的首行,请求头,空行和正文等数据写入到tcp socket中,对于tcp来说,一次连接可以发送多个请求,这时服务器就得区分一下,从哪里到哪里是一个完整的http请求。
对于没有body的http请求,读到空行,就可以认为该请求就结束了
对于有body的http请求,首先读取首行和header,解析header中的Content-length,接下来就可以根据Content-length的值,去读取正文中固定字节的内容,在这之后,就可以认为该请求就结束了。
3.Content-Type
Content-Type表示body中的数据格式,这也揭示了接收方应该如何解析body中的数据。
但是有时我们通过转包看到的正文形式很复杂,甚至看不懂,这是因为代码混淆机制,防止其他竞争对手轻易通过抓包轻易获取到我们写的代码,如下图
注意事项:不论是请求报头还是响应报头,Content-type,Content-Length和body是相互依存,缺一不可,如果有body,没有其他两个属性或者只有一个属性,都可以认为是非法的/错误的http报文
4.User-Agent
Uer-Agent里面表示了用户使用的设备的浏览器和操作系统的情况。
如下图是对一个User-Agent的解析
此外User-Agent还有区分用户设备的用途,根据用户的设备来返回不同版本的页面,例如如果设备是一个手机,就返回一个移动端的页面,如果设备是平板或者电脑,就返回一个PC端页面。
5.Referer
Referer描述了当前页面的来源,也就是表示该页面是从哪一个页面跳转过来的。
实例一
实例二
但是如果直接在浏览器中输入URL或者直接通过收藏夹来访问页面是没有Referer 。
6.Cookie
Cookie是浏览器允许网页在本地硬盘存储数据的一种机制,不是让网页直接访问文件系统,而是做了一层抽象,这层抽象就是Cookie的键值对存储机制。
Cookie中存储了一个字符串,这个数据可能是客户端(网页)自行通过JS写入的,也可能来自服务器(服务器在http响应的header中通过Set-Cookie字段给浏览器返回数据),往往通过这个字段实现“身份认证”的功能,也就是登录身份验证功能。
当浏览器保存了这些cookie之后,就会在后续给服务器发送请求的时候,把这些cookie键值对放到请求的cookie,伴随header传输给服务器。
注意:每个不同的域名下都可以有不同的Cookie,不同网站之间的cookie并不冲突。
通过抓包观察页面登录的过程(以码云为例):
1.先清除之前的cookie
为了方便观察,先清除掉之前的cookie,在码云的页面,点击URL左侧的图标,选择Cookie,
然后移除已经存在的Cookie
2.登录操作,抓登录操作的包
由于我们在此之前删除了Cookie,所以在这这个http登录请求中没有Cookie属性。
但是,http响应会通过set-Cookie来设置登录请求中Cookie中的内容,如下图
登录成功之后,此后访问码云的其他页面,http请求中就会带着刚才获取到的Cookie信息。
7.理解登录过程
Cookie里面的数据都是程序员的自定义内容,通常都与业务相关,但是有一个典型的场景,属于“通用业务”,那就是登录和用户验证。
当我们第一次在这个新的网页页面进行登录操作时,我们输入用户名和密码之后,浏览器会向服务器发送一个登录请求,此时,服务器收到登录请求后,就会查询数据库,验证该用户名和密码是否有效,如果匹配成功,服务器这端就会生成一个关于该用户的sessionId,接着就会生成一个session对象,这个sessionid与session对象是一一对应的(通过一个sessionid可以找到唯一一个与之对应的session),就可以把用户的关键信息保存在session对象中,然后把sessionid和session对象作为键值对,保存到内存中的hash表中,最后通过Set-cookie将sessionid返回给浏览器。
当浏览器接收到sessionid后,会存储在Cookie中,后续在该页面时,会根据这个sessionid来就可以知道这个请求是从哪个用户发送来的,就不需要要求已经登录过的用户重新登录了。
Cookie是可能会过期的,服务器返回的Cookie的时候,是可以设置有效时间的,如果Cookie中的sessionid过期了这时候就需要用户重新登录了。
4.HTTP响应---认识状态码
状态码可以表示访问该页面的一个结果,(是访问成功,还是访问失败,还是其他的一些情况)
下图是关于http响应的状态码图。,我们没必要全部都认识这些状态码,我们挑一些经常遇见的来介绍。
200 OK
这是一个最常见的状态码,表示页面访问成功。
404 Not Found
该状态码表示没有找到URL对应的资源。
浏览器输入一个URL,目的就是为了访问对方服务器上的一个资源,如果这个URL标识的资源不存在,那么就会出现404.
下图是B站的一个404 Not Found展示的页面,该页面的内容是可以有程序员自定义的。
403 Forbidden
403表示访问被拒绝,有的页面通常需要用户具有一定的权限才能访问,如果用户没有权限访问该页面,就容易见到403.
405 Mothod Not Allowed
前面我们已经学习了http中所支持的方法,有GET,POST等方法,但是对方服务器不一定支持所有的方法,这种情况就容易出现405的现象。
500 Internal Server Error
500表示服务器内部出现错误,一般是服务器的代码在执行过程中遇到了一些特殊情况,例如代码抛出的异常没有捕获,这种情况下就容易出现500这个状态码。
504 Gateaway Timeout
Gateaway是网关的意思,也就是网络的入口。
对应到服务器,在很多场景中,会有一个入口服务器,这个入口服务器可以是一个软件,也可以是一个专门的机器。
只有数据成功传送到入口服务器,里面的服务器才能真正的处理数据,所以当传输的数据超出入口服务器的处理能力时,就会出现504这个状态码,尤其是服务器资源紧张时很容易触发。
302 Move temporarily 和 301 Moved Permanently
302表示临时重定向。
301表示永久重定,向当浏览器收到这种响应时,后续的请求就会自动改成新的域名。
理解重定向
当我们访问一个域名的时候,有可能关于该域名的服务器就已经搬移一个新的位置,不在原来的位置了,但是这是如果有人访问旧域名,不就不能访问到该网页了吗?
如果直接迁移,就会使所有保存旧域名的用户都无法访问了,这时我们就会给旧域名设置重定向,当访问旧域名时,就会重新定向到新域名。
状态码小结
我们可以认为2xx的状态码都可以视为成功,3xx都是重定向,4xx客户端出错(用户构造的请求有问题),5xx是服务器出错。