网络课件
对于前端而言,网络部分代码不多,以概念为主。
对概念的理解程度,决定了是否能够看懂接口文档,同时也决定了是否能更好的掌控网络相关代码。
# 网络基本概念
# 客户端和服务器
在网络的世界里,两个应用程序之间会经常发生通信。
在大部分情况下,通信总是由一方发出一个消息开始,而另一方回复一个消息结束。
发出消息的一方称之为客户端 Client,发出消息的过程称之为请求 Request。
回复消息的一方称之为服务器 Server,回复消息的过程称之为响应 Response
这个过程中,有几个点需要特别注意:
不管是客户端,还是服务器,它们都是一个应用程序,而不是一台计算机。客户端和服务器可以分布在不同的计算机上,也可以在同一台计算机上,并不需要特殊看待。
比如我们之前接触的 live server 插件,就是一个服务器,它运行在本地的计算机上。
大部分后端开发的就是服务器程序,前端的 Node 技术也能开发服务器程序。
客户端和服务器的这种交互模式称之为「经典 C/S 结构」。在这种结构中,如果客户端是浏览器,则我们称之为 B/S 结构。
服务器程序往往是为互联网产品提供服务,因此又称之为 web 服务器。
一次完整的交互,总是从请求开始,响应结束。
# 作业
请描述什么叫做服务器、客户端、请求、响应、C/S、B/S
# url
要完成一次请求和响应,首先需要让客户端找到服务器,不仅如此,还要找到服务器上我们想要的资源。
在现实生活中,如果我们要找一个人,我们可以通过一个地址来找到他。
和现实生活类似,在互联网中,我们可以通过一个叫 url 地址 的东西找到我们想要的资源。
url 全称 uniform resource locator,统一资源定位符。它是一个字符串,用于表达互联网中某个资源的位置。
url 地址示例:
- 百度首页的 url 地址:https://www.baidu.com/
- 某篇新闻页面的 url 地址:https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_9610068257663826418%22%7D&n_type=-1&p_from=-1
- 某知名 css 的 url 地址:https://meyerweb.com/eric/tools/css/reset/reset.css
- 某知名 js 的 url 地址:https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
- 某张图片的 url 地址:https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fedpic_source%2F84%2F87%2F80%2F848780a296b66b382018fa7f675ecd06.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1652600873&t=803c81d81387ec5f9fd1d92ba9d7665a
url 地址可以很长,也可以很短。
通过 url 地址可以找到互联网上的资源,它可以是页面、图片、视频、音频、css 代码、js 代码、可供下载的文件、或者其他任何东西。
一个完整的 url 地址由多个部分组成
完整的url地址
协议 + 主机 + 端口 + 路径 + 参数 + hash
示例:
# 协议 Protocal / Schema
它表示客户端希望用什么方式和服务器沟通,现在只需要知道这里固定写 http 或 https 即可
小知识:
- 如果在浏览器的地址栏省略了协议,浏览器会自动为你补全
- 可以在 Chrome 浏览器的地址栏点击右键,显示完整的地址
- https 协议比 http 协议更安全,但往往出现在线上,本地的服务器通常不会是 https
# 主机 Host
它表示客户端希望在哪台计算机上寻找资源
这里有两种写法:IP 地址和域名
IP 地址。IP 地址是一个网络中计算机的唯一编号,通常,一个 IP 对应一台计算机。
记住特殊 IP 地址: 127.0.0.1,它表示本机 IP
域名。域名类似 IP 地址的别名,把不容易记忆的数字变为容易记忆的单词。当使用域名访问时,会自动转换为 IP 地址。
记住特殊域名:localhost,它表示的 IP 地址是 127.0.0.1
# 端口 Port
它表示客户端希望在哪个应用程序中寻找资源
每个服务器程序,都会监听一个或多个端口,只有找到对应的端口,才能找到这个服务器程序。
端口号是可选的,若不填写,则:
- 如果使用的是 http 协议,默认端口号为 80
- 如果使用的是 https 协议,默认端口号为 443
# 路径 Path
服务器上往往有许许多多的资源,每个资源都有自己的访问路径
路径是可选的,若不填写,则路径为 /
# 参数 Query / Param
某些资源可以根据需要呈现不同的内容,比如一篇新闻列表的页面,可以指定它呈现第几页的新闻,而「第几页」就属于一些额外信息,这些额外信息可以通过参数传递
比如,我们访问一个新闻列表的页面,同时希望它展示第 5 页,每页展示 10 条新闻,我们可能得到下面的 url 地址:
http://duyiedu.com/news?page=1&limit=10
上面这个 url 地址中,page=1&limit=10
就是参数部分,这部分可以包含多个参数,不同的参数之间使用&
符号分割
参数是可选的
# hash
在网络通信中,hash 没有什么用,它往往作为浏览器的锚链接出现。
# 作业
写出下面 url 地址中每部分的值
- http://www.duyiedu.com
- http://news.baidu.com/guonei
- https://baijiahao.baidu.com/s?id=1730140517646479713&wfr=spider&for=pc
根据下面的需求,写出 url 地址
本地有一个服务器应用正在运行,它监听了 5500 端口,在根路径下访问 index.html 可以得到首页的内容。
请写出首页完整的 url 地址
阅读下面接口文档地址的内容,写出对应的 url 地址
- 省市区接口 (opens new window)
- 热门电影接口 (opens new window),得到第 7 页,每页 22 条数据
# http
通过 url 地址,能够在茫茫互联网中准确的找到自己想要的服务。
但光找到服务还是不够,双方需要「用同一种语言」来对话,否则都听不懂对方在说什么。
这个「语言」就是协议,而互联网中最常见的协议就是 http 协议
https 是在 http 协议基础上发展起来的,它增加了安全性,其他和 http 协议完全一致
http 是基于 请求-响应 的方式完成通信的,每一次通信都是由客户端向服务器发出请求,传递一些消息过去,然后经过服务器程序处理后,响应给客户端一些消息。
http 协议规定:
每次 请求-响应 都是独立的,相互之间互不干扰。这种模式的协议我们称之为无状态协议
http 的无状态会带来一些问题,这些问题我们会在后续的课程中讨论
每次 请求-响应 传递的消息都是纯文本(字符串),而且文本格式必须按照 http 协议规定的格式书写。
# 请求的消息格式
请求消息格式有三部分组成
- 请求行:高度概括了客户端想要干什么
- 请求头:描述了请求的一些额外信息
- 请求体:包含了要给服务器传递的正文数据。请求体是可以省略的
# 请求行
请求行是整个 http 报文的第一行字符串,它包含三个部分:请求方法 路径+参数+hash 协议和版本
重点关注请求方法
请求方法是一个单词,它表达了客户端的「动作」,比如:
- GET:获取
- POST:提交
在 http 协议中,并没有规定只能使用上面两种动作,甚至没有规定每种动作会带来怎样的变化
而在实际的应用中,我们逐渐有了一些约定俗成的规范:
- 动作通常有:GET(获取资源)、POST(提交消息)、PUT(修改数据)、DELETE(删除数据)。其中,GET 和 POST 最为常见。
- GET 和 DELETE 请求不能有请求体,而 POST 和 PUT 请求可以有请求体
**浏览器遵循了上面的规范,这带来了 GET 和 POST 的诸多区别。**比如,由于 GET 请求没有请求体,所以要传递数据只能把数据放到 url 的参数中
在浏览器中,获取数据一般使用的都是 GET 请求,比如:
- 在地址栏输入地址并按下回车
- 点击了某个 a 元素
- 获取图片、音频、视频
- 获取 css、js、字体等文件
事实上,浏览器自动发出的请求基本都是 GET 请求,而 POST 请求需要开发者手动处理,比如在 form 表单中设置 method 为 POST
# 请求头 header
请求头是一系列的键值对,里面包含了诸多和业务无关的信息
浏览器每次请求服务器都会自动附带很多的请求头,其实这些请求头大部分服务器是不需要的
你可以说不要,但不能说我没给
我们只需关注下面几个请求头即可:
Host:url 地址中的主机
User-Agent:客户端的信息描述
Content-Type: 请求体的消息是什么格式,如果没有请求体,这个字段无意义
该字段的常见取值为:
application/x-www-form-urlencoded
表示请求体的数据格式和 url 地址中参数的格式一样,比如
loginId=admin&loginPwd=123123
application/json
表示请求体的数据是 json 格式,比如
{ "loginId": "admin", "loginPwd": "123123" }
multipart/form-data
一种特殊的请求体格式,上传文件一般选择该格式
# 请求体 body
包含业务数据的字符串
理论上,请求体可以是任意格式的字符串,但习惯上,服务器普遍能识别以下格式:
- application/x-www-form-urlencoded:
属性名=属性值&属性名=属性值...
- application/json:
{"属性名":"属性值", "属性名":"属性值"}
- multipart/form-data:使用某个随机字符串作为属性之间的分隔符,通常用于文件上传
由于请求体格式的多样性,服务器在分析请求体时可能无法知晓具体的格式,从而不知道如何解析请求体,因此,服务器往往要求在请求头中附带一个属性Content-Type
来描述请求体使用的格式
例如
Content-Type: application/x-www-form-urlencoded
Content-Type: application/json
Content-Type: multipart/form-data
# 响应的消息格式
服务器(通常由后端开发)收到请求的消息后,会运行后端代码对请求进行处理,处理完成后,会给予响应。
服务器的响应格式包含三个部分
# 响应行
响应行是整个响应字符串的第一行。
响应行包含两个部分:
- 协议版本:表示服务器打算和客户端用什么协议通信
- 状态码、状态消息:表示服务器对当前请求的表态
通常,状态码和状态消息是一一对应的,比如状态码 200 的消息就是 OK
不同的请求可能会得到不同的状态码,至于到底会得到哪个状态码,由后端程序决定。
状态码分为五类:
分类 | 分类描述 |
---|---|
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
通常认为,0~399 之间的状态码都是正常的,其他是不正常的
常见的状态码有:
200 OK:一切正常。
301 Moved Permanently:资源已被永久重定向。
你的请求我收到了,但是呢,你要的东西不在这个地址了,我已经永远的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了响应头的Location中了
302 Found:资源已被临时重定向。
你的请求我收到了,但是呢,你要的东西不在这个地址了,我临时的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了
304 Not Modified:文档内容未被修改。
你的请求我收到了,你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。啥?你没有缓存以前的内容,关我啥事
400 Bad Request:语义有误,当前请求无法被服务器理解。
你给我发的是个啥啊,我听都听不懂
403 Forbidden:服务器拒绝执行。
你的请求我已收到,但是我就是不给你东西
404 Not Found:资源不存在。
你的请求我收到了,但我没有你要的东西
500 Internal Server Error:服务器内部错误。
你的请求我已收到,但这道题我不会,解不出来,先睡了
# 响应头 header
和请求头一样,响应头也是由很多个键值对组成的,具体有哪些键值对,完全取决于服务器程序
目前,对我们最重要的键值对是Content-Type
,它有多种取值,表示响应体的数据类型。
在 B/S 模式中,浏览器会自动根据响应头中Content-Type
的取值,决定如何处理响应体。
text/plain
: 普通的纯文本,浏览器通常会将响应体原封不动的显示到页面上text/html
:html 文档,浏览器通常会将响应体作为页面进行渲染text/javascript
或application/javascript
:js 代码,浏览器通常会使用 JS 执行引擎将它解析执行text/css
:css 代码,浏览器会将它视为样式image/jpeg
:浏览器会将它视为 jpg 图片attachment
:附件,浏览器看到这个类型,通常会触发下载功能- 其他
MIME
类型
# 响应体 body
响应的主体内容
# 作业
- 使用 postman 向
http://www.douyutv.com
发送 GET 请求,回答下面的问题:- 状态码是什么?表达了什么含义?
- 响应头中的 Location 的值是什么?表达了什么含义?
- 使用 postman 向
https://www.taobao.com
发送 GET 请求,回答下面的问题:- 响应头中的
Content-Type
的值是什么?表达了什么含义?
- 响应头中的
- 阅读注册接口文档 (opens new window),使用 postman 完成下面的作业:
- 随意使用错误的消息内容请求注册接口,观察请求头中的 Content-Type、请求体、响应的状态码、响应体、响应头中的 Content-Type
- 使用正确的消息内容请求注册接口,观察请求头中的 Content-Type、请求体、响应的状态码、响应体、响应头中的 Content-Type
# 浏览器页面处理流程
当在浏览器地址栏中输入一个 url 地址,并按下回车后,会发生什么?
试试这个地址:oss.duyiedu.com/test/index.html
# AJAX
AJAX 就是浏览器赋予 JS 的一套 API,通过这套 API 能够使 JS 具备网络通信的能力
# 历史
浏览器本身就具备网络通信的能力,但在早期,浏览器并没有把这个能力开放给 JS。
最早是微软在 IE 浏览器中把这一能力向 JS 开放,让 JS 可以在代码中实现发送请求,这项技术在 2005 年被正式命名为 AJAX(Asynchronous Javascript And XML)
IE 使用了一套 API 来完成请求的发送,这套 API 主要依靠一个构造函数完成。该构造函数的名称为XMLHttpRequest
,简称为XHR
,所以这套 API 又称之为XHR API
由于XHR API
有着诸多缺陷,在 HTML5 和 ES6 发布之后,产生了一套更完善的 API 来发送请求。这套 API 主要使用的是一个叫做fetch
的函数,因此这套 API 又称之为Fetch API
无论是XHR
还是Fetch
,它们都是实现 ajax 的技术手段,只是 API 不同。
# XHR API
var xhr = new XMLHttpRequest(); //创建发送请求的对象
xhr.onreadystatechange = function () {
//当请求状态发生改变时运行的函数
// xhr.readyState: 一个数字,用于判断请求到了哪个阶段
// 0: 刚刚创建好了请求对象,但还未配置请求(未调用open方法)
// 1: open方法已被调用
// 2: send方法已被调用
// 3: 正在接收服务器的响应消息体
// 4: 服务器响应的所有内容均已接收完毕
// xhr.responseText: 获取服务器响应的消息体文本
// xhr.getResponseHeader("Content-Type") 获取响应头Content-Type
};
xhr.open('请求方法', 'url地址'); //配置请求
xhr.setRequestHeader('Content-Type', 'application/json'); //设置请求头
xhr.send('请求体内容'); //构建请求体,发送到服务器,如果没有请求体,传递null
# Fetch API
const resp = await fetch('url地址', {
// 请求配置对象,可省略,省略则所有配置为默认值
method: '请求方法', // 默认为GET
headers: {
// 请求头配置
'Content-Type': 'application/json',
a: 'abc',
},
body: '请求体内容', // 请求体
}); // fetch会返回一个Promise,该Promise会在接收完响应头后变为fulfilled
resp.headers; // 获取响应头对象
resp.status; // 获取响应状态码,例如200
resp.statusText; // 获取响应状态码文本,例如OK
resp.json(); // 用json的格式解析即将到来的响应体,返回Promise,解析完成后得到一个对象
resp.text(); // 用纯文本的格式解析即将到来的响应体,返回Promise,解析完成后得到一个字符串
# 特别注意
无论使用哪一种 API,AJAX 始终都是异步的
在初学的时候,可以把网络传输的时间想象的夸张一点,比如每一次请求和响应都要经过一年才能完成。这样有助于理解网络是异步这一点
# 附录
# PostMan
下载地址:https://www.postman.com/downloads/
安装后需要跟随课程做一些配置以便更好的学习老师的课程
# 常见问题
# 跨域错误
这个错误通常发生在 AJAX 请求的时候,是一个跨域错误,这里需要了解什么叫跨域。
浏览器为了安全,制定了一个规则,即页面的源和请求目标的源应该保持一致,如果不一致,就产生了跨源或者叫跨域。
源 = 协议 + 主机 + 端口
比如:
页面源 | 目标源 | 是否跨域 |
---|---|---|
https://baidu.com/news.html | http://103.231.13.42/1.jpg | 是 |
https://www.baidu.com/news.html | http://baidu.com:8080/1.jpg | 是 |
https://baidu.com/news.html | https://baidu.com/1.jpg | 否 |
- 浏览器对 img、link、script 的限制比较宽松,一般允许跨域
- 浏览器对 AJAX 比较严格,一般不允许跨域
浏览器对跨域行为作出的不同限制,统称为同源策略
如果在 AJAX 中出现跨域请求,就会报出以上错误。
但如果服务器明确告知浏览器允许跨域,则浏览器会允许 AJAX 跨域请求。
# 404 错误
浏览器请求某个资源,但服务器响应了一个 404 状态码,就会在控制台中报出这个错误。与此同时,你可以在浏览器的网络调试中进一步观察到这个错误。
404 错误是一种非常常见的错误,它表示服务器告诉客户端:你要的资源并不存在
要解决这个错误,首先要检查请求的 url 地址是否正确。如果 url 地址正确,则可能是服务器的问题,需要联系后端开发人员或者将问题上报
# favicon
报错内容:加载资源失败:服务器响应了 404 状态码
请求地址::5500/favicon.ico
原因:
很多浏览器在解析页面后,如果发现页面中并没有使用link
元素加载站点图标,会尝试请求以下地址来获取图标:
站点协议://站点主机:站点端口/favicon.ico
如果这个地址无法获得图标,就会报出相应错误
该错误会在下一次刷新后消失,是因为再次刷新后,浏览器记忆了之前无法获取图标的情况,就不再发出请求了。
# 其他问题
网络断开,检查你的网络连接,或者检查你是否在调试工具中进行了网络断开调试
访问的域名不存在,无法连接到服务器