Ajax 基础 第二章
Posted codekrist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了 Ajax 基础 第二章相关的知识,希望对你有一定的参考价值。
Ajax 错误处理的几种情况
第一种情况
- 网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期结果
* 可以判断服务器端返回的状态码 分别进行处理 xhr.status 获取 http 状态码
示 例 :
1- 在 app.js 写入error get请求
app.get('/error', (req, res) => {
// 修改状态码
res.status(400).send('not ok')
}
2- 创建html文件 07.ajax错误处理.html
<body>
<button id="btn"> 发送Ajax请求</button>
</body>
</html>
<script>
let btn = document.getElementById('btn');
btn.onclick = function () {
let xhr = new XMLHttpRequest();
xhr.open('get', 'http://localhost:3000/error');
xhr.send();
xhr.onload = function () {
consoloe.log(xhr.responseText)
}
}
</script>
3- 输入网址 http://localhost:3000/07.ajax错误处理.html
4- 获取http状态码
xhr.onload = function () {
console.log(xhr.responseText)
console.log(xhr.status) //获取http状态码
}
5- 现在就可以对这个状态码进行判断
如果状态码为 400 打印请求出错
if (xhr.status == 400) {
console.log('请求出错')
}
第二种情况
- 网络畅通,服务器端没有接收到请求 返回 404 状态码
示 例 :
xhr.open('get', 'http://localhost:3000/error123');
// 在error面写上123 我们并没有这个请求地址
2- 点击发送Ajax请求按钮是404
第三种情况
- 网络畅通 服务器端能接收到请求 服务器端返回 500 状态码
* 服务器端错误 找后端程序员进行沟通
1- 在app.js中打印 abc
app.get('/error', (req, res) => {
console.log(abc)
//修改状态码
res.status(400).send('not ok')
})
2- 输入网址 http://localhost:3000/07.ajax错误处理.html
第四种情况
- 网络中断 请求无法发送到服务器端
* 会触发 xhr 对象下面的 onerror 事件 在 onerror 事件处理函数中对错误进行处理
我们怎么才能模拟这种断网的情况呢?下面我们可以根据我所发的图来演示
现在 打开我们的控制台 点击Network
当断网的情况下是无法触发onload事件的
现在我们来处理断网事件
//当网断的时候触发onerror事件
xhr.onerror=function(){
console.log('网络中断,无法发送Ajax请求')
}
Ajax状态码 和Http状态码的区别
Ajax状态码 :表示Ajax请求的过程状态 ajax对象返回的
Http状态码 :表示请求的处理结果 是服务器返回的
低版本IE浏览器的缓存问题
xhr.open('get', 'http:www.codekrist.cn?t='+ Math.random());
示 例 :
1- 在server文件夹中创建一个test文本
现在我们要开始读取文本 要使用 fs模块
let fs = require('fs') //引入fs模块
app.get('/cache', (req, res) => {
// 回调函数
fs.readFile('./test.txt', (err, result) => {
res.send(result)
})
}
3- 创建html文件 08.Ajax缓存.html
<body>
<button id="btn"> 发送Ajax请求</button>
</body>
</html>
<script>
let btn = document.getElementById('btn');
btn.onclick = function () {
let xhr = new XMLHttpRequest();
xhr.open('get', 'http://localhost:3000/cache');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText)
}
}
}
</script>
4- 点击按钮
5- 现在我们修改文本 再次点击按钮 依然是我们上一次得到的数据
现在数据是浏览器缓存中的结果
6- 再次说明 解决办法
请求参数 不能使用本该需求的参数名 作为参数名
xhr.open('get', 'http://localhost:3000/cache?t='+Math.random());
现在我们解决了在IE低版本的缓存问题
同步异步概述
你应该知道,javascript 语言是一门“单线程”的语言,不像 java 语言,类继承 Thread 再来个 thread.start 就可以开辟一个线程,所以,javascript 就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程。
- 同步
* 一个人同一时间只能做一件事情, 只有一件事情做完,才能做另一件事情
落实到代码 就是上一行代码执行完成之后 才能执行下一行代码 即代码逐行执行
console.log(1)
console.log(2)
console.log(3)
- 异步
* 一个人一件事情做了一半 转而去做其它事情 当其他事情做完后 再回过头继续做之前未完成的事情
落实到代码上 就是异步代码虽然需要花费时间去执行 但程序不会等待异步代码执行完成之后再继续执行后续代码 直接执行后续代码 当后续代码执行完成之后再回头看异步代码是否返回结果 如果已有返回结果 在调用事先准备好的回调函数处理异步代码执行的结果
cosnole.log(1) //1
setTimeout(function(){
console.log(2) //3
},1000)
console.log(3)//2
示 例 :
<script type="text/javascript">
var xhr = new XMLHttpRequest();
console.log(xhr)
xhr.open('get', "http://localhost:3000/frist");
xhr.send();
xhr.onload = function () {
console.log('2') //后执行
console.log(xhr.responseText)
}
console.log('1') //先执行
</script>
Ajax 封装
- 问题: 发送一次请求代码过多 发送多次请求冗余且重复
* 解决方案 :将请求代码封装到函数中 发请求时调用该函数即可
第一种封装方式
1- 下面是我们封装好的Ajax函数发送
function ajax(url, data, method, success) {
// 创建异步对象
var xhr = new XMLHttpRequest();
// get 和post 分别写不同的代码
if (method == 'get') { //如果是get
if (data) { //当data中有值
url += '?' + data
}
xhr.open(method, url); //设置方法已经url;
xhr.send(); //send即可
} else {
xhr.open(method, url);
//post请求要设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
//判断data发送数据
if (data) {
xhr.send(data) //如果有值就send出去
} else {
xhr.send() //如果没有值 直接发送即可
}
}
//注册事件
xhr.onreadystatechange = function () {
//在事件中获取数据 并修改页面显示
if (xhr.readyState == 4 && xhr.status == 200) {
success(xhr.responseText)
}
}
}
2- 调用封装的Ajax函数
- server文件夹创建的test.txt文本
ajax('/server/test.txt', '', 'get', function (res) {
console.log(res)
})
第二种封装方式
封装方法1:提取需要改变部分
我们现在对本次的封装做个详细的概述
1- 创建ajax 以及兼容IE
2- 配置ajax对象
function ajax() {
//1- 创建ajax 以及兼容IE
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
//2- 配置ajax对象
xhr.open()
}
4- 现在开始调用我们的ajax函数
ajax({
type: 'get', // 请求方式
url: 'http://localhost:3000/frist', // 请求地址
})
在我们的函数中也应该传递一个 形参 options
options相当于对象的名字 type url ...
function ajax(options) { // 定义形参
}
6- 现在 xhr.open() 后面传递的参数就是
xhr.open(options.type,options.url)
7- 监听xhr对象下面的onload事件 当xhr对象接收完响应数据后触发
xhr.onload = function () {
console.log(xhr.responseText)
}
8- 完整代码
1- app.js
2 - 封装.html
3 - 控制台打印
我们封装的方法可以执行
封装方法2: 提取调用成功函数
在我们的onload事件触发时 调用
在这个函数中调用的是 实参
xhr.onload = function () {
// console.log(xhr.responseText)
options.success(xhr.responseText);
}
在函数中定义一个形参
ajax({
type: 'get', //请求方式
url: 'http://localhost:3000/frist', //请求地址
success:function(data){
console.log('success调用的'+data)
}
})
在控制台打印该方法
封装方法2: 定义请求参数 请求方式 请求参数格式类型
1- 请求参数问题
要根据请求方式的不同 把请求参数放入对应的请求方式中
> post 请求 把请求参数放入send方法中
2- 请求参数格式问题
参数名称=参数值&参数名称=参数值
> application/x-www-form-urlencoded
name=codekrist&age=18
> application/json
{ name:'codekrist',age:19 }
函数的调用者 使用哪种格式方便 ?
答道 :当然是json更加方便
1- 设置请求参数
示例:
对字符串进行截取& name=codekrist&age=19&
使用 substring( ) 方法
> 是用于提取字符串中介于两个指定下标之间的字符,两个参数,其中第一个参数是必须的,第二个参数是可选的。如果不传第二个参数,默认情况下会提取到最后。返回值是一个新的字符串。准确的说,返回的额字符串包含了第一个参数位置的字符串,而不包含第二个参数位置的元素。
继续将截取后的字符串赋值到 params
params = params.substring(0, params.length - 1);
2- 判断设置请求方式
if (options.type == 'post') {
//设置post 请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(params)
} else {
xhr.send();
}
1- 设置post请求
2- 控制台显示
封装方法3:判断请求参数格式类型
示例:
ajax({
type: 'post', //请求方式
url: 'http://localhost:3000/frist', //请求地址
data: {
name: 'codekrist',
age: 19
},
// 请求参数格式
header: {
'Content-Type': 'application/json'
},
success: function (data) {
console.log('success调用的' + data)
}
})
//如果当前请求时post
if (options.type == 'post') {
// 设置变量
var ContentType = options.header['Content-Type'];
//设置post 请求头
xhr.setRequestHeader('Content-Type', ContentType);
//判断用户希望的请求参数格式的类型
if (ContentType == 'application/json') {//如果类型为json
//向服务器端传递json数据格式的参数
xhr.send(JSON.stringify(options.data))
} else {
// 向服务器端传递普通类型的请求参数
xhr.send(params)
}
} else {
//get 发送请求
xhr.send();
}
控制台打印是否改变了数据格式
封装方法4: 数据请求与成功 回调
完成以上三个封装,我们只知道,获取成功后对该数据进行操作。 但是 当我们失败的时候怎么办呢?
我们应该使用Http状态码进行判断是否成功获取数据 或 获取数据失败
1- 判断status
xhr.onload = function () {
// console.log(xhr.responseText)
if (xhr.status == 200) { //成功
options.success(xhr.responseText, xhr);
} else { //失败
options.error(xhr.responseText, xhr);
}
}
2- ajax调用成功失败方法
ajax({
type: 'post', //请求方式
url: 'http://localhost:3000/frist', //请求地址
data: {
name: 'codekrist',
age: 19
},
header: {
'Content-Type': 'application/json'
},
success: function (data) {
console.log('success调用的' + data)
},
error: function (data) {
console.log('error调用的' + data)
}
})
3- app.js 对frist请求 手动设置状态码400
app.post('/frist', (req, res) => {
res.status(400).send('Hello CodeKrist')
})
> 在使用Ajax请求的时候 服务器端返回的结果大多是json数据作为响应内容
> 但是在客户端呢 我们拿到的是json字符串 所以在使用前我们我们要让json字符串转换为json对象
> 这个操作我们直接封装在函数当中 这样的话我们函数调用者又少关心了一步操作
> 现在的问题是 你怎么确定服务器端获取的就是json数据呢 万一服务器端返回的是一串字符呢
> 实际上服务器端在返回数据的时候会在响应头设置数据返回类型 我们只要获取到响应头当中设置的数据类 型 然后对类型进行判断就可以了
> 如果服务器端返回的是json类型数据我们在进行转换
> 如果服务器端返回的不是json类型数据我们不再进行转换
现在的问题是我们如何获取响应体的数据呢
在xhr有一个方法就是
// 获取响应头的数据 xhr.getResponseHeader('Content-Type')
console.log(xhr.getResponseHeader('Content-Type'))
1- 我们对frist请求得到的是text/html
app.js中的frist请求方式
app.get('/frist', (req, res) => {
res.send('Hello AJAX')
})
2- 打印结果 请求数据类型
如果我们换一个json对象格式呢
1- 我们对responseData
请求得到的是text/html
app.js中的responseData请求方式
app.get('/responseData', (req, res) => {
res.send({
"name": "codekrist"
})
})
2- 打印结果 请求数据类型
判断返回的是不是application/json类型
includes() 方法用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。
var contentType=xhr.getResponseHeader('Content-Type')
//判断是否包含application/json
if(contentType.includes('application/json')){
console.log('包含')
}
输出结果
我们将服务器端返回的数据定义变量
var responseText = xhr.responseText
并返回该数据 监听xhr对象下面的onload事件 当xhr对象接收完响应数据后触发 完整代码
xhr.onload = function () {
//获取响应头的数据 xhr.getResponseHeader('Content-Type')
console.log(xhr.getResponseHeader('Content-Type'))
var contentType = xhr.getResponseHeader('Content-Type')
var responseText = xhr.responseText //服务端返回的数据
//判断是否包含application/json
if (contentType.includes('application/json')) {
//将json字符串转换为json对象
responseText = JSON.parse(responseText)
}
// console.log(xhr.responseText)
if (xhr.status == 200) { //成功
options.success(responseText);
} else { //失败
options.error(responseText);
}
}
ajax调用 成功打印数据
ajax({
type: 'get', //请求方式
url: 'http://localhost:3000/responseData', //请求地址
data: {
name: 'codekrist',
age: 19
},
header: {
'Content-Type': 'application/json'
},
success: function (data) {
// console.log('success调用的' + data)
console.log(data)
},
error: function (data) {
console.log('error调用的' + data)
}
})
输出结果是不是将application/json格式 转换成json对象
> 到目前位置我们的ajax就快要封装好了
> 到现在我们还存在一些问题
> 我们在调用ajax的时候传递了很多的参数
> 如果每次调用ajax函数 都需要传递怎么多的参数也是很不方便的
> 我的想法是这样的 调用ajax参数的时候 传递一些必要的参数就可以了
> 没有传递请求参数的选项 应该有一个默认值
> 不传递就是用默认值 比如说请求参数的类型
> 如果不传递的话就是用传统的字符串类型的参数
> 如果要使用json数据类型的参数 就传递application/json
这样的需求要如何实现呢
> 我们只需要在函数的内部定义一个对象
> 对象中储存的数据就是默认参数
> 如果用户传递的某个参数就不使用默认值
> 用户哪个参数没传递就用默认值
1- 在ajax函数封装写上这么一段代码
并将函数内部原本的 options 全部改变成 defaults
var defaults = {
type: 'get',
url: '',
data: {},
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
success: function () {},
error: function () {},
}
2- 使用Object.assign方法
使用opstions对象中的属性覆盖defaults对象中的属性
如果在调用中没有传递就使用defaults中对象的值
如果在调用中传递就是用options中对象的值
Object.assign(defaults, options)
3-现在调用ajax函数
可以将不必要的实参写入到对象中
默认请求方式是get请求
ajax({
url: 'http://localhost:3000/responseData', //请求地址
success: function (data) {
// console.log('success调用的' + data)
console.log(data)
}
})
4- 在我们responseData请求中 的请求数据格式
app.get('/responseData', (req, res) => {
res.send({
"name": "codekrist"
})
})
5- 控制台输出
6- 如果是post请求呢
在ajax调用时写入post请求方式
ajax({
type:'post',
url: 'http://localhost:3000/responseData', //请求地址
success: function (data) {
// console.log('success调用的' + data)
console.log(data)
}
})
7- 现在请求方式就是post了
最终代码
function ajax(options) {
var defaults = {
type: 'get',
url: '',
data: {},
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
success: function () {},
error: function () {},
}
//使用opstions对象中的属性覆盖defaults对象中的属性
Object.assign(defaults, options)
//1- 创建ajax 以及兼容IE
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
var params = '';
for (var attr in defaults.data) {
params += attr + '=' + defaults.data[attr] + '&'
}
params = params.substring(0, params.length - 1);
// console.log(params)
//2- 配置ajax对象
xhr.open(defaults.type, defaults.url)
//3- 发送请求
//如果当前请求时post
if (options.type == 'post') {
var ContentType = defaults.header['Content-Type'];
//设置post 请求头
xhr.setRequestHeader('Content-Type', ContentType);
//判断用户希望的请求参数格式的类型
if (ContentType == 'application/json') { //如果类型为json
//向服务器端传递json数据格式的参数
xhr.send(JSON.stringify(defaults.data))
} else {
// 向服务器端传递普通类型的请求参数
xhr.send(params)
}
} else {
//get 发送请求
xhr.send();
}
//4- 监听xhr对象下面的onload事件 当xhr对象接收完响应数据后触发
xhr.onload = function () {
//获取响应头的数据 xhr.getResponseHeader('Content-Type')
console.log(xhr.getResponseHeader('Content-Type'))
var contentType = xhr.getResponseHeader('Content-Type')
var responseText = xhr.responseText //服务端返回的数据
//判断是否包含application/json
if (contentType.includes('application/json')) {
//将json字符串转换为json对象
responseText = JSON.parse(responseText)
}
// console.log(xhr.responseText)
if (xhr.status == 200) { //成功
defaults.success(responseText);
} else { //失败
defaults.error(responseText);
}
}
}
// 调用该方法
ajax({
type:'post',
url: 'http://localhost:3000/responseData', //请求地址
success: function (data) {
// console.log('success调用的' + data)
console.log(data)
}
})
以上是关于 Ajax 基础 第二章的主要内容,如果未能解决你的问题,请参考以下文章