Go to comments

网络大师课 分层模型和应用层协议

一、五层网络模型

网络要解决的问题是,两程序之间如何交换数据

由于这是一个复杂的问题,所以它分成多层,每一层解决具体的事情


1、五层网络模型

20211008163417.jpg

应用层

负责规定“消息”的格式,

该层有不同的协议,不同的协议消息的格式不一样


传输层

负责消息的“传递”,主要是负责可靠传输,有些是可靠的,有些不一定是可靠的,

TCP  是可靠的传输,准确无误的传输到对方

UDP 不一定是可靠的传输

不同的传输方式,决定了网络的传输效率(传的快还是传的慢)


网络层

负责如何找到对方,

在茫茫的互联网中有这么多台计算机,如何准确的找到对方,有可能兜了一大圈发现就是本机


数据链路层

“网络层”跟“数据链路层”要解决的问题差不多,都是为了要找到对方


“网络层”指的是在互联网当中如何来找对方,

可以简单的这样理解(虽然解释的可能没有那么准确),比如我们家里面不管有几台电脑,基本是靠一台路由器链到互联网,也就是说这几台电脑用的是公网的同一个 IP 地址。


每家的路由器用的是公网上不同的一个 IP 地址


我们要访问别人家的计算机,比如发一个聊天消息“你好”过去,

是发到对方家里面的路由器,“网络层”就是找到对方家的路由器,对方发消息回来也是一样找到我家的路由器


也就是说对于“网络层”而已,其实不太清楚路由器背后有几台电脑,它只是路由器与路由器之间的交互,因为路由器是链接到互联网的,

但是路由器背后连接着家里的多台电脑(要准确的说应该叫交换机,不能说路由器,为了便于理解说路由器),


到了路由器后要找到哪一台计算机,这个时候要靠“数据链路层”,大概是这个意思


“数据链路层”能够准确的找到对方具体那一台电脑,像平时说的 MAC 地址就是数据链路层里面的相关知识,MAC 地址是找计算机的,因为 IP 地址会变,MAC 地址是不会变的


比如 Teather Yuan 今天在成都,明天就出差到哈尔滨了,带着同一台电脑,

IP 地址会随着当前位置而变化,有点像你当前的家庭住址,当前住址可能会变,

但是 MAC 地址相当于指纹或视网膜,走到哪都不会变,它是计算机出厂的时候焊死在网卡里面的(也有手段去改,但一般不会改)


“数据链路层”找到具体计算机后,最后就是传输了


物理层

如何传输是物理层要解决的问题,如何把我们的数据转换成电信号或是光信号,

通过物理介质或无线的电磁波传递过去,这物理层解决的问题,


Ps:

以前我们的互联网公司最多在前两层玩,更多的在前一层“应用层”里面玩,

其他层基本是标准,而标准的制定基本上是被国外垄断的,但是像华为这样的公司他涉及到的是下面的三层,制定标准利润是很高的


2、数据的传输

该示例解释了,

一个消息,是如何从一台计算机的某一个程序,传到另一个计算机的某一个程序

20211008163458.jpg

发送方:

发送的原始消息是“我爱你”

应用层,给原始消息套一层东西(比如 http 协议),然后交给下一层

传输层,它要解决可靠传输,再套一层东西,比如加一些校验码(对方就可以校验一下消息是否完整传过来了),然后又往下层传递

网络层,加一层,比如 IP 地址,我的 ip 地址、对方的 ip 地址

数据链路层,前后都会加东西,我的 mac 地址、对方的 mac 地址

物理层,变成电信号或光信号,通过物理介质或无线电磁波传递过去


接收方:

物理层,收到一大堆东西,它看不懂交给数据链路层

数据链路层,它看得懂这一大堆东西,因为它看得东自己加的东西,把自己加的东西去掉,交给网络层

网络层,它看得懂自己加的 ip 地址,把自己加的去掉,又给传输层

传输层,它能看懂可靠传输的协议,于是它校验一下,如果有问题重新传,没有问题就把自己的东西去掉,给应用层

