注:这是在学习相关课程时做的总结内容,还没有进行实践,若想要更生动的学习,可以观看B站的相关视频
概述
它是浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站的应用体验
在用户浏览网页的同时,可以局部的刷新页面
应用场景:
- 页面上拉加载更多数据
- 列表数据无刷新分页
- 表单下那个离开焦点数据验证
- 搜索框提示文字下拉列表
注:需要运行在网站环境中才能生效
运行及原理实现
创建Ajax对象
-
创建
var xhr = new XMLHttpRequest();
-
告诉Ajax请求的地址及方式
告诉Ajax要向哪发送请求,以什么样的方式发送
xhr.open('get','http://www.example.com');
这个地址实际上就是服务器端对应的路由地址
-
发送请求
xhr.send();
-
获取服务器端给客户端的响应数据
xhr.onload = function () { console.log(xhr.responseText); }
当Ajax接收完服务器端的响应之后,触发onload事件
在真实的项目中,服务器端大多数情况下会以JSON对象作为响应数据的格式。当客户端拿到响应数据时,要将JSON数据和HTML字符串进行拼接,然后将拼接后的结果在页面中展示。
在http请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转化为对象字符串进行传输
JSON.parse(); //将js字符串转化为JSON对象
传递请求参数
在传统的形式当中,请求都是通过表单的形式来进行传递的。只要表单提交,根据请求方式的不同,表单内容会变成请求参数被自动拼接到对应的位置。get 请求方式会被拼接到请求地址的后面,post请求方式会被放在请求体当中,但无论是哪种请求方式,请求参数的格式都是“请求名称=参数值”的格式,多个参数之间用&符进行连接。
而在Ajax中,我们需要之间拼接请求参数,根据请求方式的不同,将参数放到对应的位置上。
get方式:
xhr.open('get','http://example.com?name=zhangsan&age=18');
post方式:
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('name=zhangsan&age=20');
参数直接放在send方法当中,但需要注意的是,post请求需要在请求报文中明确设置请求参数的内容的类型,也就是Content-Type
属性
请求参数格式
-
Content-Type
属性值为application/x-www-form-urlencoded
name=zhangsan&age=20
-
Content-Type
属性值为application/json
{name: 'zhangsan',age: 20}
需要注意的是我们需要将JSON转化为字符串的格式,放入send方法中
JSON.stringify()//将json对象转换为json字符串
服务器中的
bodyParser
也需要重新进行配置,例如app.use(bodyParser.json()); //接收json格式的参数
注意:get请求不能提交json对象数据格式,传统网站的表单提交也不支持json对象数据格式
Ajex状态码
表示Ajax请求的过程状态 是由Ajax对象返回的
onreadystatechange
事件监听状态码的变化,先添加这个事件,再发送请求,写在send方法前面
Ajax错误处理
-
情况一:网络畅通的情况下,服务器能接收到请求,但是返回的结果不是预期的结果
处理方式:判断服务器返回的状态码,分别进行处理
xhr.status //获取HTTP状态码
-
情况二:网络畅通,服务器没有接收到请求,返回404状态码
处理方式:检查请求地址是否出错
-
情况三:网络畅通,服务器能接受到请求,服务器端返回500状态码
处理方式:找后端程序员进行沟通
-
情况四:网络中断,请求无法发送到服务器
处理方式:会触发xhr对象下的onerror事件,在onerror事件处理函数中对错误进行处理
xhr.onerror = funcion (){ alert('网络中断'); }
低版本IE浏览器缓存问题
在低版本的IE浏览器中,Ajax请求会有严重的缓存问题,在请求地址不发生变化的情况下,只有第一次请求回真正发送到服务器端,后续的请求都会从浏览器的缓存中拿到结果。即使服务器端的数据更新了,客户端依然拿到的是旧数据。
解决方法:在请求地址后面加一的请求参数,保证每一次请求中的请求参数的值不同
xhr.open('get','http://example.com?t=' + Math.random);
Ajax异步编程
同步与异步
同步 :一个人同一时间只能做一件事情,只有一件事情做完,才能做另一件事情;落实到代码中就是,一行代码执行完,才能执行下一行代码,即代码逐行执行。
异步:一个人一件事情做了一般,转而去做其它事情,当其他事情做完之后,再回过头来继续做之前未完成的事情;落实到代码上,就是异步代码虽然需要花时间去执行,但是程序不会等待异步代码执行完成后再去继续执行后面的代码,而是直接执行后面的代码,当后面的代码执行完之后,再查看异步代码的返回结果,如果已有返回结果,再调用事先准备好的回调函数处理异步代码执行的结果。
Ajax发送请求的过程就是异步代码执行的过程;
Ajax封装
- 参数设置成对象的形式,可以帮助我们更好的知道每个参数代表的意思;
- 传递对象数据类型对于函数的调用者更加友好,在函数内部对象数据类型转换为字符串数据类型更加方便;
- onload 事件触发的时候,只能说明这次请求完成了,不能代表这次请求一定是成功的,因此需要对http状态码进行判断。
- 处理服务器返回值,在服务器进行返回的数据时候,会在响应头中设置数据的返回类型,我们可以对响应头中的数据类型进行判断;获取响应头当中的数据
xhr.getReponseHeader
; - Ajax函数参数太多,会给调用者造成麻烦,因此我们可以给一些参数设置默认值,让调用者只传递必要的参数即可
function ajax (options){
//设置默认对象
var defaults = {
type: 'get',
url: '',
data: {},
header:{
'Content-Type': 'application/x-www-form-urlencoded'
},
success: function(){},
error: function(){}
}
//对默认对象进行覆盖
Object.assign(defaults,options);
//创建Ajax对象
var xhr = new XMLHttpRequest();
var params = '';
//将传递过来的参数格式,转化为字符串格式
for(var attr in defaults.data) {
params += attr + '=' + defaults.data[attr] + '&';
}
//截取最后的&符号
params.substr(0,params.length - 1);
//判断请求方式
if (defaults.type == get){
defaults.url += '?' + params;
}
//配置Ajax对象
xhr.open(defaults.type,defaults.url);
if (defaults.type == post){
//发送请求
var contentType = defaults.header['Content-Type']
xhr.setRuquestHeader('Content-Type',contentType);
//判断用户希望请求参数格式的类型
//如果为Json
if(contentType == 'application/json'){
//向服务器返回Json格式的数据
xhr.send(JSON.Stringify(defaults.data));
}else{
//如果不是,向服务器传递普通类型参数
xhr.send(params);
}
}else{
xhr.send();
}
//监听xhr对象下的onload事件,当对象接受完响应数据后触发
xhr.onload = function(){
//判断返回数据的类型
var contentType = xhr.getReponseHeader('Content-Type');
var responseText = xhr.responseText;
//如果是json,还需要进一步转换
if(contentType.includes('application/json'){
//将json字符串转化为json对象
responseText = JSON.parse(responseText)
}
//当http状态码为200时,表示请求成功,调用成功的代码
if(xhr.atutas == 200){
defaults.success(responseText,xhr);
}else{
//否则,表示请求失败,调用失败的代码
defaults.error(responseText,xhr);
}
}
}
ajax ({
url: 'http://www.example.com',
data: {
name: 'zhangsan',
age: 20
},
success: function(data,xhr){
console.log(data);
},
error: function(data,xhr){
console.log(data);
}
})
模板引擎
作用:使用模板引擎提供的语法,可以将数据和HTML拼接起来
FromData 对象
作用与使用方法
作用:
- 模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单中对象中的数据拼接成请求参数的格式。
- 异步上传二进制文件(如图片、视频)
创建formData对象
var form = document.getElementById('form');
var formData = new FormData(form);
提交表单对象
xhr.send(formData);
注意:不能使用get方法请求,因为formData对象内容要放在send方法中。
这是Html5提供的,还有兼容性的问题
实例方法
这些方法都是对表单当中数据的操作,一般来说,表单数据是不会直接被i叫到服务器端,在用户点击完提交按钮后,客户端一般还要对数据进行校验。
-
获取表单对象中属性的值
formData.get('key'); //key代表表单控件中name属性的值
-
设置表单控件的属性值
formData.set('key','value');
注意:设置的时候,如果表单属性的值是存在的会把原有的值替换掉;若设置的这个属性是表单当中原本不存在的,那么将会创建出这个属性。
-
删除表单对象的属性值
例如,我们一些表单会输入两次密码,那么我们只需要提交一次,需要删掉一个
formData.delete('key');
-
向表单对象中追加值
应用场景:我们在创建formData对象的时候也可以创建一个空的表单对象,然后进行追加
formData.append('key','value');
注意:set方法和append方法都可以给表单对象追加属性,但是区别是,在属性名已存在的情况下,set方法会覆盖已有的值,而append方法会保留两个值,但是,若不在服务器进行特殊设置的时候,它默认提交的是最后一个值。
二进制文件上传
Ajax请求限制
Ajax无法向非同源地址发送请求;Ajax只能向自己的服务器发送请求。如果客户端向非同源网站发送了请求,那么浏览器的控制太会报错,但实际上,这个请求是能够发送出去的,只不过是浏览器拒绝接收服务器端的返回结果,座椅最终请求还是失败的。
同源
多个请求或者页面来自同一个服务器端。
如果两个页面有相同的协议、域名、端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。
同源政策
同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指A网站的Cookie,B网站是不能访问的。
解决同源限制
JSONP解决
使用JSONP解决同源限制问题 (实际上已经不属于Ajax请求的范围了,但是可以模拟出Ajax的请求效果,它绕过了浏览器同源政策的限制,向非同源页面发送请求)
JSONP :json with padding 的缩写
首先,将不同源服务器请求地址写在script标签的src属性当中
<script src="www.example.com"> </script>
在客户端,并不是所有能发送请求的方式都受同源政策的限制,src 就是一种。
之后,服务器端的响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数
const data = 'fn({name: 'zhangsan', age: 20})';
res.send(data);
在客户端全局作用域下定义被调用的函数,还要写在script的标签前面;
function fn (data){}
最后,在函数内部对服务器返回的数据进行处理
function fn (data) {console.log(data)};
JSONP代码优化
- 解决页面一加载就发送请求的问题,让请求根据用户的需求来进行发送,例如点击按钮动态发送请求;
方法:通过JS动态创建Script标签
btn.onclick = function (){
//创建script标签
var script = document.createElement('script');
//设置src属性
script.src = 'http://www.example.com';
//追加到页面当中
document.body.appendChild(script);
//为script标签添加onload事件
script.onload = function (){
//当script执行完成之后,删除掉这个标签,避免出现因多次点击,页面中有多个相同的script标签的现象
document.body.removeChild(script);
}
}
- 客户端需要将函数名称传递到服务器,可以做到客户端修改函数名称而不影响服务器端的效果
<script src="www.example.com?callback=fname"> </script>
- 封装JSONP函数
function jsonp (options) {
//动态创建script标签
var script = document.createElement('script');
var params = '';
for(var attr in options.data){
params += '&' + attr + '=' + options.data[attr];
}
//随机生成一个函数名
var fnName = 'myjsonp' + Math.random().toString().replace('.','');
//将传递过来的函数变成全局函数
window[fnName] = options.success;
//添加src属性
script.src = options.url + '?callback=' + fnName + params;
//追加到页面当中
document.body.appendChild(script);
script.onload = function (){
document.body.removeChild(script);
}
}
jsonp ({
data:{
name: 'lisi',
age: 30
},
url:'http://www.example.com',
success: function(data){
console.log(data);
}
})
服务器端优化
app.get('/xxxx',(req,res) =>{
res.jsonp({name: 'lisi',age: 20});
})
CORS 跨域资源共享
全称:Cross-origin resourse sharing
,即跨域资源共享,它允许浏览器向跨域服务器发送Ajax请求,克服了Ajax只能同源使用的限制。
简单来说就是,服务器端允许你跨域访问它,你就可以跨域访问它;服务器端不允许你跨域访问它,你就不能访问。
服务器端要1.设置允许哪些客户端可以访问 ;2.要设置允许哪些请求方法可以访问
app.use((req,res,next) => {
res.header('Access-Control-Allow-Origin','*');
res.header('Access-Control-Allow-Origin','get,post')
next();
})
同源政策
cookie 复习
在http协议中规定,客户端与服务器端的交互属于无状态,谁也不认识谁;为例实现登录功能,识别客户端的身份,这个时候就有了cookie,它就是用来识别客户端与服务器端身份的一种技术。应用起来就是,当客户端第一次访问服务器端的时候,服务器会给这个客户端发一个身份证,也就是响应一个cookie,当客户端第二次访问服务器时,这个身份证会随着请求一起发送给服务端,服务器就会知道这个客户端是谁了,这样也就建立了持久的联系。
jQuery中的方法
&.ajax()
方法
注意:
data还可以传递拼接好的字符串
{
data: 'name=zhangsan&age=20'
}
在写请求地址的时候,如果遇到了协议、域名、端口都相同的情况;可以省略
serialize方法
作用:将表单中的数据自动拼接成字符串类型的参数
var params = $('#form').serialize()
//name=zhangsan&age=20
function serializeObject(obj) {
//处理结果对象
var result = {};
//转化成数组格式,数组里面的内容以对象的形式存在[{name:'username',value: 'zhangsan'},{name:'password',value: '12345']
var params = obj.serializeArray();
//循环数据,将数组转化为对象类型
$.each(params,function(index, value){
result[value.name] = value.value;
})
return result;
}
发送jsonp请求
$.ajax({
url:...,
dataType: 'jsonp',
//可选参数 ,修改callback参数名称
jsonp: 'cb',
//可选参数 , 指定函数名称
jsonCallback: 'fnName',
success: function(response){}
})
post()方法
分别用来发送get请求和post请求
$.get('http://www.example.com',{name; 'zhangsan',age: 30},function(response){})
$.post('http://www.example.com',{name; 'zhangsan',age: 30},function(response){})
//第二个参数可以是对象类型的也可以是字符串类型的,如果不需要,可以省略,第三个参数实际上也就是success函数
Jquery中的全局事件
需求:只要页面中有Ajax请求被发送,对应的全局事件就会被触发
.ajaxStart() //当请求开始的时候触发
.ajaxComplete() //当请求完成的时候触发
告诉用户进度,可以使用NProgress插件
RESTful 风格的API
传统请求缺点:
语义不明且混乱,没有统一的规范来约束
RESTful API 概述: 一套关于设计请求的规范
GET: 获取数据
POST: 添加数据
PUT: 更新数据
DELETE: 删除数据
不需要在请求地址中,添加动词了
特点:请求地址相同,请求方式不同,所做的事情也就不同