目录
HTTP协议全称为超文本传输协议,所谓超文本,就是指可以传输文本及其他格式的数据,如音乐,图片,视频等,是一种被广泛应用的应用层协议
对于应用层协议的解释:将数据从A端传输到B端,TCP/IP协议对应的功能是顺丰的功能,但是两端还要对数据进行加工处理或使用,所以还需要一层协议,不必关心通信时的细节,只关心应用,这层协议就是应用层协议
我们平时打开的网站就是通过HTTP协议来传输数据的,HTTP协议是基于传输层TCP协议实现(HTTP1.0,HTTP1.1,HTTP2.0都是基于TCP,HTTP3.0基于UDP实现),我们此处所讨论的以HTTP1.1为主
对于在浏览器访问一个资源(网页,图片,视频等)来说,就是基于HTTP数据包的格式,从主机A的进程传输到主机B的进程
如:在浏览器输入百度的网址(URL)时,浏览器向百度服务器发送了一个HTTP请求,百度的服务器给我们浏览器返回了一个HTTP响应,响应被浏览器解析后,就展示为页面内容

HTTP协议的工作过程也就是客户端与服务端交互的过程(网络通信),这里的客户端指浏览器进程,服务端指web服务器进程
如:在浏览器输入一个网址,浏览器向给对应服务器发送HTTP请求,对方收到这个请求后进行处理,处理完后返回一个HTTP响应

通常访问一个网站的时候,涉及到多次HTTP请求和响应的交互过程,可以通过浏览器的开发者工具的网络标签页,刷新页面查看详细过程

说明:百度搜索的页面是通过HTTPS协议来进行通信的,HTTPS是在HTTP及基础上做了一个加密解密的过程,在后续文章中介绍
HTTP协议是一个文本格式的协议,可以使用抓包工具Fiddler进行抓包,以此来分析HTTP请求和响应的细节
Fiddler抓包工具的使用
附上下载地址:Fiddler抓包工具下载地址,需要的小伙伴可以去下载哟!安装过程一路next即可

抓包工具的原理
Fiddler相当于一个代理,当浏览器访问baidu.com时,就会把HTTP请求先发给Fiddler,Fiddler再把请求转发给baidu的服务器,baidu的服务器返回响应时,也是先把数据发到Fiddler,Fiddler再将数据转发给浏览器,所以Fiddler对浏览器和服务器交互的细节否是非常清楚的

上述原理相当于:代理就可以简单理解为一个跑腿小弟,你想买罐冰可乐,又不想自己下楼去超市,那么就可以把钱给你的跑腿小弟,跑腿小弟来到超市把钱给超市老板,再把冰可乐拿回来交到你手上,这个过程中,这个跑腿小弟对于 "你" 和 "超市老板" 之间的交易细节,是非常清楚的
抓包结果
HTTP请求:

HTTP响应:

协议格式总结
HTTP请求:
HTTP响应:
为什么HTTP报文中要存在空行?
Body是任意格式的数据,如何解析?
Header头中有两个字段:Content-Length,Content-Type
Content-Type的常用格式:
请求正文的格式常用表单格式,图片,视频等文件格式,都是用来上传数据到服务端
响应正文的格式常用的是text/javascript,text/css,text/html,来返回网页,css样式文件,js文件,客户端使用这些文件将图片渲染出来,播放视频,下载文件等
application/json格式,请求和响应都常用,对于请求就是输入内容提交到服务端,对于响应就是服务端返回一些数据,客户端js代码获取到响应数据后,然后填充到html中
URL标识网络中某个资源的路径,俗称网址,互联网上每个文件都有一个唯一的URL
URL的格式:协议名://服务器地址:服务器端口号/带层次的资源路径?查询字符串
ping命令的简单使用
使用ping命令查看域名对应的IP地址:

URL中可以省略的部分
URL encode
如果URL中包含特殊字符如中文,空格等都会转义,转义后再放在http数据包中,然后在发送http请求,浏览器的地址栏中还是显示中文,但是真实发送的http数据包是已经转义过的内容
获取URL时,就得注意,因为可能获取的是编码后的内容,可能需要解码,如在后端获取到URL需要解码,在JS中,img.src=="xxx",如果xxx有中文,可能达不到预期结果,因为img.src保存的是编码后的内容
请求方法标识具体使用什么方式来操作资源,如:获取资源,保存资源,修改资源,删除资源,属于操作资源的类型
说明:这里只是规范上的约定,具体服务端代码中要怎样实现,由程序员自己决定,GET,POST方法最常用,其他方法了解就行
GET方法常用于获取服务器资源,在浏览器中输入URL,浏览器会向服务器发送一个GET请求(浏览器输入URL默认是GET方法),使用JavaScript中的ajax也能构造GET请求
GET请求的特点:
POST方法常用于将用户输入的数据提交到服务端(如登陆功能),通过HTML中的form标签能构造POST请求,使用JavaScript中的ajax也能构造POST请求
POST请求的特点:
这些方法的HTTP请求也可以使用JavaScript的ajax来构造
Header头标识数据包属性,格式为用冒号分割的键值对,键:值,每个键值对独占一行
理解登录过程

重点说明:
登陆成功后,服务端返回的响应中响应头有一个Set-Cookie属性,该属性意味着告诉浏览器要将这些信息存起来,浏览器将收到响应,将Set-Cookie的值存在本地中,客户端浏览器后续访问该网站的其他页面时,发送的HTTP请求中,请求头携带一个Cookie属性,该属性就保存了登陆的一些相关信息
Cookie是一种客户端保存数据的技术
服务端响应的http数据包中,设置Set-Cookie头,客户端收到响应后将此信息保存在本地,Cookie是和网站关联,不同的网站有不同的Cookie(保存的信息如账号等不同)
浏览器在每次请求时,自动将保存的信息携带在Cookie头中
多组键值对(键=值,多个键值对用分号间隔)
Session是一种服务端保存会话的技术,一次会话指登陆没有注销或者超时
由于HTTP协议是无状态的,所谓无状态,就是一次请求,一次响应,服务端无法感知之前登陆的用户,所以在服务端使用Map

以登陆功能举例:
Session的过期校验
服务端保存的Session信息有默认的过期时间(可通过程序设置)
服务器有Session的过期校验机制:通过单独的线程扫描,发现当前时间和Session最后一次使用的时间超时就删掉
服务器存放Session的地方,web服务器默认是存放在内存中,所以重启服务器Session也就没了,但是有些服务器把数据保存在服务器硬盘,重启就还有
如果用户注销登录,相当于服务端删除Map中的Session
所以超时后,注销后,重启服务器后需要访问页面就需要重新登陆
Cookie的过期校验
Cookie也有过期时间(可以通过程序设置)
如果Cookie过期,浏览器发请求时就不会携带这些信息,服务端验证sessionId时就会验证失败,也就是没有登陆
如果在客户端手动删除Cookie,就相当于服务端还有Session信息,但是客户端请求时也不会携带Cookie信息,服务端验证sessionId失败,也就意味没有登陆
状态码由三位数字构成,表示访问一个页面的结果,HTTP响应报文由服务端返回(程序可以设置内容),状态码也可以由程序设置
常见状态码

状态码总结
| 类别 | 原因 | |
|---|---|---|
| 1xx | Informational(信息性状态码) | 接收的请求正在处理 |
| 2xx | Success(成功状态码) | 请求正常处理完毕 |
| 3xx | Redirection(重定向状态码) | 需要进行附加操作完成请求 |
| 4xx | Client Error(客户端错误状态码) | 服务器无法完成请求 |
| 5xx | Server Error(服务器错误状态码) | 服务器处理请求出错 |
响应报头的格式与请求报头的格式基本一致,也就是Content-Type,Content-Length等属性含义也和请求中含义相同
响应请求头中可能会有Location属性,指重定向跳转的路径
Content-Type
响应中的Content-Type常见取值有以下几种:
form(表单)是HTML中的一个常用标签,可用于给服务端发送GET或者POST请求
form的重要参数
input的重要参数
- <body>
-
- <form action="http://abc.com" method="GET">
-
- <input type="text" name="username">
- <Input type="password" name="password">
- <input type="submit" value="提交">
- form>
- body>
页面效果:

点击提交就会构造出GET请求并发出去

体会form代码和HTTP请求之间的关系:
与构造GET请求不同的是只需将form的method由GET修改为POST
- <body>
-
- <form action="http://abc.com" method="POST">
-
- <input type="text" name="username">
- <Input type="password" name="password">
- <input type="submit" value="提交">
- form>
- body>
页面效果:

点击提交就会构造POST请求并发出去

