Ajax
前端数据请求方式
前后端分离的优势
- 早期的网页都是通过后端渲染来完成的:服务器端渲染(SSR,server side render):
- 客户端发出请求 -> 服务端接收请求并返回相应 HTML 文档 -> 页面刷新,客户端加载新的 HTML 文档;
- 服务器端渲染的缺点:
- 当用户点击页面中的某个按钮向服务器发送请求时,页面本质上只是一些数据发生了变化,而此时服务器却要将重绘的整个页面再返回给浏览器加载,这显然有悖于程序员的“DRY( Don‘t repeat yourself )”原则;
- 而且明明只是一些数据的变化却迫使服务器要返回整个 HTML 文档,这本身也会给网络带宽带来不必要的开销。
- 有没有办法在页面数据变动时,只向服务器请求新的数据,并且在阻止页面刷新的情况下,动态的替换页面中展示的数据呢?
- 答案正是“AJAX”。
- AJAX 是“Asynchronous JavaScript And XML”的缩写(异步的 JavaScript 和 XML),是一种实现 无页面刷新 获取服务器数据的技术。
- AJAX 最吸引人的就是它的“异步”特性,也就是说它可以在不重新刷新页面的情况下与服务器通信,交换数据,或更新页面。
- 你可以使用 AJAX 最主要的两个特性做下列事:
- 在不重新加载页面的情况下发送请求给服务器;
- 接受并使用从服务器发来的数据。
服务器端渲染
前后端分离
HTTP
什么是 HTTP
- 什么是 HTTP 呢?我们来看一下维基百科的解释:
- 超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议;
- HTTP 是万维网的数据通信的基础,设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法;
- 通过 HTTP 或者 HTTPS 协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识;
- HTTP 是一个客户端(用户)和服务端(网站)之间请求和响应的标准。
- 通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个 HTTP 请求到服务器上指定端口(默认端口为 80);
- 我们称这个客户端为用户代理程序(user agent);
- 响应的服务器上存储着一些资源,比如 HTML 文件和图像。
- 我们称这个响应服务器为源服务器(origin server);
- 通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个 HTTP 请求到服务器上指定端口(默认端口为 80);
网页资源的获取
- 我们网页中的资源通常是被放在 Web 资源服务器中,由浏览器自动发送 HTTP 请求来获取、解析、展示的。
- 目前我们页面中很多数据是动态展示的:
- 比如页面中的数据展示、搜索数据、表单验证等等,也是通过在 JavaScript 中发送 HTTP 请求获取的;
HTTP 的组成
- 一次 HTTP 请求主要包括:请求(Request)和响应(Response)
HTTP 的版本
- HTTP/0.9
- 发布于 1991 年;
- 只支持 GET 请求方法获取文本数据,当时主要是为了获取 HTML 页面内容;
- HTTP/1.0
- 发布于 1996 年;
- 支持 POST、HEAD 等请求方法,支持请求头、响应头等,支持更多种数据类型(不再局限于文本数据) ;
- 但是浏览器的每次请求都需要与服务器建立一个 TCP 连接,请求处理完成后立即断开 TCP 连接,每次建立连接增加了性能损耗;
- HTTP/1.1(目前使用最广泛的版本)
- 发布于 1997 年;
- 增加了 PUT、DELETE 等请求方法;
- 采用持久连接(Connection: keep-alive),多个请求可以共用同一个 TCP 连接;
- 2015 年,HTTP/2.0
- 2018 年,HTTP/3.0
HTTP 的请求方式
- 在 RFC 中定义了一组请求方式,来表示要对给定资源执行的操作:
- GET:GET 方法请求一个指定资源的表示形式,使用 GET 的请求应该只被用于获取数据。
- HEAD:HEAD 方法请求一个与 GET 请求的响应相同的响应,但没有响应体。
- 比如在准备下载一个文件前,先获取文件的大小,再决定是否进行下载;
- POST:POST 方法用于将实体提交到指定的资源。
- PUT:PUT 方法用请求有效载荷(payload)替换目标资源的所有当前表示;
- DELETE:DELETE 方法删除指定的资源;
- PATCH:PATCH 方法用于对资源应部分修改;
- CONNECT:CONNECT 方法建立一个到目标资源标识的服务器的隧道,通常用在代理服务器,网页开发很少用到。
- TRACE:TRACE 方法沿着到目标资源的路径执行一个消息环回测试。
- 在开发中使用最多的是 GET、POST 请求;
- 在后续的后台管理项目中,我们也会使用 PATCH、DELETE 请求;
HTTP Request Header
- 在 request 对象的 header 中也包含很多有用的信息,客户端会默认传递过来一些信息:
content-type 是这次请求携带的数据的类型:
- application/x-www-form-urlencoded:表示数据被编码成以 ‘&’ 分隔的键 - 值对,同时以 ‘=’ 分隔键和值
- application/json:表示是一个 json 类型;
- text/plain:表示是文本类型;
- application/xml:表示是 xml 类型;
- multipart/form-data:表示是上传文件;
content-length:文件的大小长度
keep-alive:
- http 是基于 TCP 协议的,但是通常在进行一次请求和响应结束后会立刻中断;
- 在 http1.0 中,如果想要继续保持连接:
- 浏览器需要在请求头中添加 connection: keep-alive;
- 服务器需要在响应头中添加 connection:keey-alive;
- 当客户端再次放请求时,就会使用同一个连接,直接一方中断连接;
- 在 http1.1 中,所有连接默认是 connection: keep-alive 的;
- 不同的 Web 服务器会有不同的保持 keep-alive 的时间;
- Node 中默认是 5s 中;
accept-encoding:告知服务器,客户端支持的文件压缩格式,比如 js 文件可以使用 gzip 编码,对应 .gz 文件;
accept:告知服务器,客户端可接受文件的格式类型;
user-agent:客户端相关的信息;
HTTP 响应状态码
- Http 状态码(Http Status Code)是用来表示 Http 响应状态的数字代码:
- Http 状态码非常多,可以根据不同的情况,给客户端返回不同的状态码;
- MDN 响应码解析地址:https://developer.mozilla.org/zh-CN/docs/web/http/status
HTTP Response Header
- 响应的 header 中包括一些服务器给客户端的信息:
Ajax 简介
- AJAX 全称为 Asynchronous Javascript And XML,就是异步的 JS 和 XML。
- 通过 AJAX 可以在浏览器中向服务器发送异步请求, 最大的优势:页面无刷新获取数据。
- AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
XML 简介
- XML : 可扩展标记语言。
- XML 被设计用来传输和存储数据。
- XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。
1 | <!-- 例如: 用XML表示一个学生数据 --> |
1 | // 现在已经被JSON取代了 |
Ajax 的优缺点
优点
- 可以无需刷新页面而与服务器端进行通信。
- 允许你根据用户事件来更新部分页面内容。
缺点
- 没有浏览历史,不能回退;
- 存在跨域问题;
- SEO 搜索引擎优化不友好; 比如:爬虫爬不到,但不是绝对爬不到
Ajax 的基本使用
核心对象
- XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。
搭建测试服务器
- 项目初始化:
1 | npm init -y |
- 安装 express
1 | npm install express |
- 搭建测试服务器
1 | const express = require('express') |
- 启动服务器
1 | node server.js |
- nodemon 工具的使用
01 安装: npm install nodemon
02 用 nodemon 启动服务 : nodemon server.js
使用步骤
- server.js : 暴露静态资源,不用考虑跨域问题
- 访问方式:
http://127.0.0.1:8080/01_ajax小试牛刀.html
1 | // 引入 express |
- 使用步骤
- 需求: 点击按钮,发起 ajax 请求,将返回的数据放到 div 中
1 | <body> |
XHR 的 5 种状态
- xhr 内部有 5 种状态,值分别为:0、1、2、3、4
- 0: 实例出来的那一刻状态就是 0,初始状态。
- 1:open 已经调用了,但是 send 还没有调用,此时可以修改请求头内容。
- 2:send 已经调用了,已经无法修改请求头
- 3:已经回来一部分数据了,小的数据会在此阶段一次性接收完毕,较大的数据有待进一步接收,响应头已经回来了。
- 4:数据全部接收完毕
1 | // 4. 接收响应 |
Ajax 请求携带参数
get 请求携带参数
携带 query 参数
- 客户端发请求时携带 query 参数:
- 形如:key=value&key=value 就是 query 参数的 urlencoded 编码形式
1 | // 2. 指定发送请求的 method url 参数 |
- 服务端 server.js 响应请求时获取到请求携带的 query 参数:
- 形如:/xx/xxx/老刘/18 就是 params 参数
1 | // 响应 get 请求 |
携带 params 参数
- 客户端发请求时携带 params 参数:
1 | // 2. 指定发送请求的 method url 参数 |
- 服务端 server.js 响应请求时获取到请求携带的 params 参数:
1 | // 响应 get 请求 |
post 请求携带参数
携带 query 参数
- 客户端发请求时携带 query 参数:
1 | // 2. 指定发送请求的 method url 参数 |
- 服务端 server.js 响应请求时获取到请求携带的 query 参数:
1 | // 响应 post 请求 |
携带 params 参数
- 客户端发请求时携带 params 参数:
1 | // 2. 指定发送请求的 method url 参数 |
- 服务端 server.js 响应请求时获取到请求携带的 params 参数:
1 | // 响应 post 请求 |
携带请求体参数(1)
- 客户端发请求时携带 urlencoded 形式的 请求体 参数:
1 | // 2. 指定发送请求的 method url 参数 |
- 服务端 server.js 响应请求时获取到请求携带的 urlencoded 形式的 请求体 参数:
1 | // 使用中间件解析 urlencoded 编码形式的请求体参数 |
携带请求体参数(2)
- 客户端发请求时携带 json 形式的 请求体 参数:
1 | // 2. 指定发送请求的 method url 参数 |
- 服务端 server.js 响应请求时获取到请求携带的 json 形式的 请求体 参数:
1 | // 使用中间件解析 json 编码形式的请求体参数 |
Ajax 解析 json 数据
- 客户端发请求
1 | // 获取DOM元素 |
- 服务端 server.js 响应请求,返回一个 json 形式的数据
1 | // 响应 get 请求 |
请求异常与超时处理
1 | // 获取DOM元素 |
取消请求
- 点击按钮取消请求:
1 | // 取消请求 需要将前面的按钮的 xhr 定义为一个全局变量 |
- 或者可以直接在 发送请求 后面直接 取消请求,
- 此时的状态是:
- 如果来得及取消请求,那么请求就到不了服务器
- 如果来不及取消请求,那么请求可以到达服务器,服务器作出响应,但是浏览器会拦截响应,使得响应回不到浏览器
1 | // 3. 发送请求 |
避免多次重复请求
1 | let xhr |
jQuery 封装的 ajax
jquery 发送 get 请求
- 完整写法
1 | const btn1 = $('#btn1') |
- 精简写法
1 | btn1.click(() => { |
- 服务端 server.js 响应请求
1 | // 响应 get 请求 |
jquery 发送 post 请求
- 完整写法
1 | btn2.click(() => { |
- 精简写法
1 | btn2.click(() => { |
- 服务端 server.js 响应请求
1 | // 使用中间件解析 urlencoded 编码形式的请求体参数 |
跨域和同源策略
为什么存在跨域问题
- 原因是浏览器为了安全,而采用的同源策略( Same origin policy )
- 跨越的产生: 存在跨越的情况下,浏览器的 ajax 引擎会对服务器返回的数据进行拦截
什么是同源策略
01 同源策略是由 Netscape 提出的一个著名的安全策略,现在所有支持 JavaScript 的浏览器都会使用这个策略
02 web 是构建在同源策略基础之上的,
浏览器只是针对同源策略的一种实现
03 所谓同源是指 : 协议 , 域名(IP),端口 必须要完全相同
- 即:协议、域名(IP)、端口都相同,才能算是在同一个域里,只要有一个或多个不同,就算跨域。
规则举例如下:(假设已有网站地址为:
http://study.cn
)
非同源受到的限制
- 01 Cookie 不能读取;
- 02 DOM 无法获得;
- 03 Ajax 请求能发送,但是浏览器不能获取到返回的数据
JSONP 解决跨域
JSONP 是什么
- JSONP (JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求。
JSONP 的实现原理
在网页有一些标签天生具有跨域能力,比如: img link iframe script 等标签发起的请求不受同源策略的限制。
JSONP 就是利用了 script 标签发送请求不受同源策略的限制的特点。
form xhr 浏览器地址栏 img script 标签,都是发起的请求都是 get 请求
利用 JSONP 绕开 xhr , 借助 script 标签发起请求,避免同源策略的限制
JSONP 解决跨域的过程
- 客户端点击按钮时发起请求,传递一个回调名传递给服务器
1 | <body> |
- 服务端 **server.js ** 作出响应,将传递来的回调,携带数据,返回给客户端
1 | // 响应 get 请求 |
jQuery 封装的 JSONP
- 客户端点击按钮时,调用 getJSON 方法, 发起请求
1 | <body> |
- 服务端 server.js 作出响应,将传递来的回调,携带数据,返回给客户端
1 | // 响应 get 请求 |
CORS 解决跨域
CORS 是什么
- CORS (Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持常见的所有请求
CORS 解决跨域
- 客户端仅发起请求,跨域问题在服务端解决
1 | <body> |
- 服务端 server.js 作出响应,并设置响应头解决跨越
1 | // 响应 get 请求 query参数 |
PUT 请求的跨域问题解决
- 客户端仅发起请求,跨域问题在服务端解决
1 | <body> |
- 服务端 server.js 作出响应,并设置响应头解决跨越,以及作出预请求的响应
- get / post 请求也叫简单请求
- put / delete 请求也叫复杂请求,在真正发起请求之前,会发起一个嗅探请求,也叫预请求
1 | // 响应 put 请求,并解决put请求的跨域 |
利用中间件解决跨域
- 安装 cors 中间件
1 | npm install cors |
- 服务端 server.js 使用中间件即可,无需其他配置
1 | // 1. 导入中间件 |
扩展
连续解构赋值
1 | // 连续解构赋值和重命名 |
浏览器的协商缓存
- 01 发起一次请求后,获得服务器返回的数据,返回的状态码为 200
- 02 当在 url 没变的情况下,再次发起请求,服务器接收到了请求,但是服务器数据也没变,此时返回的状态码为 304
- 03 此时浏览器就会走缓存,去拿上一次请求得来的数据
- (协商缓存大概过程:浏览器去问服务器,数据变了没有,服务器说数据没变,就返回 304 状态码,浏览器就去自己缓存里拿上一次的数据)
- 如果服务器的数据变了,就返回新的数据,响应状态码为 200
- 浏览器和服务器协商
- (协商缓存大概过程:浏览器去问服务器,数据变了没有,服务器说数据没变,就返回 304 状态码,浏览器就去自己缓存里拿上一次的数据)
- 除了 get / post / head 请求外,其他都算是复杂请求,复杂请求都会有一个预请求,预请求成功,才会发起真正的请求
IE 的 get 请求缓存问题
- IE 浏览器的强缓存机制:
- 发起一次请求后,获得服务器返回的数据, 返回的状态码为 200
- 当在 url 没变的情况下,再次发起请求,IE 浏览器会直接走缓存,服务器也收不到请求,即使服务器数据变了
- IE 会直接走缓存,不会再与服务器协商
- 解决方法:
- 可以在请求 url 后面携带参数, 比如:携带当前时间戳
1 | xhr.open('GET', 'http://127.0.0.1:8080/get_person?t=' + Date.now()) |
- IE 浏览器下的 post 请求不存在该问题
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自蜗牛浪迹天涯