不刷新的情况下向服务端发送请求,获得响应
AJAX全称是Asynchronous JavaScript And XML 异步的JS和XML
通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势是无刷新获取数据
AJAX不是新的编程语言,而是一种将现有标准组合在一起使用的新方式
如:
百度在搜索内容时,会出现关键词的相关词提醒,就是用的AJAX
当注册网站时输入用户名,如果用户名用过了,会提示用户名不可用,也是AJAX
网站的二级菜单,一般都是鼠标放上去了才会加载,称为懒加载,也是AJAX
优点:
可以无需刷新就像服务器端发出请求
允许根据用户事件(鼠标,键盘事件等)来更新部分页面内容
由此可以根据用户行为向服务器发出请求
缺点:
没有浏览历史,不能回退
存在跨域问题
a.com不能向b.com发送请求
搜索引擎优化不友好
网页的html中没有相应的内容信息,无法通过爬虫爬取结果
XML可拓展标记语言,与HTML类似
XML被设计用来传输和存储数据
XML和HTML类似,不同的是HTML使用的都是预定义标签,而XML没有预定义标签,全都是自定义标签,用来标识一些数据
如一个学生数据: name=‘孙悟空’ age=18 gender=‘男’
用XML表示为:
孙悟空
18
男
最开始AJAX在进行数据交换时使用的格式就是XML,服务器向浏览器返回结果时,返回的就是XML格式的字符串,JS在接到结果以后,提取数据并进行处理
但是现在在应用时已经不再使用XML,而是使用JSON
{"name":'孙悟空',"age":18,"gender":'男'}
JSON灵活度更高.因此以后用的都是JSON
HTTP : hypertext transport protocol 超文本传输协议
它详细规定了浏览器和万维网服务器之间互相通信的准则
协议是一种约定,一种规则,它约定了两种内容:
报文的重点是格式与参数
请求报文:
请求报文的格式分为四部分:请求行,请求头,请求空行,请求体
也就是说,每一次浏览器向服务器提交内容,实际上都由四部分组成:行,头,空行,体
行的结构:
头的结构:每一项的结构都是: 名字: 值
空行: 没有内容
体:
响应报文:
响应报文也是四部分: 响应行,响应头,响应空行,响应体
行的结构:
头的结构: 格式和请求头相同,内容写的是对响应体内容的描述
空行: 必须空一行
体: 主要的返回结果,返回格式为HTML语法的内容
在浏览器中点击F12,在网络界面中,点击第一个文件,即可查看报文
最主要的两项为标头和预览
标头Headers: 内容有请求头和响应头
请求头:可以查看浏览器向服务器发送的内容,点击查看源代码可以查看请求行的内容
响应头:可以查看服务器向浏览器的信息,点击查看源代码可以查看响应行的内容
在载荷中可以查看向服务器交互的参数
在响应中可以看到响应体的内容
在预览中可以看到网页的加载预览结果
Express是基于Node.js的平台
我们需要给服务端发送请求,因此首先需要一个服务端框架
先通过node下载express
使用步骤;
引入express
var express = require('express');
创建应用对象
var app=express();
创建路由规则
request是对请求报文的封装
response是对响应报文的封装
app.get('/',function(request,response){
//设置响应
response.send('hello express');
})
监听端口
app.listen(8000,function(){
console.log('服务已经启动,8000端口监听中');
})
监听端口之后,在浏览器中打开:
127.0.0.1:8000
即可收到服务器返回的响应报文
我们可以借助这个express,实现与ajax的交互
有两个准备:前端页面的准备和服务端的准备
我们希望的是,在点击按钮时向服务器发送请求
页面中,写一个div+一个button
服务器,将app.get的第一个参数设置为’/server’
这样当客户端向服务器发送请求时,如果url的路径内容是/server,才会执行回调函数里面的代码,并由回调函数中的response中的内容做出响应
app.get('/server',function(request,response){
//设置响应头 设置允许跨越
//第一个参数是响应头的名字,第二个是flag值
response.setHeader('Access-Control-Allow-Origin','*');
//设置响应体
response.send('hello');
})
这样一来,如果输入的网址为:
127.0.0.1:8000
则不会获取到任何内容
而只有设置为:
127.0.0.0:8000/server
才会获取到响应的内容
我们希望的是点击按钮时发送请求,因此我们需要给按钮绑定一个事件
获取元素
var btn=document.getElementsByTagName('button')[0];
绑定事件
btn.onclick=function(){
console.log('test');
}
我们将在单击事件的内部进行ajax操作
ajax操作由以下四步构成:
创建对象
var xhr=new XMLHttpRequest();
初始化请求
设置请求的方法和url
两个参数:
xhr.open('GET','http://127.0.0.1:8000/server');
如果想加某个参数,可以在url后面加一个后缀参数,格式为: ?+参数名=参数值 ,如果有多个参数,用&分割
xhr.open('GET','http://127.0.0.1:8000/server?a=100&b=200&c=300');
参数如果传递成功,可以在载荷中看到
发送请求
xhr.send();
事件绑定
处理服务端返回的结果
事件: xhr.onreadystatechange
on 当…时候
readystate 是xhr中的属性,num类型,表示状态
change 改变
因此,当服务端返回的结果改变时,事件发生
一共5个值,会触发4次,很多次的返回是没有价值的,我们应该在他返回了所有结果时再做处理
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
//判断相应的状态码200 403 404等
if(xhr.status===200){
//处理服务端响应的结果 内容有:行,头,空行,体(我们不获取空行)
console.log(xhr.status);//响应行中的状态码
console.log(xhr.statusText);//响应行中的状态字符串
console.log(xhr.getAllResponseHeaders())//响应头
console.log(xhr.response);//响应体
}else{
}
}
}
将相应的结果在div中呈现
var result=document.getElementById('result');
然后在事件中:
if(xhr.status===200){
result.innerHTML=xhr.response;
}
如果报错,就重启控制台
需求: 当把鼠标放到div上面时,发送post请求,返回的结果在div中呈现
获取元素对象
var result=document.getElementById('result');
绑定事件
result.addEventListener('mouseover',function(){
console.log('test');
})
创建对象
var xhr=new XMLHttpRequest();
初始化对象
xhr.open('POST','http://127.0.0.1:8000/server');
发送请求
xhr.send();
参数在这里设置,格式和url相同:
xhr.send('a=100&b=200&c=300');
用等号和冒号都可以
事件绑定
xhr.onreadystatechange=function(){
if(xhr.readystate===4&&xhr.status>=200&&xhr.status<300){
result.innerHTML=xhr.response;
}
}
同时,要在服务端中设置一个POST请求的响应
app.post('/server',function(request,response){
response.setHeader('Access-Control-Allow-Origin','*');
response.send('hello');
})
如果想设置请求头信息:
只需要在xhr.open( )后面加一个方法: xhr.setRequestHeader( )
参数有两个:
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
实操中这两个参数会有人告诉我们
设置的请求头信息可以在浏览器控制窗口的请求头中看到
需求:按下键盘按键,就像服务端发送请求,服务端返回的结果在div中呈现
绑定键盘按下事件
window.onkeydown=funtion(){
}
向服务端发送请求
var xhr=new XMLHttpRequest();
初始化
xhr.open('GET','http://127.0.0.1:8000/json-server');
这里不再是给server发送,而是给json-server发送,相应的,服务器端应该设置为json-server
发送请求
xhr.send();
事件绑定
xhr.onreadystatechange=function(){
if(xhr.readystate===4&&xhr.status>=200&&xhr.status<300){
result.innerHTML=xhr.response;
}
}
这些没什么新奇的了,但是我们要在服务端做一些事情:
设置一个对象data,作为返回的数据
var data={
name:'liu'
};
对对象进行字符串转换
var str=JSON.stringify(data);
将响应体的内容设置为data
response.send(str);
然后在客户端接收:
将字符串数据转化成对象
手动转化:
var data =JSON.parse(xhr.response);
自动转化:
先设置响应体数据的类型
xhr.responseType='json';
然后直接使用即可
console.log(xhr.response);
输出
手动转化:
result.innerHTML=data.name;
自动转化:
result.innerHTML=x.name;
Nodemon是一个可以帮我们重启程序的工具,基于Nodejs
可以自动检测文件变化,当文件发生改变时自动重启express框架的js文件,即模拟的服务器
使用
npm install -g nodemon
语句安装nodemon,安装完成后,以后使用时就不是node ajax.js了,而是:
nodemon server.js
这样启动服务之后,只要修改代码然后ctrl+s,就可以自动重启服务器
在实际应用中,不能够保证服务端永远能够及时,快速的响应,一定会出现超时的情况
这时候,我们可以通过对AJAX做一个超时的设置,给用户一个提醒
需求:同样是通过按钮向服务器发送请求,如果2s后还没有返回结果,则说明网络超时,请重试
先在服务器中模拟延时响应
app.get('/delay',funtion(request,response){
response.setHeader('');
setTimeout(funtion(){
response.send('延时响应')
},3000);//延时3秒
})
客户端弄一个超时设置:
xhr.timeout=2000;
timeout属性,如果响应时间超了,就会自动取消
超时的回调
如果超时了,该怎么办
xhr.ontimeout=function(){
alert('网络异常,请刷新重试');
}
网络异常的回调
xhr.onerror=function(){
alert("你的网络似乎出了些问题");
}
将浏览器控制界面的网络设置为断网,即可模拟网络异常的情况
需求:两个按钮,点击第一个发送请求,点击第二个取消请求
取消请求的方法: xhr.abort( )
xhr为发送请求的对象
步骤:
给第一个按钮绑定发送请求事件
var xhr=new XMLHttpRequest();//将x定义在外部,目的是按钮2也可以用这个变量
btn1.onclick=function (){
xhr.open('GET','http://127.0.0.1:8000/delay');
xhr.send();
}
给第二个按钮绑定取消请求事件
btn2.onclick=function (){
xhr.abort();
}
请求重复发送问题
我们每次点击按钮,就会创建一个请求,但是如果狂点,就会疯狂发送请求,那么服务器就会频繁接收相同的请求,就会增加服务器的压力
于是需求来了:点击一下按钮,先看看之前是否发送过请求,如果发送过,就将之前的取消掉,然后发一个新的,这样就可以减小服务器压力
取消上一个请求的步骤:
标识变量
是否正在发送ajax请求
var isSending=false;
发送请求时,修改表示变量的值
var xhr=new XMLHttpRequest();
btn1.onclick=function (){
isSending=true;
xhr.open('GET','http://127.0.0.1:8000/delay');
xhr.send();
x.onreadystatechange=function(){
if(x.readyState===4) isSending=false;
}//判断时不加状态码的判断,因为我们希望的是不论是否发送成功都可以取消
}
判断标识变量
在btn1.onclick第一行加一个判断
如果正在发送,则取消该请求,创建一个新的请求
if(isSending) x.abort();
略
是目前前端最热门的ajax工具库,以后会细讲
发送请求:
axios.get( ) axios.post( )
参数:
btn1.onclick=function (){
axios.get('http://127.0.0.1:8000/axios-server',{
//url参数
params:{id:100,vip:7},
//请求头信息
headers:{name:'liu',age:20}
});
}
相应的,服务器也要改成
app.get('/axios-server',function(){});
参数baseURL,对路径简化:
axios.defaults.baseURL='http://127.0.0.1:8000';
然后再发送时就不用再写了
axios.get('/axios-server',{
params:{id:100,vip:7},
headers:{name:'liu',age:20}
});
如果想使用返回的响应:
axios.get('/axios-server',{
params:{id:100,vip:7},
headers:{name:'liu',age:20}
}).then(function(resopnse){//这里是Promise语法,日后会学
console.log(response);
});
略
略
同源策略最早由Netscape公司提出,是浏览器的一种安全策略
同源:协议(http协议),域名(a.com),端口号(8000)完全相同
同源策略 : 网页的url和AJAX请求的目标资源的url之间,必须同源
ajax默认遵循同源策略,违背同源策略就是跨域
如果目标资源和网页资源都来自同一个服务器的同一个服务,那就是同源的
如果目标资源和网页资源来自不同服务器或者同一个服务器的不同服务,就是跨域的
跨域在实际应用中使用很广泛,因为一台服务器使用常常不够
但是ajax默认是遵循同源策略的
在满足同源策略的前提下,open的url可以简写:
//原来是:
xhr.open('GET','127.0.0.1:8000/data');
//可以简写为:
xhr.open('GET','/data');
添加一个响应页面:
app.get('/home',function (request,response){
response.sendFile(__dirname+'/Request.html');//dir前面两个下划线
});
然后就可以在浏览器中输入
127.0.0.1:8000/home
打开同源的Request.html文件
跨域的请求头:
response.setHeader('Access-Control-Allow-Origin','*');
response.setHeader('Access-Control-Allow-Headers','*');
jsonp是非官方的跨域的一个解决方案,是通过通过程序员的聪明才智开发出来的
只支持get请求
页面中的某些标签本身就拥有跨域的特性,如: img link iframe script
它是利用网页的script标签的跨域能力发送请求的
我们可以通过script的src属性引入外部资源:
<script src="http://127.0.0.1:8080/ajax.js">script>
它的返回结果是引入文件其中的所有内容,内容都可以在跨域的html文件中进行处理
然后在ajax.js中书写:
var data={name:'123'};
function handle(data){
var result=document.getElementById('result');
result.innerHTML=data.name;
}
handle(data);
但是,其实我们也可以把函数写到html文件中:
<script>
function handle(data){
var result=document.getElementById('result');
result.innerHTML=data.name;
}
script>
<script src="http://127.0.0.1:8080/ajax.js">script>
然后ajax.js中的内容就变成了:
var data={name:'123'};
handle(data);
就只剩下了参数的赋值和函数的调用
而我们的实际目的是用script标签向服务器发送请求:
<script src="http://127.0.0.1:8080/jsonp-server"></script>
当使用script标签向服务器发送请求,返回的应该是js代码
由此,我们可以在服务端书写数据,转化为json格式返回:
app.all('/jsonp-server',function (request,response){
var data={name:'liu'};
vat str=JSON.stringify(data);
response.end(`handle(${str})`);
})
服务器返回结果的形式是一个函数调用,函数的实参就是我们想给客户端返回的结果数据
这就是JSONP实现跨域的原理
需求:一个用户名的文本框,在其中输入用户名,然后丧失焦点,丧失焦点时向服务器发送请求,对用户名做是否存在的检测,然后服务端返回已存在,然后更改文本框的颜色为红色
客户端步骤:
获取用户元素
var input=document.getElementById('input');
var p=document.getElementsByTagName('p')[0];
声明handle函数
function handle(data){
input.style.border='solid 1px #f00';
p.innerHTML=data.msg;
}
绑定失去焦点事件
input.onblur=function (){
}
后面的内容都在失去焦点事件的函数中
获取用户的输入值
var username=this.value;
向服务器发送请求,检测用户名是否存在
创建script标签
var script =document.createElement('script');
设置标签的src属性
script.src='http://127.0.0.1:8000/check-username';
将script插入到文档中
document.body.appendChild(script);
服务器步骤:
声明对象
var express=require('express');
var app=express();
监听端口
app.listen(8000,function(){
console.log('服务已经启动,8000端口监听中');
});
设置请求的响应
返回的是一个对象.
app.all('/check-username',function (request,response){
var data={
exist:1,
msg:'用户名已经存在'
};
var str=JSON.stringify(data);
response.end(`handle(${str})`);
})
略
CORS,跨域资源共享,是一种官方的跨域解决方案
它的特点是不需要客户端做任何的操作,完全在服务器中进行处理,支持get和post请求
它新增了一组http响应头,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
CORS是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该请求以后就会对响应放行
服务端的响应头设置:
response.setHeader('Access-Control-Allow-Origin','*');
response.setHeader('Access-Control-Allow-Headers','*');
参数:
第一个参数是固定写法,不同的写法有不同的效果,可以在API文档中查看
第二个参数是允许的网页的url,但是一般写通配,如果不想通配:
response.setHeader('Access-Control-Allow-Origin','127.0.0.1:5000');