前端开发在需要与后端进行数据交互时,为了方便快捷,都会选择JQuery中封装的AJAX方法,但是有些时候,我们只需要JQuery的AJAX请求方法,而其他的功能用到的很少,这显然是没必要的。其实,原生JavaScript实现AJAX并不难,下面我们可是演示如何实现利用原生JS构建简单的AJAX,还有跨域请求JSONP的实现。
AJAX的根本是XMLHttprequest,而一个完整的AJAX请求一般包括以下步骤:
- 实例化XMLHttpRequest对象
- 连接服务器
- 发送请求
- 接收响应数据
下面我们使用原生JS封装一个简单地ajax()方法:
1 const Ajax = (object) => {
2 object = object || {};
3 object.data = object.data || {};
4 //判断请求类型为AJAX或者JSONP
5 let json = object.jsonp ? Jsonp(object) : ajax(object);
6
7 //设置ajax方法
8 function ajax(object) {
9 // 1.设置请求方式:如果没有制定则默认为GET
10 object.type = (object.type || 'GET').toUpperCase();
11 // 2.设置data数据的格式化
12 object.data = formateObject(object.data);
13 // 3.实例化XMLHttpRequest对象
14 var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
15 // 4.监听事件,只要readyState改变,就会调用readystatechange事件
16 xhr.onreadystatechange = function(){
17 // readyState属性表示请求/响应过程的当前活动阶段,4为完成,已经接收到全部响应数据
18 if(xhr.readyState == 4) {
19 let status = xhr.status;
20 // status : HTTP响应的状态码,2开头表示成功
21 if(status >=200 && status < 300){
22 let response = '';
23 // 判断接受数据的内容类型
24 let type = xhr.getResponseHeader('Content-type');
25 if(type.indexOf('xml') !== -1 && xhr.responseXML) {
26 response = xhr.responseXML; //Document对象响应
27 } else if(type === 'application/json') {
28 response = JSON.parse(xhr.responseText); //JSON响应
29 } else {
30 response = xhr.responseText; //字符串响应
31 };
32 // 成功回调函数
33 object.success && object.success(response);
34 }else {
35 object.error && object.error(response);
36 }
37 }
38 }
39
40
41 // 5.连接和传输数据
42 if(object.type == 'GET') {
43 // 三个参数:请求方式、请求地址(get方式时,传输数据是加在地址后的)、是否异步请求(同步请求的情况极少);
44 xhr.open(object.type, object.url + '?' + object.data, true);
45 xhr.send(null);
46 } else {
47 xhr.open(object.type, object.url, true);
48 //必须,设置提交时的内容类型
49 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
50 // 传输数据
51 xhr.send(object.data);
52 }
53 }
54
55 //data的格式化方法
56 function formateObject(data){
57 if(data){
58 let arr = [];
59 for(let name in data){
60 //encodeURIComponent() :用于对 URI 中的某一部分进行编码
61 arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
62 }
63
64 //为了防止缓存,在后面添加一个随机数
65 arr.push('randomV=' + randomNumber());
66 return arr.join('&');
67 }else {
68 console.error('无法格式化请求数据')
69 }
70 }
71
72 //生成随机数的方法
73 function randomNumber(){
74 return Math.floor(Math.random()*10000+404);
75 }
76
77 };
同理,我们也可以实现一个JSONP的方法
//设置Jsonp方法
function Jsonp(object) {
// 创建script标签并加入到页面中
let callbackName = object.jsonp,
head = document.getElementsByTagName('head')[0];
// 设置传递给后台的回调参数名
object.data['callback'] = callbackName;
let data = formateObject(object.data),
script = document.createElement('script');
head.appendChild(script);
// 创建JSONP的回调函数
//创建jsonp回调函数
window[callbackName] = function(json) {
head.removeChild(script);
clearTimeout(script.timer);
window[callbackName] = null;
object.success && object.success(json);
};
// 发送请求
script.src = object.url + '?' + data;
//为了得知此次请求是否成功,设置超时处理
if(object.time) {
script.timer = setTimeout(function() {
window[callbackName] = null;
head.removeChild(script);
object.error && object.error({
message: '请求超时'
});
}, time);
}
}
下面我们来尝试一下这两个方法是否管用
新建一个index.html文件,新建一个test.json和jsonp.php
利用nginx搭建一个简单地服务器,因为谷歌默认不允许本地文件进行ajax请求:
test.json内容
1 {
2 "name" : "111",
3 "gender" : "222"
4 }
jsonp.php内容:
callback({"name":"李大师","gender":"是前端开发工程师"})
index.html内容
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="Generator" content="EditPlus®">
6 <meta name="Author" content="">
7 <meta name="Keywords" content="">
8 <meta name="Description" content="">
9 <title>原生JS实现ajax和JSONP请求</title>
10 <style type="text/css">
11 input[type='button'] {
12 margin:20px;
13 }
14 </style>
15 </head>
16 <body>
17 <button>点击验证AJAX</button>
18 <input type="button" value="点击验证JSONP" onclick="">
19 <div id="div1" class="">
20
21 </div>
22 </body>
23 <script type="text/javascript">
24 <!--
25 //原生JS方法封装AJAX请求和JSONP请求
26
27 window.Ajax = (object) => {
28 object = object || {};
29 object.data = object.data || {};
30 //判断请求类型为AJAX或者JSONP
31 let json = object.jsonp ? Jsonp(object) : ajax(object);
32
33 //设置ajax方法
34 function ajax(object) {
35 // 1.设置请求方式:如果没有制定则默认为GET
36 object.type = (object.type || 'GET').toUpperCase();
37 // 2.设置data数据的格式化
38 object.data = formateObject(object.data);
39 // 3.实例化XMLHttpRequest对象
40 var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
41 // 4.监听事件,只要readyState改变,就会调用readystatechange事件
42 xhr.onreadystatechange = function(){
43 // readyState属性表示请求/响应过程的当前活动阶段,4为完成,已经接收到全部响应数据
44 if(xhr.readyState == 4) {
45 let status = xhr.status;
46 // status : HTTP响应的状态码,2开头表示成功
47 if(status >=200 && status < 300){
48 let response = '';
49 // 判断接受数据的内容类型
50 let type = xhr.getResponseHeader('Content-type');
51 if(type.indexOf('xml') !== -1 && xhr.responseXML) {
52 response = xhr.responseXML; //Document对象响应
53 } else if(type === 'application/json') {
54 response = JSON.parse(xhr.responseText); //JSON响应
55 } else {
56 response = xhr.responseText; //字符串响应
57 };
58 // 成功回调函数
59 object.success && object.success(response);
60 }else {
61 object.error && object.error(response);
62 }
63 }
64 }
65
66
67 // 5.连接和传输数据
68 if(object.type == 'GET') {
69 // 三个参数:请求方式、请求地址(get方式时,传输数据是加在地址后的)、是否异步请求(同步请求的情况极少);
70 xhr.open(object.type, object.url + '?' + object.data, true);
71 xhr.send(null);
72 } else {
73 xhr.open(object.type, object.url, true);
74 //必须,设置提交时的内容类型
75 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
76 // 传输数据
77 xhr.send(object.data);
78 }
79 }
80
81 //设置Jsonp方法
82 function Jsonp(object) {
83 // 创建script标签并加入到页面中
84 let callbackName = object.jsonp,
85 head = document.getElementsByTagName('head')[0];
86 // 设置传递给后台的回调参数名
87 object.data['callback'] = callbackName;
88 let data = formateObject(object.data),
89 script = document.createElement('script');
90 head.appendChild(script);
91 // 创建JSONP的回调函数
92 //创建jsonp回调函数
93 window[callbackName] = function(json) {
94 head.removeChild(script);
95 clearTimeout(script.timer);
96 window[callbackName] = null;
97 object.success && object.success(json);
98 };
99 // 发送请求
100 script.src = object.url + '?' + data;
101 //为了得知此次请求是否成功,设置超时处理
102 if(object.time) {
103 script.timer = setTimeout(function() {
104 window[callbackName] = null;
105 head.removeChild(script);
106 object.error && object.error({
107 message: '请求超时'
108 });
109 }, time);
110 }
111
112 }
113
114
115 //data的格式化方法
116 function formateObject(data){
117 if(data){
118 let arr = [];
119 for(let name in data){
120 //encodeURIComponent() :用于对 URI 中的某一部分进行编码
121 arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
122 }
123
124 //为了防止缓存,在后面添加一个随机数
125 arr.push('randomV=' + randomNumber());
126 return arr.join('&');
127 }else {
128 console.error('无法格式化请求数据')
129 }
130 }
131
132 //生成随机数的方法
133 function randomNumber(){
134 return Math.floor(Math.random()*10000+404);
135 }
136
137 };
138
139
140 const button = document.querySelector('input[type="button"]');
141 const btn = document.querySelector('button');
142
143 const successFun = (res) => {
144 console.log(res);
145 let div1= document.querySelector("#div1");
146 div1.innerHTML = res.name + res.gender;
147 };
148 const obj = {
149 url : 'jsonp.php',
150 type : 'GET',
151 jsonp : 'callback',
152 data : '',
153 success: successFun,
154 error: function(){
155 }
156 };
157
158 const obj1 = {
159 url : 'test.json',
160 type : 'GET',
161 data : '',
162 success: successFun,
163 error: function(){
164 }
165 };
166
167
168 button.addEventListener('click', () => Ajax(obj));
169 btn.addEventListener('click',() => Ajax(obj1));
170
171
172 //-->
173 </script>
174 </html>
测试效果:
验证JSONP: