【计算机网络】HTTP协议详解

目录

1. HTTP协议概述 

2. HTTP协议的工作过程

3. 使用抓包工具观察HTTP协议格式 

3.1 Fiddler抓包工具 

3.2 HTTP协议格式

4. 解析HTTP请求

4.1 URL 

4.2 请求方法 

4.2.1 GET方法

4.2.2 POST方法 

4.2.3 经典面试题:GET与POST的区别? 

4.2.4 其他方法 

4.3 请求报头(Header) 

4.4 Cookie和Session(面试常考) 

4.4.1 Cookie

4.4.2 Session 

4.4.3 Cookie和Session是如何一起工作的? 

4.4.2 Cookie和Session的过期校验

5. 解析HTTP响应 

5.1 HTTP响应状态码 

5.2 响应报头(Header) 

6. 构造HTTP请求 

6.1 form表单构造HTTP请求

6.1.1 form表单的介绍 

6.1.2 form表单构造GET请求

6.1.3 form表单构造POST请求

6.2 Ajax构造HTTP请求 

6.2.1 为何使用ajax构造HTTP请求? 

6.2.2 ajax构造GET请求 

6.2.3 ajax构造POST请求  

6.2.4 封装Ajax函数

6.2.5 ajax的跨域问题


1. HTTP协议概述 

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响应,响应被浏览器解析后,就展示为页面内容

2. HTTP协议的工作过程

HTTP协议的工作过程也就是客户端与服务端交互的过程(网络通信),这里的客户端指浏览器进程,服务端指web服务器进程

如:在浏览器输入一个网址,浏览器向给对应服务器发送HTTP请求,对方收到这个请求后进行处理,处理完后返回一个HTTP响应

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

说明:百度搜索的页面是通过HTTPS协议来进行通信的,HTTPS是在HTTP及基础上做了一个加密解密的过程,在后续文章中介绍 

3. 使用抓包工具观察HTTP协议格式 

HTTP协议是一个文本格式的协议,可以使用抓包工具Fiddler进行抓包,以此来分析HTTP请求和响应的细节 

3.1 Fiddler抓包工具 

Fiddler抓包工具的使用 

附上下载地址:Fiddler抓包工具下载地址,需要的小伙伴可以去下载哟!安装过程一路next即可 

  • 左侧窗口显示了所有的HTTP请求/响应,可以选中某个查看详情
  • 右侧上方显示了HTTP请求报文的内容(Raw标签可以查看详细的数据格式)
  • 右侧下方显示了HTTP响应报文的内容(Raw标签可以查看详细的数据格式)

抓包工具的原理 

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

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

抓包结果 

HTTP请求:

HTTP响应:

3.2 HTTP协议格式

协议格式总结 

HTTP请求: 

  • 首行:请求方法+url+协议版本号
  • Header头:请求的属性,为多个用冒号分割的键值对,每个键值独占一行
  • 空行:表示Header头的结束
  • Body:空行后面的内容都是Body,Body允许空,如果Body存在,则在Header头中有一个Content-Length的属性来标识Body的长度 

HTTP响应:

  • 首行:协议版本号+响应状态码+状态码解释
  • Header头:请求的属性,为多个用冒号分割的键值对,每个键值独占一行
  • 空行:表示Header头的结束
  • Body:空行后面的内容都是Body,Body允许空,如果Body存在,则在Header头中有一个Content-Length的属性来标识Body的长度 

为什么HTTP报文中要存在空行? 

  • HTTP协议并没有规定Header头有多少个键值对,空行就是相当于Header头结束的标记,也就是报头和正文的间隔 
  • HTTP在传输层依赖TCP协议,TCP是面向字节流的,如果没有空行,就会出现“粘包问题” 

Body是任意格式的数据,如何解析? 

Header头中有两个字段:Content-Length,Content-Type

  • Content-Length:标识Body的长度(字节长度)
  • Content-Type:标识Body的数据格式,目的是告诉对方如何解析body 

Content-Type的常用格式:

  • application/x-www-form-urlencode:表单提交的格式,键值对的形式,键=值,多个键值对用&间隔(与queryString的格式一样),只能是简单类型(数值,字符,boolean等)
  • image/jpeg:指定具体的一个文件类型,客户端发送请求只能上传一个文件,服务端返回相应只能返回一个图片 
  • text/javascript,text/css,text/html
  • application/json
  • multipart/form-data:简称form-data格式,一般用于请求,不用于响应,可以发送多个字段,每个字段可以是简单类型(数值,字符,boolean等),也可是复杂类型(图片,视频等)

请求正文的格式常用表单格式,图片,视频等文件格式,都是用来上传数据到服务端

