AJAX

什么是AJAX?

​ Ajax(Asynchronous JavaScript and XML的缩写)是一种异步请求数据的web开发技术,对于改善用户的体验和页面性能很有帮助。简单地说,在不需要重新刷新页面的情况下,Ajax 通过异步请求加载后台数据,并在网页上呈现出来。常见运用场景有表单验证是否登入成功、百度搜索下拉框提示和快递单号查询等等。

AJAX的好处:可以通过js代码发送get或者post的请求去从后台获取到相应数据,并只对页面中的部分标签进行刷新渲染,而不需要刷新整个页面,节约了带宽,优化了性能

创建AJAX对象

1
2
//兼容性写法  ActiveXObject('Microsoft.XMLHTTP');是为了兼容IE5 IE6
var ajax = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');

AJAX的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//设置请求方式
ajax.open("post","url",true); //第三个参数如果为true,则是异步,反之同步

//设置请求头格式(post请求时一定要加请求头,这是因为在传输过程中会出现转码的情况,可能导致乱码的情况)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

//发送请求:get请求参数放在url后面,post请求参数send()方法里面
ajax.send("数据");

//监听ajax状态,当ajax的状态发生改变的时候执行
ajax.onreadystatechange = function(){
//响应完成,浏览器已经可以获取到服务器响应结果了
if(this.readyState == 4){ //这是AJAX的状态码 区别与http的状态码 状态码还有 1 2 3 其中3是数据正在传输时的状态,他不保证数据的完整性
//http响应的状态码
if(this.state == 200){ //还有302 301 404...
//获取响应内容
console.log(this.responseText); //用ajax.responseText获取服务器返回的数据
//responseText 获得字符串形式的响应数据。
//responseXML 获得XML 形式的响应数据
}
}
}

数据渲染的两种方式

数据在服务器中渲染完毕,返回给客户端一个完整页面

  1. 浏览器发送请求至服务器
  2. 服务器接收到请求的信息,根据请求找到相应的信息(如JSON数据),在读取相应的页面文件,并渲染成一个完整的页面,将这个页面返回给客户端
  3. 客户端接收到此页面,并显示 (此方式要在服务器端安装art-template express-art-template等第三方模板)

服务器只返回相应的数据,客户端接收到数据后,在客户端进行渲染,并显示

  1. 客户端发送数据请求给服务器
  2. 服务器拿到请求,找到相应的数据(如JSON),直接将此数据返回给客户端
  3. 客户端拿到数据后,在客户端进行渲染,并显示。(此方式要用到前端渲染插件template-web.js)

XML

XML extensible Markup Language 扩展的标记语言,XML的标签可以自定义
HTML Hyper Text Markup Lanaguage HTML的标签是由W3C规范的,大概一共200多个

XML用途:
1、 定义数据结构
2、 作为配置文件出现

XML组成:
1、 XML文档声明
2、 XML标签
3、 XML属性
4、 XML注释

XML文档注意点:
1)xml的标签必须成对出现如,为成对出现时的标签也必须要是自关闭标签 如
2)xml标签名称区分大小写
3)xml标签一定要正确配对。
4)xml标签名中间不能使用空格
5)xml标签名不能以数字开头
6)注意: 在一个xml文档中,有且仅有一个根标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//使用xml设计一个通讯录
<?xml version="1.0" encoding="utf-8"?>
<contact>
<person id="100">
<name>张三</name>
<age>18</age>
<phone>12345678</phone>
<email>12453@qq.com</email>
</person>
<person id="101">
<name>李四</name>
<age>20</age>
<phone>22345678</phone>
<email>34453@qq.com</email>
</person>
</contact>

xml的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//服务器代码
//返回XML格式的数据
app.get("/getXML",(req,res)=>{
//设置响应头,指定返回的数据是XML
res.header("content-type","application/xml");

var xml = '<?xml version="1.1" encoding="utf-8"?>';//XML文档声明
xml += '<person>';
xml += '<name>羊杨</name>';
xml += '<age>16</age>';
xml += '<gender>男</gender>';
xml += '</person>';

res.send(xml);
})

//客户端代码
ajax.onreadystatechange = function(){
if(this.readyState == 4){
//获取响应的XML数据
var xml = this.responseXML.documentElement;//ajax.responseXML.documentElement拿到文档数据
var age = xml.querySelector("age");//用标签选择器获取到age数据 但此时age是<age>16</age>
console.log(age.innerHTML);//此处用innerText拿不到数据
console.log(xml.children);//xml的语法几乎与html语法类似
}
}