应用层,把加的东西去掉就看到原始的消息“我爱你”,显示到计算机屏幕上


在电光火石之间,就完成了这一系列的操作,消息就发送过去了,

这里面的细节非常非常多,前端了解到这个程度就行了,珍惜有限的时间!


前端工程师主要是跟“应用层”打交道,应用层里面有很多的协议、很多的标准,其中我们的要研究两个

1. URL

2. HTTP


二、url

URL(uniform resource locator,统一资源定位符)用于定位网络服务


在茫茫互联网上有很多服务,

比如看新闻、视频、听音乐等等,我们用 URL 来描述要找的这些服务在哪里,

URL 就是一个字符串,是一个统一的标准格式的字符串,叫统一资源定位符(定位的是资源,资源就是服务

202301121029498.jpg

其实整个 url 是在不断的细化通信的细节,具体每一个部分写什么要看服务器

细节名称示例意思
domain域名a.com在茫茫互联网中要找哪一台计算机
port端口80找到这台计算上是哪一个程序
path路径/news/detail程序中可能有很多服务,要找哪一服务
query参数id=1服务里面的具体的细节
scheam协议http通信协议(scheam或者用protocol都是协议的意思)
hash哈希#t1

哈希一般不参与网络通信,不用太关心它,后端跟浏览器都不 care 它,一般是在本页内部跳转


示例,

VSCode 右键点击 Open with Live Server 之后,地址栏就是 url 地址  http://localhost:5500/index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Document</title>
</head>
<body>

  <h1>Hello</h1>

</body>
</html>


域名

可以这样理解,在互联网上每一台计算机都会对应一个域名,通过域名可以在互联网上找到计算机,域名这里也可以写 ip 地址

localhost 表示访问本机,127.0.0.1 也是本机,本身上的哪一个程序要看端口


端口

因为一台计算上会运行很多的程序,不同的程序会监听不同的端口,

就好比一栋楼里面有很多的房间,要找哪个房间,就要把房间的号码给我,然后找里面的住的人


 localhost:5500 

5500 的意思表示是 Live Server 插件它住的房间编号是 5500

通过 localhost 找到本地计算机,

通过 5500 打开了房间,发现里面住是一个叫 Live Server 的应该程序在里面运行


所以通过这一段 localhost:5500

就可以准确找到,某一台计算机上的某一个应用程序,

该程序可以做很多事情,给不同的路径,程序可能做不一样的事情,提供不一样的服务


路径

这里的路径是  /index.html   


这个路径能做什么,要看 5500 这个程序是怎么写的,

程序可能给我们一张图片

可能给一个 js 文件

可能给一个 css 代码

甚至报一个 404 错误,告诉我们资源不存在等...它可能会做任何事情


不过 Live Serve 这个程序比较正常,

它就给我们找到对应的 index.html 文件,然后读取该文件的内容,发送到我们的浏览器,于是浏览器渲染就看到页面的 hello 了


Teacher Yuan 说了这么多,因为这个地方的认识容易产生偏差,

当访问这个地址  http://localhost:5500/index.html,

看到页面上显示一个 Hello,

并不意味着在 localhost 这台计算机,访问的这个 5500 程序,该程序的目录里面有一 index.html 文件!


因为网络通信不是通过文件的,

而是说路径  /news/detail,是被监听 80 端口的这个程序所拿到的,

这个监听 80 端口的程序可以给我们一个图片、一个 js 代码、css 代码...,或做任何事情,或者什么都不给


网络是两个应用程序进行通讯,

客户端浏览器程序,另外一端是服务器上的程序


这个路径 /index.html 不一定有 html 页面,服务器端写一个程序可以直接发一个字符

1. npm init 

2. npm i express body-parser cors

3. 新建文件 server.js

4. 启动 node server.js

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.get('*', (req, res) => {
  // res.heaher('Conten-Type', 'image/png');
  res.send('快乐的池塘里有一只小青蛙');
});

const PORT = 9528;

app.listen(PORT, () => {
  console.log(`server start on port ${PORT}`)
});


http://localhost:9528/abc/def/hij/kkk.css  访问的这个地址 

现在我们知道,这个路径 /abc/def/hij/ 的程序里面没有 kkk.css 文件,

但是得到了内容“快乐的池塘里有一只小青蛙”是程序给我们的


当然,服务器程序可以判断,有没有这个 kkk.css 文件,

如果有,把该文件读出来,把文件的内容发给我们


一定要清楚这是“浏览器”跟“服务器”,这两个程序在通信

浏览器向服务器请求东西,

服务器给浏览器一个东西,至于怎么给,服务器有自己的逻辑,甚至可以把 kkk.css 返回一个图片 


所以,通过这些,

不要认为路径 /abc/def/hij/kkk.css  跟服务器程序的里面的文件相关联,

没有任何的关联,

只不过有些程序比较常规,把 url 的路径当成文件读,这种规矩的程序,我们把这个程序叫静态资源服务器


总结,

路径只是一个“服务”,只能表达我想要什么东西,仅此而已


query

表示某一些服务的细节


比如  https://www.baidu.com/s?wd=渡一教育 

/s      路径部分表示百度的搜索服务

?wd  这部分是 query,表示搜索服务的具体的细节,既要搜索的内容


url 的一些细节

1. 当协议是 http 端口默认为 80,可以省略端口

2. 当协议是 https 端口默认为 443,可以省略端口

3. schema、domain、path 是必填的,其他的根据具体的要求填写

    域名 必填,决定计算机在哪里

    协议 必填,平时浏览器会自动补全。浏览器先用 http 试,如果网站支持 https,一般会自动跳转到 https

    path 必填,平时不写,浏览器默认补全 / 路径,斜杠表示根路径


三、应用层协议 HTTP

超文本传输协议(Hyper Text Transfer Protocol, HTTP)是一个广泛用于互联网应用层的协议


HTTP 是一个协议(也就说它就 bb,不做任何具体事情),只要用该协议通讯,就必须遵守它规定两方面的内容

1. 传递消息的模式

2. 传递消息的格式


1、传递消息的模式

两个程序之间传递消息,应该怎么通讯呢?

1. 永远是由客户端一方发起主动,服务器一端被动

2. 浏览器主动向服务器发起一个消息过去,这个过程叫 请求 Request

    服务器一方拿到这个消息后,回应一个消息叫 响应 Response

3. 请求 - 响应完成后一次交互结束。说的跟废话一样,但这就是 http 传送消息的模式,既 请求 - 响应 模式

202301121100790.jpg

平时我们跟朋友打电话,没有限制要求,

可能你一个人说,对方听你说,

也可能两个人一起说


但是 HTTP 协议要求必须要这样通电话,

你电话打过去了叫请求,说完一句了,要停

你朋友会回应你一句消息,

然后双方就挂电话吧。

如果你还想说,

你重新拨号过去,发一个请求消息过去,然后对方你回应一个消息


http 这样一来一回的消息模式叫“请求-响应”模式

发出请求的一端叫客户端 Client

接收请求回复响应的叫服务器 Server


“请求-响应”模式非常简单、很好理解、很好推广,但同时也会有一些问题(具体后面会说)


2、传递消息的格式

HTTP 的消息的格式是一个纯文本的"字符串",该字符串由三个部分组成

请求行 Line
请求头 Header

请求体 Body


请求的意思就是把这个字符串发到服务器 Server,

服务器响应也是一样,生成一个字符串发回客户端 Client


不要忘记上面说过五层网络模型,

客户端的应该层把消息组装好了,就是一个字符串,该字符串传给下一层传输层在做一些事情,

但是到了对方服务器端的应用层,它拿到的就是这个字符串


实际体验一下消息格式是什么样子,有非常多的工具可以发送 http 请求,

Teacher Yuan 推荐一个非常直观的工具 REST Client,因为它可以完整的看到“请求”跟“响应”两完整个字符串的组成的部分

1. vscode 安装插件 REST Client

2. 新建后缀为 .http 的文件,比如 test.http 

3. 在 test.http 文件里面编辑请求消息,写一个请求消息的字符串(一般 GET 不带请求体,也可以写请求体)

4. 点击 Send Request 按钮发送请求消息,发出去后得到百度给我们的响应

拿百度首页的请求消息

test.http

GET / HTTP/1.1
Host: www.baidu.com


百度响应的也是一个字符串,也是由三部分组成

响应行

响应头

响应体

HTTP/1.1 200 OK
Date: Mon, 05 May 2025 07:06:06 GMT
Server: Apache
Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
ETag: "51-47cf7e6ee8400"
Accept-Ranges: bytes
Content-Length: 81
Cache-Control: max-age=86400
Expires: Tue, 06 May 2025 07:06:06 GMT
Connection: close
Content-Type: text/html

<html>
<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
</html>


HTTP 协议的本质,

就是一个字符串发过去,一个字符串发回来


尽管进阶阶段还有 HTTP2,

它不在是文本格式了,是二进制格式,

但是对我们的开发影响不大,仍然可以当成文本格式理解


3、请求消息的字符串格式

请求方法

请求行中第一个单词 GET 表示请求方法

http 协议官方描述,请求方法只有含义上的不同,只是表达了这次请求的愿望

The request method token is the primary source of request semantics;

it indicates the purpose for which the client has made this request and what is expected by the client as a successful result.


The request method token  这个 token 请求方法

is the primary source of request semantics  是请求语义的主要来源,意思是请求方法表达了请求的含义


具体什么含义呢?

it indicates the purpose 它指明了一个目的,

client has made this request 客户端发出这个请求的目的


常见的请求方法,表达了客户端的一些美好愿望,仅此而已

GET    获取,表示拿一些东西

POST 提交,表示要提交一些东西

PUT    修改,想修改

DELETE 删除,想删除


所以面试的时候问题 GET 和 POST 的区别?

从 HTTP 协议的角度看,不同的请求方法只是表达了客户端不同的愿望,他们只有含义(语义)上的区别,


但是由于只有语义上的区别,

GET 表达了客户端想要一些东西,又没什么东西要给出去,

所以浏览器觉得 GET 方法应该没有请求体,只有请求行,请求头,请求体是空的,

但是在协议层面上,它可以带请求体,只是一般很少这么做


请求路径

请求行中的 / 斜杠,表示 url 地址中的   请求路径加 + query 


比如

请求这个地址  http://www.baidu.com/s?wd=html 

请求路径是端口号后面的那一坨    GET  /s?wd=html  HTTP/1.1  


HTTP/1.1

这部分基本是固定的,用的是 HTTP 协议,版本号是 1.1


如果今后 HTTP2.0 这里是不是要写 2.0  呢?

不是这样,这是协议升级,今后会学到


接下来是请求头


请求头

请求头是很多的属性名和属性值(一行一个),不同属性表达了不同的含义

有些属性是你们公司自行规定的

有些属性是很多公司一起不约而同规定的

有些属性是 HTTP 协议官方规定的(就是标准组织规定的


 Host: www.baidu.com:80 

Host 属性属性是必须要传递的,表示 url 地址里面的主机域名,默认端口号 80 可以不写


怎么写这个请求地址?https://study.duyiedu.com/api/movies

1. 请求方法 GET

2. 路径 /api/movies

3. 请求头的 Host 属性是主机地址  study.duyiedu.com

使用 REST Client 插件请求可以就可以得到响应结果,结果电影数据

GET /api/movies HTTP/1.1
Host: study.duyiedu.com


研究一下请求消息里面的请求体

之前一直用 GET 请求,只不过一般客户端的 GET 不带请求体(其实 GET 也可以写请求体


请求体

带请求体的用 POST 请求,表示要提交一些东西


比如注册一个账号

1. 请求行,POST 请求表示提交,api/user/reg  请求路径 


2. 请求体写在哪呢?在请求行后面两次回车后写“请求体


请求体怎么写呢?

一般请求体有三种格式,这里用第一种 json 格式,

json 格式就是 js 的对象 {},或是 js 的数组 [],

属性值、属性名是字符串必须用双引号(不是单引号)


3. 当带请求体后,必须在请求头中通过 Content-Type 字段,表明请求体的格式 application/json


使用插件 REST Client 发送注册请求

POST /api/user/reg HTTP/1.1
Host: study.duyiedu.com
Content-Type: application/json

{
  "loginId": "ruyiccom",
  "loginPwd": "123123",
  "nickname": "远远的地方"
}

返回的响应体也是一个 json 格式

{

  "code": 0, 0 表示没有错误码,注册成功

  "msg": "", 为空表示没有错误消息

  "data": {

    "id": "66f533385f8cc70c8a37e38a",

    "loginId": "ruyiccom",

    "nickname": "远远的地方"

  }

}


注册成功后就可以登陆了,

请求行的路径是 /api/user/login

请求体传递账号和密码

POST /api/user/login HTTP/1.1
Host: study.duyiedu.com
Content-Type: application/json

{
  "loginId": "ruyiccom",
  "loginPwd": "123123"
}

使用插件 REST Client 发送登录请求,

登录成功了,

没有浏览器、没有表单界面,就纯粹的 HTTP 就可以完成了注册和登陆。本质就是网络通信,完成了登陆和注册,不是模拟的是真实的登录


在请求头中使用 Content-Type 属性表达了请求体的格式,常见的格式有三种

第一种

application/json 是上面已经看到过了 json 格式


第二种

application/x-www-form-urlencoded 格式,

其中有一个单词 urlencoded,表示请求体的数据格式跟 url 地址里面问号后   ? 属性名=属性值&属性名=属性值    后面的格式是一样的

POST /api/user/login HTTP/1.1
Host: study.duyiedu.com
Content-Type: application/x-www-form-urlencoded

loginId=ruyiccom&loginPwd=123123


第三种

multipart/form-data 格式一般用做文件上传(md文档)

Content-Type: multipart/form-data; boundary=aaa

--aaa
Content-Disposition: form-data; name="loginId"

admin
--aaa
Content-Disposition: form-data; name="loginPwd"

123456
--aaa
Content-Disposition: form-data; name="avatar"; filename="small.jpg"
Content-Type: image/jpeg

文件的二进制
--aaa--


4、第三种格式 multipart/form-data

该格式的请求体是由很多部分,分割而成的

1. 使用分割符 --aaa  进行分割

2. 分割符可以自定义,看请求头后半部分   Content-Type: multipart/form-data; boundary=aaa  


比如,用户登陆需要传两个数据 loginId 和 loginPwd 

1. --aaa 下面写第一个数据 loginId

2. --aaa  然后下面写第二个的数据 loginPwd

3. 然后没有了 --aaa-- 表示结束

POST /api/user/login HTTP/1.1
Host: study.duyiedu.com
Content-Type: multipart/form-data; boundary=aaa

--aaa
第一个数据loginId

--aaa
第二个数据loginPwd

--aaa--


loginId 用户 id 的写法

1. Content-Disposition: form-data; 前面是固定写法

2. name="loginId" 后面是服务器接收数据时候要的属性名

3. 下面的 ruyiccom 是属性值

POST /api/user/login HTTP/1.1
Host: study.duyiedu.com
Content-Type: multipart/form-data; boundary=aaa

--aaa
Content-Disposition: form-data; name="loginId";

ruyiccom 
--aaa
Content-Disposition: form-data; name="loginPwd";

123456
--aaa--


5、使用 multipart/form-data 格式上传一个文件

multipart/form-data 格式可以上传二进制文件数据


服务器不需要传用户名和密码,只传一个图片文件

POST /my-code/upload/single.php HTTP/1.1
Host: localhost
Content-Type: multipart/form-data; boundary=aaa

--aaa
Content-Disposition: form-data; name="avatar";
filename="img247635499.jpg"
Content-Type: image/jpeg

< ./img247635499.jpg
--aaa--

文件上传的本质就是一个网络通信,按照指定格式的要求把文件发过去,然后服务器响应一个结果

1. /my-code/upload/single.php   文件上传的请求行路径

    localhost  服务器是本地主机,端口默认 80

2. Content-Disposition: form-data;   前面是固定

    name="avatar"   后面的表示服务器要的属性名是 avatar(要服务器配合

3. 还有一些附加信息

    filename="img247635499.jpg"   表示告诉服务器文件的后缀名,一般写本地要上传的文件名

    Content-Type=image/jpeg   表示图片的类型,跟上面 filename 后缀名 .jpg 是对应的,这种 image/jpeg 写法表示 MIME 类型

4. 属性值是图片,图片文件是二进制,

    在文本编辑器里面写不了二进制数据,写出来什么都是文本  0101 的数字 ,

    插件 REST Client 帮我们搞的,可以用特殊的符号 < 后面写文件的路径,既 < ./img247635499.jpg


MIME 类型是标准字符串描述属性类型,意思是用一个字符串来描述数据类型

MIME 类型

数据类型

text/javascript 或 application/javascript

描述 js 代码
text/css描述 css 代码
text/plain普通的纯文本
text/html描述 html 文档
image/jpeg描述 jpg 图片
image/png
image/gif
application/jsonjson 格式的数据
attachment附件
其他 MIME 类型

 

5、响应消息的字符串格式

响应也是三部分

请求行

请求头

请求体 

HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Wed, 02 Oct 2024 10:37:52 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 110
Connection: keep-alive
Vary: Origin
Accept-Ranges: bytes
authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2ZjUzMzM4NWY4Y2M3MGM4YTM3ZTM4YSIsImlhdCI6MTcyNzg2NTQ3MiwiZXhwIjoxNzI4NDcwMjcyfQ.byacBHSuLIrySfKx2INgKR3Qa2mWLRQ7Y7hysAWMnw0
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
x-download-options: noopen
x-readtime: 7

{
  "code": 0,
  "msg": "",
  "data": {
    "id": "66f533385f8cc70c8a37e38a",
    "loginId": "ruyiccom",
    "nickname": "远远的地方"
  }
}


响应码

响应行关注这个  200 OK 

一数字 200,一个单词 OK,一般是对应的,

该响应码表达的意思是,先汇总的说一下这次响应是一个什么情况,相当于用非常简短的化描述目前的情况


常见的响应码

1**、2**、3** 都是表示没问题

分类描述用法
1**信息,服务器收到请求,需要请求者继续执行操作

服务器也收到请求了,也做出了响应,但是还没有完,浏览器还要继续发一些别的请求,

比如请求升级的协议、续传等

2**成功,一般表示请求成功

最常见的是 200 ok

3**

也是成功,表示重定向

你访问的地址现在没了,请你到另外一个地址去找

301 资源永久重定向

302 临时重定向

4**客户端错误请求的语法错误或无法完成请求
5**服务器错误服务器在处理请求的过程中发生了错误


常见的状态码

 200 OK 

一切正常


 301 Moved Permanently 

资源已被永久重定向


永久重定向的意思是,

你的请求我收到了,但是你要的东西不在这个地址了,

我已经永远的把它移动到了一个新的地址,麻烦你去请求新的地址,

而且以后永远不要来了,地址我放到了响应头的 Location 属性中了


比如请求斗鱼

先设置一下插件,不然自动重新定向

1. 搜索 rest redirect

2. 找到 Rest-clinet:Followredirect

3. 去掉勾 Follow HTTP 3xx responses as redirects.

POST / HTTP/1.1
Host: www.douyutv.com

得到 301 重定向,并且在头里面告诉资源永久的移动到另外的地址

HTTP/1.1 301 Moved Permanently

location: https://www.douyu.com


 302 Found 

资源已被临时重定向


你的请求我收到了,

但是呢,意思是最近正在装修,你要的东西不在这个地址了,

我临时的把它移动到了一个新的地址,麻烦你取请求新的地址,

地址我放到了请求头的 Location 中了,

说不定以后东西又放回来了


区别只是语义不同,

但是 301 永久重定向,浏览器会记住,今后在用户在请求,直接请求新地址


 304 Not Modified 

文档内容未被修改(会涉及到缓存)


你的请求我收到了,

你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。

啥?你没有缓存以前的内容,关我啥事


 400 Bad Request 

语义有误

服务器说,我看不懂你给我发的信息,我听不懂你发过来的是什么


4** 开头的一般都是客户端的错误,但也不一定真的的是客户端错误,服务器程序是可以改的,

后端在服务器的全局错误里面,可以这样写,无论发生什么错误,响应的错误吗都是 400,

try{


}catch{

  res.code = 400

}


 403 Forbidden 

表示服务器拒绝执行,

你的请求我已收到,但是你没有权限,我就是不给你东西


 404 Not Found  

表示资源不存在,

这是最常见的,你的请求我收到了,但我没有你要的东西


 500 Internal Server Error   

服务器报错了,它也不知道怎么回事,客户端那边收到 500,5** 开头的一般是服务器的错误


但是服务器到底发什么响应码,完全是被服务器控制的

比如用户注册失败,很多公司的做法是

1. 响应行全是 200 ok

2. 错误码实际是放在响应体里面的 code: 400

HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Sat, 28 Sep 2024 05:58:25 GMT
Content-Type: application/json
Content-Length: 48
Connection: keep-alive
Vary: Origin
Accept-Ranges: bytes

{
  "code": 400,
  "msg": "账号已存在",
  "data": null
}


响应头

响应头只需要关注一个 Content-Type 属性,它表示响应体里面是什么格式,跟请求头里面是一样的


比如表示响应体是一个 json 格式的字符串

Content-Type: application/json


比如请求百度试试

GET / HTTP/1.1
Host: baidu.com

Content-Type: text/html  表示请求体里面是一个 html 文档


在请求一张图片

GET /blog/uploads/image/202311/169936706514263.jpg HTTP/1.1
Host: ruyic.com

请求体当成文件渲染了

保存为 .http 文件,是响应的原始格式

拖进 vscode 打开,仍然打开

选文本编辑器打开

响应头里面有 Content-Type: image/jpeg


请求 css 文件,表示响应体是 css 格式

Content-Type: text/css; charset=UTF-8


6、思考题

根据这节课学到的知识,思考一个问题:如果不使用浏览器,是否能够完成页面浏览?


四、课后回答的一些问题

三次握手,四次挥手


我们的原始消息是请求体或响应体,应用层加 行 和 头 后交给传输层,

传输层用 TCP 协议,

TCP 要进行三次握手和四次挥手


我们可以把 TCP 想象成打电话,电话过去先不着急说正事,先连接的建立(三次挥手

客户端:喂能听见吗 

服务器:能听见你说话,你能听见我说话吗

客户端:我也能听见你说话


三次握手后联通了后,才正式发送 HTTP 协议的消息

请求 - 响应”完后要挂电话了,

挂电话是四次挥手


连接的销毁(四次挥手)

开始

客户端:我说完了,现在可以挂电话吗

服务器:我知道你说完了,先别忙着挂,我还有话要说

服务器继续说...,说完后,

服务器:我也说完了,可以挂了吗?

客户端:好的,可以挂了

结束


只要 TCP 协议连接,就是双方电话打通了,

HTTP 协议就可以随时通信了,

只要一方不挂电话,HTTP 协议就永远“请求-响应”的通信下去


哈希

http://abc.con/xxx#/header

哈希改变的是 /header 


最早的时候哈希是做锚连接的

点击 <a href="#/header1">header</a> 改变了哈希

页面自动滑到 <h1 id="/header1">标题1</h1>


单页应用框架

#/header 想要跳转某一个组件,

就跟页面上的一个  id="/header"  就造成了冲突


所以 

官方推出 H5: history api 

它可以改变地址的路径,浏览器也不刷新



Leave a comment 0 Comments.

Leave a Reply

换一张