响应正文的格式常用的是text/javascript,text/css,text/html,来返回网页,css样式文件,js文件,客户端使用这些文件将图片渲染出来,播放视频,下载文件等

application/json格式,请求和响应都常用,对于请求就是输入内容提交到服务端,对于响应就是服务端返回一些数据,客户端js代码获取到响应数据后,然后填充到html中

4. 解析HTTP请求

4.1 URL 

URL标识网络中某个资源的路径,俗称网址,互联网上每个文件都有一个唯一的URL

URL的格式:协议名://服务器地址:服务器端口号/带层次的资源路径?查询字符串

  • 协议名:常见的有http,https
  • 服务器地址:可以使用IP地址或域名,IP地址不方便记忆,使用域名更方便,而且更换服务器后,只需要将域名绑定新的IP,域名还可以使用
  • 服务器端口号:当端口号省略时,浏览器会根据协议的类型自动决定使用哪个端口,http协议默认使用80端口,https协议默认使用443端口
  • 带层次的资源路径:标识某个服务器中的某个资源路径,如果没有输入资源路径,就默认访问 /(称为某个web应用的根路径)
  • 查询字符串(queryString):用=分割的键值对,键=值,多个键值对用&分割,它的作用是获取不同条件下的资源,如userId=10,当使用不同的userId时,会获取到不同的user信息 

ping命令的简单使用

使用ping命令查看域名对应的IP地址:

  1. 在开始菜单输入cmd,打开命令提示符
  2. 在cmd中输入ping www.baidu.com,即看到域名解析的结果

URL中可以省略的部分 

  • 协议名:可以省略,省略后默认为http://
  • IP地址/域名:在HTML中可以省略(如img,link,script,a标签的src或者href属性),省略后表示服务器的IP地址/域名与HTML所属的IP地址/域名一致
  • 端口号:可以省略,http协议默认端口80,https默认端口443
  • 带层次的资源路径:可以省略,省略后相当于/,有些服务器发现/路径时自动访问/index.html
  • 查询字符串:可以省略

URL encode 

如果URL中包含特殊字符如中文,空格等都会转义,转义后再放在http数据包中,然后在发送http请求,浏览器的地址栏中还是显示中文,但是真实发送的http数据包是已经转义过的内容

  • urlencode(url编码):将url里的中文,空格等转换为16进制数据
  • urldecode(url解码):将url里的16进制数据转换为原始的空格,中文等

获取URL时,就得注意,因为可能获取的是编码后的内容,可能需要解码,如在后端获取到URL需要解码,在JS中,img.src=="xxx",如果xxx有中文,可能达不到预期结果,因为img.src保存的是编码后的内容

4.2 请求方法 

请求方法标识具体使用什么方式来操作资源,如:获取资源,保存资源,修改资源,删除资源,属于操作资源的类型

说明:这里只是规范上的约定,具体服务端代码中要怎样实现,由程序员自己决定,GET,POST方法最常用,其他方法了解就行

4.2.1 GET方法

GET方法常用于获取服务器资源,在浏览器中输入URL,浏览器会向服务器发送一个GET请求(浏览器输入URL默认是GET方法),使用JavaScript中的ajax也能构造GET请求 

GET请求的特点:

  • 首行的方法为GET
  • URL的queryString可以为空,也可以不为空,数据一般存放于queryString中
  • body一般为空

4.2.2 POST方法 

POST方法常用于将用户输入的数据提交到服务端(如登陆功能),通过HTML中的form标签能构造POST请求,使用JavaScript中的ajax也能构造POST请求

POST请求的特点:

  • 首行的方法为POST
  • URL的queryString一般为空
  • body一般不为空,数据一般保存在body中

4.2.3 经典面试题:GET与POST的区别? 

  • 语义:GET一般用于获取服务端资源,POST一般用于提交数据到服务端
  • 存放数据位置:GET一般存放数据在queryString中,POST一般存放数据在body中
  • 幂等性:GET具有幂等性,POST不具有幂等性,所谓幂等性是指多次发送http相同的数据包,得到的结果一样
  • 缓存:GET可以被缓存,POST不能被缓存,浏览器为了提高性能,把GET获取的资源提前保存在本地,下次请求直接从本地获取 

4.2.4 其他方法 

  • PUT:与POST相似,只是具有幂等特性,一般用于更新
  • DELETE:删除服务器指定资源
  • OPTIONS:返回服务器所支持的请求方法
  • HEAD:类似于GET,只不过响应体不返回,只返回响应头
  • TRACE:回显服务器端收到的请求,测试的时候会用到这个
  • CONNECT:预留,暂无使用

这些方法的HTTP请求也可以使用JavaScript的ajax来构造 

4.3 请求报头(Header) 