JSON

json数据的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//服务器代码
//返回JSON格式的数据
app.get("/getJSON",(req,res)=>{
//数组
let arr = [
{
name:"zhangsan",
age:"18",
gender:"男",
id:001
},
{
name:"lisi",
age:"28",
gender:"男",
id:002
}
]
//将数组转换为JSON数据
res.status(200).send(JSON.stringify(arr));
})

//客户端代码
ajax.onreadystatechange = function(){
if(this.readyState == 4){
console.log(this.responseText); //这是JSON字符串,在使用的时候往往需要转换为对象
var students = JSON.parse(this.responseText);
var html = template("generatorTable",{students:students});
container.innerHTML = html;
}
}

jQuery中的AJAX

推荐使用 方便的一批

使用

客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$.ajax({
//请求方式
type:"get", //post

//请求路径
url:"", //如http://localhost:3000/index

//请求参数,无论是get还是post请求,请求参数都可以写在这里
//注意:请求为get时 在服务器得到请求参数时 仍然使用res.query
//这里的data数据必须为字符串 若要传入json数据 需要将json数据转换为字符串如 JSON.stringify({[{},{}]})
data:{name:"zhangsan"},

//规定所要请求的数据的类型
dataType: '',

//在jQuery中如果请求已经是post,默认的contentType就是application/x-www-form-urlencoded,不需要单独再去写
//contentType: "application/x-www-form-urlencoded",
//请求成功的回调
success:function(res){
console.log(res);//res是请求的到的数据
}
//请求出错的回调 推荐写
error:function(err){
console.log(err);
}
//无论请求的成功与否,只要请求结束都会执行此函数
complete:function(xhr){

}
})

服务器代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
let express = require("express");
let app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));
//注意 当客户端中的data:JSON.stringify([{name:'zhangsan'},{name:'lisi'}])时,服务器需要此配置
//以解析body中的json数据
app.use(bodyParser.json({extended:false}));

app.use(express.static("./views"));

//当ajax的url为'/getJSON'时 此接口响应 返回JSON格式的数据
//此时ajax的dataType要设置为'json'
app.get("/getJSON",(req,res)=>{
//数组
let arr = [
{
name:"zhangsan",
age:"18",
gender:"男",
id:001
},
{
name:"lisi",
age:"28",
gender:"男",
id:002
}
]

arr.forEach((user,idx)={
if(user.name == req.body.name){
res.status(200).send(JSON.stringify(user));
}
})

})

//当ajax的url为'/getXML'时 此接口响应 返回XML格式的数据
//此时ajax的dataType要设置为'xml'
app.get("/getXML",(req,res)=>{
//设置响应头,指定返回的数据是XML
res.header("content-type","application/xml");

var xml = '<?xml version="1.1" encoding="utf-8"?>';
xml += '<person>';
xml += '<name>zhangsan</name>';
xml += '<age>16</age>';
xml += '<gender>男</gender>';
xml += '</person>';

res.send(xml);
})

发送也接受html或script数据

服务器代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));

app.use(express.static('views'));

app.get('/getScript',(req,res)=>{
res.header('content-type','application/javascript;charset=utf-8');
res.send('alert(123);');
});

app.get('/getHtml',(req,res)=>{

res.header('content-type','text/html;charset=utf-8')
res.send('<h1>HTML</h1>');
});

app.listen(3000,()=>{
console.log('running...');
});

客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$('#btn1').click(function(){
$.ajax({
type: 'get',
url: '/getHtml',
data: '',
dataType: 'html',
success:function(res){
//因为dataType为html jQuery。AJAX会自动设置响应头为text/html 则 可以直接追加res到页面中
$('#info').append(res);
},
error:function(err){
console.log(err);
}
});
});

$('#btn2').click(function(){
$.ajax({
type: 'get',
url: '/getScript',
data: '',
dataType: 'script',
success:function(res){
//之所以alert()能执行 是因为将script代码打印到控制台 控制台会执行script代码
//也可以用script标签的对res进行封装 追加到页面中 也可以执行
console.log(res);
},
error:function(err){
console.log(err);
}
});
});

dataType

dataType取值有xml、html、json、jsonp、script或者text

