AJAX
在网页中利用 XMLHttpRequest
对象和服务器进行数据交互的方式,就是Ajax
Ajax
能让我们轻松实现 网页 与 服务器之间的 数据交互
客户端与服务器
客户端概念:
在上网过程中,负责 获取和消费资源 的电脑,叫做客户端
服务器概念:
上网过程中,负责 存放和对外提供资源 的电脑,叫做服务器
上网的目的:
上网的**本质目的:**通过互联网的形式来 获取和消费资源
URL(统一资源定位符) 三部分
- 客户端与服务器之间的 通信协议 http
- 存有该资源的 服务器名称 www.xxx.com
- 资源在服务器上 具体的存放位置 /xxxxxx/xx/xxxx.html
客户端与服务器的通信过程
- 请求-处理-响应
网页中如何请求数据
最简单的用法 var xhrObj = new XMLHttpRequest()
资源的请求方式
客户端请求服务器时,请求的方式 有很多种,最常见的两种请求方式分别是 get
和 post
请求
-
get 请求
,通常用于 获取服务器资源(要资源)例如:根据
URL
地址,从服务器获取HTML
文件、css
文件、js
文件、图片文件、数据资源等 -
post 请求
,通常用于 向服务器提交数据(送资源)例如:登录时,向服务器 提交登录信息、注册时向服务器 提交注册信息、添加用户时向服务器 提交用户信息等各种 数据提交操作
监听Ajax请求
// 监听到Ajax请求被发起了
$(document).ajaxStart(function () {
// 执行代码
})
// 监听到 Ajax 完成的事件
$(document).ajaxStop(function () {
// 执行代码
})
Ajax
应用场景
场景一:用户名检测
注册用户时,通过 ajax
的形式,动态 检测用户名是否被占用
场景二:搜索提示
当输入搜索关键字时,通过 ajax
的形式,动态 加载搜索提示列表
场景三:数据分页显示
当点击页码值得时候,通过 ajax
的形式,根据页码值动态刷新表格的数据
场景四:数据的增删改查
数据的添加、删除、修改、查询操作,都需要通过 ajax
的形式,来实现数据的交互
jQuery
中的Ajax
$.get()
get方式请求,用于获取数据$.post()
post方式请求,用于提交数据$.ajax()
比较综合,既可以获取数据,又可以提交数据
$.get() 获取数据
getbooks
$.get(url, [data], [callback])
// url 要请求的资源地址
// data 请求资源期间要携带的参数
// callback 请求成功时的回调函数
$.get(url, { id:1 }, function(res){ console.log(res) })
// 相当于获取的数据里 id为1的那个 返回值 res
$.get()发起不带参数的请求
使用 $.get() 函数 发起不带参数的请求时,直接提供给 请求的 URL 地址 和 请求成功之后的回调函数 即可
$('#btnGET').on('click', function () {
$.get('http://ajax-base-api-t.itheima.net/api/getbooks', function (res) {
console.log(res);
})
})
$.get()发起携带参数的请求
使用$.get()
发起携带参数的请求,那么携带的参数应该写在第二个参数的位置
$('#btnGETINFO').on('click', function () {
$.get('http://ajax-base-api-t.itheima.net/api/getbooks', { id: 1 }, function (res) {
console.log(res)
})
})
$.get()删除图书
delbook
使用$.get()
发起删除请求,第二个参数的位置写要删除的id
$('#btnGETINFO').on('click', function () {
$.get('http://ajax-base-api-t.itheima.net/api/delbook', { id: 1 }, function (res) {
console.log(res)
})
})
$.post() 提交数据
addbook
jQuery
中 $.post()
函数的功能单一,专门用来发起post
请求,从而向服务器提交数据
$.post(url,[data],[callback])
// url 要提交到的数据地址
// data 要提交的数据 { }
// callback 提交成功时的回调函数
var obj = { bookname: '水浒传', author: '施耐庵', publisher: '天津图书出版社' }
$(function () {
$('#btnPOST').on('click', function () {
$.post('http://ajax-base-api-t.itheima.net/api/addbook', obj, function (res) {
console.log(res)
})
})
})
获取成功判断
res.status == 200 获取成功
res.status == 201 添加成功
$.ajax()
获取图书数据
$(function () {
$('#btnGET').on('click', function () {
$.ajax({
type: 'get', // get获取 post发送
url: 'http://ajax-base-api-t.itheima.net/api/getbooks',
success: function (res) {
console.log(res);
}
})
})
})
发送图书数据
$('#btnPOST').on('click', function () {
$.ajax({
type: 'POST',
url: 'http://ajax-base-api-t.itheima.net/api/addbook',
data: {
bookname: '老魏与驴',
author: '老魏说书',
publisher: '吹出天际出版社'
},
success: function (res) {
console.log(res);
}
})
})
获取机器人回复的消息
$.ajax({
type: 'get',
url: 'http://ajax-base-api-t.itheima.net/api/robot',
data: {
// 定义请求数据 spoken:value
spoken: text
// text 是你发送的消息 spoken 根据你的消息返回对应回复
},
success: function (res) {
// res.message == 'success' 代表成功获取
if (res.message == 'success') {
// res.data.info.text 是机器人回复的消息
var msg = res.data.info.text
}
}
})
获取机器人回复的语音消息
$.ajax({
method: 'get',
url: 'http://ajax-base-api-t.itheima.net/api/synthesize',
data: {
// 定义请求数据 text:value
text: text // text 要转换成语音的文字
},
success: function (res) {
if (res.status == 200) {
// res.voiceUrl 机器人回复的语音地址
$('#voice').attr('src', res.voiceUrl)
}
}
})
Ajax写法的 回调函数
success:function( res ){ } // 请求成功后执行
error:function( res ) { } // 请求失败后执行
complete: function(res) { } // 无论成功还是失败都执行
3者返回的res对象 内容不一样
$.ajax({
month: 'get',
url: '/my/userinfo',
headers: {
Authorization: localStorage.getItem('token')
},
success: function (res) {
if (res.status !== 0) {
return console.log('身份验证失败');
} else {
// 渲染头像
userPic(res.data)
}
},
complete: function (res) {
if (res.responseJSON.status == 1 && res.responseJSON.message == '身份认证失败!') {
// 1. 强制清空 token
localStorage.removeItem('token')
// 2. 强制跳转到登录页面
location.href = '/login.html'
}
}
})
接口
使用 Ajax
请求数据时,被请求的 URL
地址,就叫做 数据接口(简称接口)。同时,每个接口必须有请求方式。
接口测试工具
为了验证接口是否被正常被访问,我们常常需要使用接口测试工具,来对数据接口进行检测
**好处:**接口测试工具能让我们在 不写任何代码 的情况下,对接口进行 调用 和 测试
接口文档
接口文档,顾名思义就是 接口的说明文档,它是我们调用接口的依据。好的接口文档包含了对 接口URL,参数 以及 输出内容 的说明,我们参照接口文档就能方便的知道接口的作用,以及接口如何进行调用
接口文档的组成部分
- **接口名称:**用来标识各个接口的简单说明,如 登录接口,获取图书列表接口等
- **接口URL:**接口的调用地址
- **调用方式:**接口的调用方式,如 GET 或者 POST
- **参数格式:**接口需要传递的参数,每个参数必须包含 参数名称、参数类型、是否必选、参数说明 这4项内容
- 响应格式:接口的返回值的详细描述,一般包含数据名称、数据类型、说明3项内容
- **返回示例(可选):**通过对象的形式,列举服务器返回数据的结构
Form表单
表单在网页中主要负责 数据采集功能。HTML中<form>
标签,就是用于采集用户输入的信息,并通过 <form>
标签的提交操作,把采集的信息提交到服务器端进行处理
表单的组成
- 表单标签
- 表单域:包含了文本框,密码框,隐藏域,都行文本框,复选框,单选框,下拉选择框和文件上传框等等
- 表单按钮:通过设置
type
属性为submit
来触发form
表单的提交
<form>
标签的属性
action
action
属性用来规定当提交表单时,向何处发送表单数据。
action
属性的值应该是后端提供的一个URL地址,这个URL地址专门负责接收表单提交过来的数据。
target
target
属性用来规定 在何处打开 action URL
默认 当前窗口 target=“_self ”
新窗口打开:target=“_blank ”
method
method
属性用来规定 以何种方式 把表单数据提交到 action URL
它的可选值有两个,分别是 get
和 post
默认情况下,method
的值为 get
- get 方式适合用来提交少量的,简单的数据
- post 方式适合用来提交大量的,复杂的,或包含文件上传的数据
enctype
enctype
属性用来规定在 发送表单数据之前如何对数据进行编码
它的可选值有三个,默认情况下,enctype
的值为 application/x-www-form-urlencoded
,表示在发送前编码的所有字符
如果涉及到文件上传操作时,必须将enctype的值设置为 multipart/form-data
表单同步提交的缺点
<form>
表单同步提交后,整个页面会发生跳转,跳转到 action URL 所指向的地址,用户体验很差<form>
表单同步提交后,页面之前的状态和数据会丢失
解决:表单只复杂采集数据,Ajax负责将数据提交到服务器
Ajax提交表单数据
表单提交事件 submit
快速获取表单数据
serialize() 函数
<form id="f1">
<input type="text" name="user_name" />
<input type="password" name="password" />
<button type="submit">提交</button>
</form>
<script>
// 表单提交事件
$('#f1').on('submit', function (e) {
e.preventDefault() // 阻止默认行为跳转页面
console.log($(this).serialize()); // 快速获取表单数据
// user_name=输入的值 & password=输入的值
})
</script>
**注意:**在使用 serialize() 函数快速获取表单数据时,必须为每个表单元素添加 name 属性
XML HttpRequest(原生Ajax)
XMLHttpRequest
(简称 xhr
)是浏览器提供的 Javascript
对象,通过它,可以请求服务器上的数据资源
使用xhr
发起GET请求
- 创建 XHR 对象
- 调用 open 函数 创建一个Ajax请求
- 调用 send 函数 发起请求
- 监听 onreadystatechange 事件
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数 创建一个Ajax请求
xhr.open('GET', 'http://ajax-base-api-t.itheima.net/api/getbooks')
// 3. 调用 send 函数 发起请求
xhr.send()
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
// 判断是否获取成功
if (xhr.readyState === 4 && xhr.status === 200) {
// 获取服务器响应的数据 字符串型
console.log(xhr.responseText)
// 将字符串转为对象
var obj = JSON.parse(xhr.responseText)
console.log(obj)
}
}
使用xhr
发起带参数的GET请求
这种在 URL 地址后面拼接的参数,叫做查询字符串。
// 带1个参数
http://ajax-base-api-t.itheima.net/api/getbooks?id=1
// 带2个参数
ajax-base-api-t.itheima.net/api/getbooks?id=1&bookname=书名
查询字符串
**定义:**查询字符串(URL 参数)是指在 URL 的末尾加上用于向服务器发送信息的字符串(变量)。
**格式:**将英文的 ? 放在URL
的末尾,然后再加上 参数=值 ,想加上多个参数的话,使用 & 符号进行分隔
使用xhr
发起POST请求
- 创建
xhr
对象 - 调用
xhr.open()
函数 创建一个Ajax请求 - 设置 Content-Type 属性(固定写法)
- 调用
xhr.send()
函数,同时指定要发送的数据 - 监听
xhr.onreadystatechange
事件
// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数
xhr.open('POST', 'http://ajax-base-api-t.itheima.net/api/addbook')
// 3. 设置 Content-Type 属性(固定写法)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 4. 调用 send 函数
xhr.send('bookname=水浒传&author=施耐庵&publisher=上海图书出版社')
// 5. 监听事件
xhr.onreadystatechange = function () {
// 判断是否获取成功
if (xhr.readyState === 4 && xhr.status === 200) {
// 获取服务器响应的数据 字符串型
console.log(xhr.responseText)
// 将字符串转为对象
var obj = JSON.parse(xhr.responseText)
console.log(obj)
}
}
URL编码与解码
-
encodeURI()
编码的函数 -
decodeURI()
解码的函数
encodeURI('贾庆军') // %E8%B4%BE%E5%BA%86%E5%86%9B
decodeURI('%E8%B4%BE%E5%BA%86%E5%86%9B') // 贾庆军
数据交换格式
数据交换格式,就是服务器端与客户端之间进行数据传输与交换的格式
前端领域,经常提及的两种数据交换格式分别是 XML
和 JSON
XML
XML
的英文全称是 EXtensible Markup Language
,即可扩展标记语言
XML和HTML的区别
XML
和 HTML
虽然都是标记语言,但是,它们两者之间没有任何的关系。
-
HTML
被设计用来描述网页上的内容,是网页内容的载体 -
XML
被设计用来传输和存储数据,是数据的载体
XML的缺点
-
XML
格式臃肿,和数据无关的代码多,体积大,传输效率低 -
在
Javascript
中解析XML
比较麻烦
JSON
JSON
的英文全称是 JavaScript Object Notation
,即“JavaScript 对象表示法”
JSON
的本质是字符串。
JSON
是一种轻量级的文本数据交换格式,在作用上类似于 XML
,专门用于存储和传输数据,但是 JSON
比 XML
更小、更快、更易解析。
数据类型
数据类型可以是数字、字符串、布尔值、null、数组、对象6种类型。
JSON
的两种结构
JSON
中包含对象和数组两种结构
对象结构
对象结构在 JSON
中表示为 { }
括起来的内容。数据结构为 { key: value, key: value, … }
的键值对结构。其中,key
必须是使用英文的双引号包裹的字符串,value
的数据类型可以是数字、字符串、布尔值、null、数组、对象6种类型。
数组结构
数组结构在 JSON
中表示为 [ ]
括起来的内容。数据结构为 [ "java", "javascript", 30, true … ]
。
数组中数据的类型可以是数字、字符串、布尔值、null、数组、对象6种类型。
JSON
语法注意事项
① 属性名必须使用双引号包裹
② 字符串类型的值必须使用双引号包裹
③ JSON
中不允许使用单引号表示字符串
④ JSON
中不能写注释
⑤ JSON
的最外层必须是对象或数组格式
⑥ 不能使用 undefined
或函数作为 JSON
的值
**JSON
的作用:**在计算机与网络之间存储和传输数据。
**JSON
的本质:**用字符串来表示 Javascript
对象数据或数组数据
JSON
和JS
对象的关系
JSON
是 JS
对象的字符串表示法,它使用文本表示一个 JS
对象的信息,本质是一个字符串
var json = '{"a": "Hello", "b": "world"}'
var obj = {"a": "Hello", "b": "world"}
JSON
和JS
对象的相互转换
JSON.parse() 字符串转对象
JSON.stringify() 对象转字符串
// 字符串转对象
var json = '{"a": "Hello", "b": "world"}'
var obj = JSON.parse(json)
console.log(obj)
// 对象转字符串
var obj2 = { a: 'hello', b: 'world', c: false }
var str = JSON.stringify(obj2)
console.log(str)
序列化和反序列化
把数据对象 转换为 字符串的过程,叫做序列化,例如:调用 JSON.stringify()
函数的操作,叫做 JSON
序列化。
把字符串 转换为 数据对象的过程,叫做反序列化,例如:调用 JSON.parse()
函数的操作,叫做 JSON
反序列化。
设置HTTP
请求时限
有时,Ajax
操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。新版本的 XMLHttpRequest
对象,增加了 timeout
属性,可以设置 HTTP
请求的时限:
var xhr = new XMLHttpRequest()
// 设置 超时时间 毫秒
xhr.timeout = 30
// 设置超时以后的处理函数 自动停止HTTP请求
xhr.ontimeout = function () {
console.log('请求超时了!')
}
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
FormData
对象管理表单数据
// 1. 新建 FormData 对象
var fd = new FormData()
// 2. 为 FormData 添加表单项
fd.append('uname', 'zs')
fd.append('upwd', '123456')
// 3. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 4. 指定请求类型与URL地址
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
// 5. 直接提交 FormData 对象,这与提交网页表单的效果,完全一样
xhr.send(fd)
FormData
对象快速获取表单数据
// 获取form表单
var form = document.querySelector("#form1")
// 监听form表单的提交事件
form.addEventListener('submit', function (e) {
// 清除默认行为
e.preventDefault()
// 创建 FormData,快速获取到 form 表单中的数据
var fd = new FormData(form)
// 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 调用open 函数 创建一个Ajax请求
xhr.open('post', 'http://ajax-base-api-t.itheima.net/api/formdata')
// 调用 send 函数 传入数据发起请求
xhr.send(fd)
// 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// 获取服务器响应的数据 字符串型
console.log(xhr.responseText);
// 将字符串转为对象
console.log(JSON.parse(xhr.responseText));
}
}
})
FormData
对象上传文件(原生Ajax)
<!-- 1. 文件选择框 -->
<input type="file" id="file1" />
<!-- 2. 上传文件的按钮 -->
<button id="btnUpload">上传文件</button>
<br />
<!-- bootstrap 中的进度条 -->
<div class="progress" style="width: 500px; margin: 15px 10px;">
<div class="progress-bar progress-bar-striped active" style="width: 0%" id="percent">
0%
</div>
</div>
<!-- 3. img 标签,来显示上传成功以后的图片 -->
<img src="" alt="" id="img" width="800" />
<script>
// 获取提交按钮
var btn = document.querySelector('#btnUpload')
// 绑定点击事件
btn.addEventListener('click', function () {
// 获取上传的内容
var files = document.querySelector('#file1').files
if (files.length <= 0) {
return alert('请选择要上传的文件!')
}
// 创建 FormData,快速获取到 form 表单中的数据
var fd = new FormData()
// 把上传的第一个内容添加到 FormData 中
fd.append('tupian', files[0])
// 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 监听文件上传的进度 监听xhr.upload的 onprogress 事件
xhr.upload.onprogress = function (e) {
console.log(e);
if (e.lengthComputable) {
// 计算出上传的进度
var jdt = Math.ceil((e.loaded / e.total) * 100)
// 动态设置进度条
$('#percent').attr('style', 'width: ' + jdt + '%;').html(jdt + '%')
}
}
// 调用函数 创建Ajax请求
xhr.open('POST', 'http://ajax-base-api-t.itheima.net/api/upload/avatar')
// 调用请求 传入数据
xhr.send(fd)
// 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 获取的数据转为对象
var data = JSON.parse(xhr.responseText)
if (data.status === 200) {
// 上传成功
document.querySelector('#img').src = 'http://ajax-base-api-t.itheima.net' + data.url
} else {
// 上传失败
alert('图片上传失败!' + data.message)
}
}
}
})
</script>
FormData
对象上传文件(jQuery)
<input type="file" id="file1" />
<button id="btnUpload">上传文件</button>
<br />
<img src="./images/loading.gif" alt="" style="display: none;" id="loading" />
<script>
$(function () {
// 监听到Ajax请求被发起了
$(document).ajaxStart(function () {
$('#loading').show()
})
// 监听到 Ajax 完成的事件
$(document).ajaxStop(function () {
$('#loading').hide()
})
// 创建点击上传事件
$('#btnUpload').on('click', function () {
// 获取上传的图片 伪数组
var files = $('#file1')[0].files
// 判断有没有上传图片
if (files.length <= 0) {
alert('请上传文件')
}
// 创建 FormData,
var fd = new FormData()
// 向FormData里添加 图片名 和 图片
fd.append('tupian', files[0])
// 创建请求
$.ajax({
method: 'post',
url: 'http://ajax-base-api-t.itheima.net/api/upload/avatar',
// 传入图片数据
data: fd,
// 不修改 Content-Type 属性,使用 FormData 默认的 Content-Type 值
contentType: false,
// 不对 FormData 中的数据进行 url 编码,而是将 FormData 数据原样发送到服务器
processData: false,
// 执行回调
success: function (res) {
console.log(res);
}
})
})
})
</script>
同源
同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能
同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制
http://www.test.com/index.html
http://www.test.com/userlist
// 同源
跨域
同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域
**注意:**浏览器允许发起跨域请求,但是,跨域请求回来的数据,会被浏览器拦截,无法被页面获取到!
实现跨域数据请求
实现跨域数据请求,最主要的两种解决方案,分别是 JSONP
和 CORS
。
JSONP
出现的早,兼容性好(兼容低版本IE)。是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持 GET
请求,不支持 POST
请求。
JSONP
的实现原理,就是通过 <script>
标签的 src
属性,请求跨域的数据接口,并通过函数调用的形式,接收跨域接口响应回来的数据
<script>
function abc(data) {
console.log(data);
}
</script>
<script src="http://ajax-base-api-t.itheima.net/api/jsonp?callback=abc&name=zs&age=18"></script>
//? callback=函数名&name=zs&age=18
jQuery中的JSONP
jQuery
中的 JSONP
,也是通过 <script>
标签的 src
属性实现跨域数据访问的,只不过,jQuery
采用的是动态创建和移除标签的方式,来发起 JSONP
数据请求。
-
在发起
JSONP
请求的时候,动态向<header>
中 append 一个<script>
标签; -
在
JSONP
请求成功以后,动态从<header>
中移除刚才append
进去的<script>
标签;
$(function () {
// 发起JSONP的请求
$.ajax({
url: 'http://ajax-base-api-t.itheima.net/api/jsonp?name=zs&age=20',
// 代表我们要发起JSONP的数据请求
dataType: 'jsonp',
success: function (res) {
console.log(res)
}
})
})
原生Ajax请求封装
// 对象转为字符串封装函数
function resolveData(data) {
var arr = []
// 遍历对象
for (var i in data) {
// 接收每个属性名和属性值以等号相接
var str = k + '=' + data[k]
// 添加进数组
arr.push(str)
}
// 再把数组里的每个值 以 & 分隔成字符串返回
return arr.join('&')
}
// 封装原生Ajax请求
function Ajax(options) {
// 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 把传递过来的参数对象调用字符串转换封装 转换为 字符串
var qs = resolveData(options.data)
// 判断传过来的请求方式是获取还是发送
if (options.method.toUpperCase() === 'GET') {
// 发起GET请求
xhr.open(options.method, options.url + '?' + qs)
// 调用 xhr.send() 内置函数
xhr.send()
}
else if (options.method.toUpperCase() === 'POST') {
// 发起POST请求
xhr.open(options.method, options.url)
// 设置 Content-Type 属性(固定写法)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 调用 xhr.send() 内置函数,传入要发送的数据
xhr.send(qs)
}
// 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
// 判断请求成功(固定写法)
if (xhr.readyState === 4 && xhr.status === 200) {
// 将数据(字符串型)转为对象并声明一个变量接收
var result = JSON.parse(xhr.responseText)
// 调用请求对象的success方法 就是将数据返回到请求里面的匿名函数
options.success(result)
}
}
}
调用方法
// 发起get请求
Ajax({
method: 'GET',
url: 'http://ajax-base-api-t.itheima.net/api/getbooks',
data: {
id: 1
},
success: function (res) {
console.log(res)
}
})
// 发起post请求
Ajax({
method: 'post',
url: 'http://ajax-base-api-t.itheima.net/api/addbook',
data: {
bookname: '水浒传',
author: '施耐庵',
publisher: '北京图书出版社'
},
success: function (res) {
console.log(res)
}
})