Header头标识数据包属性,格式为用冒号分割的键值对,键:值,每个键值对独占一行

  • Host:标识服务器主机的地址(域名或IP+端口) 
  • Content-Length:标识Body长度,对方根据这个属性来解析
  • Content-Type:标识Body的数据格式
  • User-Agent:简称UA,标识浏览器和操作系统的信息,常用作判断是哪个浏览器,pc,手机
  • Referer:标识这个页面是从哪个页面跳转过来的
  • Cookie:用于请求头,浏览器自动携带本网站在本地保存的Cookie信息
  • Set-Cookie:用于响应头,服务端设置信息 

理解登录过程

重点说明:

登陆成功后,服务端返回的响应中响应头有一个Set-Cookie属性,该属性意味着告诉浏览器要将这些信息存起来,浏览器将收到响应,将Set-Cookie的值存在本地中,客户端浏览器后续访问该网站的其他页面时,发送的HTTP请求中,请求头携带一个Cookie属性,该属性就保存了登陆的一些相关信息

4.4 Cookie和Session(面试常考) 

4.4.1 Cookie

Cookie是一种客户端保存数据的技术

  • 如何保存?

服务端响应的http数据包中,设置Set-Cookie头,客户端收到响应后将此信息保存在本地,Cookie是和网站关联,不同的网站有不同的Cookie(保存的信息如账号等不同)

  • 如何使用?

浏览器在每次请求时,自动将保存的信息携带在Cookie头中

  • 保存的数据是什么格式?

多组键值对(键=值,多个键值对用分号间隔)

4.4.2 Session 

Session是一种服务端保存会话的技术,一次会话指登陆没有注销或者超时

由于HTTP协议是无状态的,所谓无状态,就是一次请求,一次响应,服务端无法感知之前登陆的用户,所以在服务端使用Map<String,Session>的数据结构来保存用户信息

4.4.3 Cookie和Session是如何一起工作的? 

以登陆功能举例: 

  1. 服务端校验账号密码成功后,生成一个随机字符串(sessionId,标识用户身份)及一个Session对象(标识用户的该次对话),把sessionId作为键,Session对象作为值存入Map<String,Session>如果需要保存用户信息就保存在Session对象Map<String,Object>中,相当于登陆时服务端使用Session保存用户信息 
  2. 登陆响应,服务端返回给客户端的HTTP响应数据包中,Set-Cookie响应头包含sessionId=xxx
  3. 客户端收到响应后,保存Cookie信息,将响应的Set-Cookie中的内容保存在客户端本地(和此次服务器地址绑定)
  4. 客户端每次请求时,都携带sessionId=xxx在Cookie头中
  5. 服务端获取客户端请求时,先获取Cookie请求头中的内容,查找sessionId对应的值,然后从保存的Map结构中查找,如果存在就是登录用户,如果为null就是未登录

4.4.2 Cookie和Session的过期校验

Session的过期校验

服务端保存的Session信息有默认的过期时间(可通过程序设置) 

服务器有Session的过期校验机制:通过单独的线程扫描,发现当前时间和Session最后一次使用的时间超时就删掉

服务器存放Session的地方,web服务器默认是存放在内存中,所以重启服务器Session也就没了,但是有些服务器把数据保存在服务器硬盘,重启就还有

如果用户注销登录,相当于服务端删除Map中的Session

所以超时后,注销后,重启服务器后需要访问页面就需要重新登陆

Cookie的过期校验 

Cookie也有过期时间(可以通过程序设置) 

如果Cookie过期,浏览器发请求时就不会携带这些信息,服务端验证sessionId时就会验证失败,也就是没有登陆

如果在客户端手动删除Cookie,就相当于服务端还有Session信息,但是客户端请求时也不会携带Cookie信息,服务端验证sessionId失败,也就意味没有登陆

5. 解析HTTP响应 

5.1 HTTP响应状态码 

状态码由三位数字构成,表示访问一个页面的结果,HTTP响应报文由服务端返回(程序可以设置内容),状态码也可以由程序设置

常见状态码

  • 200:表示服务端对当次请求处理成功
  • 404 Not Found:找不到请求路径url对应的资源
  • 304 Not Modified:表示之前访问过的资源,本次请求时没有被修改过,也就是客户端直接从缓存中获取
  • 403 Forbidden:表示访问被拒绝,一般是没有访问权限,没有登陆时就访问就会出现403
  • 405 Method Not Allowed:方法不支持,检查前端请求方法也要检查后端的请求方法
  • 500 Internal Server Error:服务器内部错误,要检查后端控制台异常堆栈信息
  • 504 Gateway Timeout:请求在服务端处理超时,服务端也有返回响应的时间限制,发现处理时间超时就返回504
  • 302 Move temporarily:临时重定向,响应报文的header部分会包含一个Location字段,表示要跳转到哪个页面
  • 301 Moved Permanently:永久重定向,301也是通过Location字段来表示要重定向到的新地址