当dataType取值为json,会自动将服务器返回的文本数据通过JSON.parse()转换成对象。
服务器应该设置这个响应头:res.header(“content-type”, “application/json;charset=utf-8”);

当dataType为xml或者text的时候,返回的数据不会另做处理
服务器应该设置这个响应头:res.header(“content-type”,”application/xml”);
res.header(“content-type”,”text/plain;charset=utf-8”);

当dataType为html的时候,返回的内容中的script标签会在网页内容被拼接到页面的时候执行
服务器应该设置这个响应头:res.header(“content-type”,”text/html;charset=utf-8”);

当dataType为script的时候,会将服务器返回的结果当成js代码执行并且将js代码的文本内容返回给客户端
服务器应该设置这个响应头:res.header(“content-type”,”application/javascript”);

当dataType为jsonp的时候,会向服务器发送一个jsonp请求
服务器应该设置这个响应头:res.header(“content-type”,”application/javascript”);

nprogress的使用(全局事件处理)

1、在html文件中引入nprogress.js 和 nprogress.css

2

1
2
3
4
5
$(document).ajaxStart(function(){//请求数据开始
NProgress.start();//数据加载动画
}).ajaxStop(function(){//请求数据结束
NProgress.done();//数据加载完毕动画
});

跨域请求

同源策略是浏览器的一种安全策略,所谓同源是指 域名,协议,端口完全相同 ,只有同源的地址才可以相互通过AJAX的方式请求。

同源或者不同源说的是两个地址之间的关系,不同源地址之间请求我们称之为跨域请求

例如

1
2
http://localhost:8000  是不可以通过ajax访问  http://locally.uieee.com/categories的
因为两者不满足同源的条件

如何进行跨域请求

  1. CORS
  2. JSONP
  3. 代理服务器
  4. 修改document.domain
  5. Iframe
  6. Location.hash
  7. Window.postMessage()
  8. Websocket

CORS

只需要改动服务器,不用改动客户端代码,客户端可以直接使用$.ajax()

Cross Origin Resource Share,跨域资源共享。这种方案无需客户端作出任何变化(客户端不用改代码),只是在被请求的服务端响应的时候添加一个Access- Control-Allow-Origin 的响应头,表示这个资源是否允许指定域请求。

1
2
3
4
5
6
7
8
//直接在服务器配置如下,客户端代码和以前一样写
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Headers', 'Content-type');
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,PATCH");
res.header('Access-Control-Max-Age',6000);//预请求缓存10分钟
next();
});

JSONP

JSON with Padding 实质上是通过script的src属性进行数据请求。本质上不是AJAX请求

需要服务器和客户端配合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//此时客户端的地址为http://localhost:3000
实现要点
//客户端代码
var script = document.createElement('script');
script.src = 'http://localhost:9999/testJSONP';//向http://localhost:9999发送跨域请求
document.body.appendChild(script)

//服务器代码
app.get("/testJSONP",(req,res)=>{
//设置响应头 服务器给客户端发送了一个js代码块
res.header("content-type","application/javascript");
let data = JSON.stringify({"name":"zhangsan"}) ;
//服务器发送 `foo('{"name":"zhangsan"}')` 这个字符串给客户端
res.send(`foo(${data})`);
})
//如果服务器给客户端返回的js代码块中有函数调用,必须提前在客户端中声明要调用的那个函数
function foo(data){
console.log(data);
}

jQuery代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//客户端代码
$.ajax({
type:"get",
url:"http://localhost:9999/testJSONP",
data:'',
dataType: 'jsonp',
success:function(res){
$('body').append(res);
}
error:function(err){
console.log(err);
}
complete:function(xhr){
}
});

function foo(data){
console.log(data);
}

//服务器http://localhost:3000代码
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));

app.use(express.static('views'));

app.listen(3000,()=>{
console.log('running...');
});

//服务器http://localhost:8888代码
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));

app.get('/getJsonp',(req,res)=>{
res.send('foo("你拿到了http://localhost:8888的jsonp");');
});


app.listen(8888,()=>{
console.log('running...');
});

结束语

AJAX是通过XMLHttpRequest或者封装后的框架进行网络请求,由于这种方式的配置和调用方式非常混乱,已被Fetch取代

最后更新: 2019年09月02日 11:02

原始链接: https://HowlCN1997.github.io/2018/01/15/AJAX/

× 请我吃糖~
打赏二维码