0


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

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为了安全起见,如果发现响应头中没有设置允许跨域的信息,就会报错

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


本文转载自: https://blog.csdn.net/qq_58710208/article/details/126155536
版权归原作者 Java猿~ 所有, 如有侵权,请联系我们删除。

“【计算机网络】HTTP协议详解”的评论:

还没有评论