状态码总结 

类别原因
1xxInformational(信息性状态码)接收的请求正在处理
2xxSuccess(成功状态码)请求正常处理完毕
3xxRedirection(重定向状态码)需要进行附加操作完成请求
4xxClient Error(客户端错误状态码)服务器无法完成请求
5xxServer Error(服务器错误状态码)服务器处理请求出错

5.2 响应报头(Header) 

响应报头的格式与请求报头的格式基本一致,也就是Content-Type,Content-Length等属性含义也和请求中含义相同 

响应请求头中可能会有Location属性,指重定向跳转的路径 

Content-Type 

响应中的Content-Type常见取值有以下几种:

  • text/html:body数据格式是HTML
  • text/css:body数据格式是CSS
  • text/javascript : body数据格式是JavaScript
  • application/json:body数据格式是JSON

6. 构造HTTP请求 

6.1 form表单构造HTTP请求

6.1.1 form表单的介绍 

form(表单)是HTML中的一个常用标签,可用于给服务端发送GET或者POST请求

form的重要参数 

  • action:构造HTTP请求的URL
  • method:构造HTTP请求的方法(GET或POST,form只支持GET或者POST)

input的重要参数

  • type:表示输入框的类型,text表示文本,password表示密码,submit表示提交
  • name:对于GET请求来说,表示构造出的HTTP请求的queryString的key,queryString的value就是输入框输入的内容,对于POST请求来说,数据从queryString转移到了body中
  • value:input标签的值,对于submit来说,value对于按钮上显示的文本 

6.1.2 form表单构造GET请求

<body>
    <!-- form表单,action为请求的url,method为请求的方法 -->
    <form action="http://abc.com" method="GET">
        <!-- name作为键,内容作为值,多个键值对用&间隔 -->
        <input type="text" name="username">
        <Input type="password" name="password">
        <input type="submit" value="提交">
    </form>
</body>

页面效果:

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

体会form代码和HTTP请求之间的关系:

  

6.1.3 form表单构造POST请求

与构造GET请求不同的是只需将form的method由GET修改为POST

<body>
    <!-- form表单,action为请求的url,method为请求的方法 -->
    <form action="http://abc.com" method="POST">
        <!-- name作为键,内容作为值,多个键值对用&间隔 -->
        <input type="text" name="username">
        <Input type="password" name="password">
        <input type="submit" value="提交">
    </form>
</body>

页面效果:

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

6.2 Ajax构造HTTP请求 

从前端角度,除了浏览器地址栏能构造GET请求,form表单能构造GET和POST之外,还可以在 JavaScript中可以通过ajax的方式构造HTTP请求,并且功能更强大

6.2.1 为何使用ajax构造HTTP请求? 

使用表单提交数据,URL会改变,相当于跳转到另一个页面,假如想实现页面局部内容的改变(如发送HTTP请求,用响应返回的数据生成一些内容),这个过程页面不会刷新,就要使用ajax技术 

使用ajax的好处:

  • 不刷新页面就可以发送HTTP请求,用户体验更好
  • 相同的一个页面,动态的通过响应数据来生成局部的页面内容,如果是服务端直接返回变化后的HTML,这时数据传输量比较大,效率较低,但是使用ajax,效率较高,因为响应的数据量只有变化的数据 

ajax产生的原因:

  • JS是单线程运行(代码一行一行的运行,不能基于多线程的方式一次运行多行代码)
  • ajax异步:发送ajax请求后,后边的JS代码还可以继续执行,在ajax事件发生后,由系统内核来通知执行ajax的回调函数

6.2.2 ajax构造GET请求 

<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>

6.2.3 ajax构造POST请求  

对于 POST 请求,需要设置 body 的内容:

  • 先使用setRequestHeader设置Content-Type
  • 再通过send的参数设置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>

6.2.4 封装Ajax函数

原生的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);
        }
    });

6.2.5 ajax的跨域问题

请求当前html页面路径中的服务器地址(ip/域名+端口号)和使用ajax请求的服务器地址不同,就是跨域,跨域问题是ajax中存在的(和html,js,服务器)无关,也就是服务端还能接收到这个请求,并返回响应,但是ajax为了安全起见,如果发现响应头中没有设置允许跨域的信息,就会报错

如果想要强行跨域,需要服务器进行配合,需要在服务器的响应中设置“允许跨域” 

 

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:终极编程指南 设计师:CSDN官方博客 返回首页
评论 16

打赏作者

Java猿~

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值