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

本文涉及的产品
.cn 域名,1个 12个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 请求当前html页面路径中的服务器地址(ip/域名+端口号)和使用ajax请求的服务器地址不同,就是跨域,跨域问题是ajax中存在的(和html,js,服务器)无关,也就是服务端还能接收到这个请求,并返回响应,但是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响应,响应被浏览器解析后,就展示为页面内容

image.png



2. HTTP协议的工作过程

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


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

image.png


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


image.png


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


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

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


3.1 Fiddler抓包工具

Fiddler抓包工具的使用


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

image.png


左侧窗口显示了所有的HTTP请求/响应,可以选中某个查看详情

右侧上方显示了HTTP请求报文的内容(Raw标签可以查看详细的数据格式)

右侧下方显示了HTTP响应报文的内容(Raw标签可以查看详细的数据格式)

抓包工具的原理


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

image.png


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


抓包结果


HTTP请求:

image.png


HTTP响应:

image.png



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地址:


在开始菜单输入cmd,打开命令提示符

在cmd中输入ping www.baidu.com,即看到域名解析的结果

image.png


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:用于响应头,服务端设置信息

理解登录过程


image.png


重点说明:


登陆成功后,服务端返回的响应中响应头有一个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的数据结构来保存用户信息

image.png


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

以登陆功能举例:


服务端校验账号密码成功后,生成一个随机字符串(sessionId,标识用户身份)及一个Session对象(标识用户的该次对话),把sessionId作为键,Session对象作为值存入Map如果需要保存用户信息就保存在Session对象Map中,相当于登陆时服务端使用Session保存用户信息

登陆响应,服务端返回给客户端的HTTP响应数据包中,Set-Cookie响应头包含sessionId=xxx

客户端收到响应后,保存Cookie信息,将响应的Set-Cookie中的内容保存在客户端本地(和此次服务器地址绑定)

客户端每次请求时,都携带sessionId=xxx在Cookie头中

服务端获取客户端请求时,先获取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字段来表示要重定向到的新地址image.png

状态码总结


类别
原因
1xx Informational(信息性状态码) 接收的请求正在处理
2xx Success(成功状态码) 请求正常处理完毕
3xx Redirection(重定向状态码) 需要进行附加操作完成请求
4xx Client Error(客户端错误状态码) 服务器无法完成请求
5xx Server 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>


页面效果:

image.png


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

image.png


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

image.png

 

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>



页面效果:

image.png

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

image.png

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


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

image.png



相关文章
|
1天前
|
负载均衡 网络协议 算法
|
3天前
|
网络协议 安全 Go
Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
【10月更文挑战第28天】Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
23 13
|
23小时前
|
开发者
HTTP 协议请求方法的发展历程
【10月更文挑战第21天】
|
1天前
|
安全
HTTP 协议的请求方法
【10月更文挑战第21天】
|
23小时前
|
缓存 安全 前端开发
HTTP 协议的请求方法在实际应用中有哪些注意事项?
【10月更文挑战第29天】HTTP协议的请求方法在实际应用中需要根据具体的业务场景和需求,合理选择和使用,并注意各种方法的特点和限制,以确保网络通信的安全、高效和数据的一致性。
|
3天前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
4天前
|
网络协议 算法 网络性能优化
计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
计算机网络常见面试题(一):TCP/IP五层模型、应用层常见的协议、TCP与UDP的区别,TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议、ARP协议
|
2月前
|
监控 安全 搜索推荐
设置 HTTPS 协议以确保数据传输的安全性
设置 HTTPS 协议以确保数据传输的安全性
|
30天前
|
安全 网络协议 算法
HTTPS网络通信协议揭秘:WEB网站安全的关键技术
HTTPS网络通信协议揭秘:WEB网站安全的关键技术
134 4
HTTPS网络通信协议揭秘:WEB网站安全的关键技术
|
1月前
|
存储 网络安全 对象存储
缺乏中间证书导致通过HTTPS协议访问OSS异常
【10月更文挑战第4天】缺乏中间证书导致通过HTTPS协议访问OSS异常
60 4