从前端角度,除了浏览器地址栏能构造GET请求,form表单能构造GET和POST之外,还可以在 JavaScript中可以通过ajax的方式构造HTTP请求,并且功能更强大
使用表单提交数据,URL会改变,相当于跳转到另一个页面,假如想实现页面局部内容的改变(如发送HTTP请求,用响应返回的数据生成一些内容),这个过程页面不会刷新,就要使用ajax技术
使用ajax的好处:
ajax产生的原因:
- <script>
- //XMLHttpRequest对象就是ajax发送请求及处理响应的对象
- let xhr = new XMLHttpRequest();
- //设置一个异步回调函数到ajax对象的属性中
- //发送http请求,对应事件发生,才会调用回调函数
- xhr.onreadystatechange = function(){
- //xhr.readyState属性:
- //0:请求未初始化,还没有发生http请求
- //1:客户端和服务器已经建立连接
- //2:服务端已经接收请求
- //3:服务端已经处理请求
- //4:客户端已经收到服务端返回的响应
- if(xhr.readyState == 4){
- //响应状态码
- console.log(xhr.status);
- //响应正文
- console.log(xhr.responseText);
- }
- //open,设置请求方法和url,此时还没有发生http请求
- xhr.open("GET", "http://42.192.83.143:8089/AjaxMockServer/info");
- //send,正式发送http请求,也可以设置请求正文(body)数据
- xhr.send();//send(),send(body)两种方式
- }
- script>
对于 POST 请求,需要设置 body 的内容:
- <script>
- //XMLHttpRequest对象就是ajax发送请求及处理响应的对象
- let xhr = new XMLHttpRequest();
- //设置一个异步回调函数到ajax对象的属性中
- //发送http请求,对应事件发生,才会调用回调函数
- xhr.onreadystatechange = function(){
- //xhr.readyState属性:
- //0:请求未初始化,还没有发生http请求
- //1:客户端和服务器已经建立连接
- //2:服务端已经接收请求
- //3:服务端已经处理请求
- //4:客户端已经收到服务端返回的响应
- if(xhr.readyState == 4){
- //响应状态码
- console.log(xhr.status);
- //响应正文
- console.log(xhr.responseText);
- }
- //open,设置请求方法和url,此时还没有发生http请求
- xhr.open("POST", "http://42.192.83.143:8089/AjaxMockServer/info");
- //设置请求头,设置body数据格式
- xhr.setRequestHeader("Content-Type", "application/x-www-formurlencoded")
- //send,正式发送http请求,也可以设置请求正文(body)数据
- xhr.send("username=abc&password=123");//send(),send(body)两种方式
- }
- script>
原生的XMLHTTPRequest类使用并不方便,我们可以在这个基础上进行简单封装
- <script>
- //封装ajax函数,args为一个js对象
- //args对象属性如下:
- //method:请求方法,url:请求资源路径,contenType:请求正文格式
- //body:请求正文,callback:回调函数,客户端接收到响应数据后调用
- function ajax(args){
- let xhr = new XMLHttpRequest();
- //设置回调函数
- xhr.onreadystatechange = function(){
- //4:客户端接收到服务端响应
- if(xhr.readyState == 4){
- //回调函数可能会使用响应的内容,作为传入参数
- args.callback(xhr.status,xhr.responseText);
- }
- }
- xhr.open(args.method,args.url);
- //如果args中contentType有内容,就设置Content-Type请求头
- if (args.contentType) {//js中if可以判断是否有值
- xhr.setRequestHeader("Content-Type", args.contentType);
- }
- //如果args中body有内容,设置body请求正文
- if(args.body){
- xhr.send(args.body);
- }else {
- xhr.send();
- }
- }
- script>
使用封装的ajax函数构造GET请求
直接调用封装好的ajax函数,传入args对象即可
- ajax({
- method: "GET",
- url: "http://42.192.83.143:8089/AjaxMockServer/info",
- callback: function(status,responseText){
- console.log(status+responseText);
- }
- });
使用封装的ajax函数构造POST请求
直接调用封装好的ajax函数,传入args对象即可
- ajax({
- method: "POST",
- url: "http://42.192.83.143:8089/AjaxMockServer/info",
- contentType: "application/x-www-formurlencoded",
- body: "username=abc&password=123",
- callback: function(status,responseText){
- console.log(status+responseText);
- }
- });
请求当前html页面路径中的服务器地址(ip/域名+端口号)和使用ajax请求的服务器地址不同,就是跨域,跨域问题是ajax中存在的(和html,js,服务器)无关,也就是服务端还能接收到这个请求,并返回响应,但是ajax为了安全起见,如果发现响应头中没有设置允许跨域的信息,就会报错
如果想要强行跨域,需要服务器进行配合,需要在服务器的响应中设置“允许跨域”