I believe that when most front-end developers need to interact with the back-end data, for convenience and speed, they will choose JQuery
the method encapsulated in the middle AJAX
, but sometimes, we only need JQuery
the AJAX
request method, and other functions are rarely used, which is obviously is not necessary.
In fact, the native JavaScript
implementation AJAX
is not difficult. This article will explain how to implement simple AJAX
and cross-domain requests JSONP
!
First,
the core of AJAX AJAX is XMLHttpRequest
.
A complete AJAX
request generally includes the following steps:
- instantiated
XMLHttpRequest
object - connect to the server
- send request
- receive response data
I AJAX
encapsulate the request into a ajax()
method that accepts a configuration object params
.
function ajax(params) {
params = params || {};
params.data = params.data || {};
// 判断是ajax请求还是jsonp请求
var json = params.jsonp ? jsonp(params) : json(params);
// ajax请求
function json(params) {
// 请求方式,默认是GET
params.type = (params.type || 'GET').toUpperCase();
// 避免有特殊字符,必须格式化传输数据
params.data = formatParams(params.data);
var xhr = null;
// 实例化XMLHttpRequest对象
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
// IE6及其以下版本
xhr = new ActiveXObjcet('Microsoft.XMLHTTP');
};
// 监听事件,只要 readyState 的值变化,就会调用 readystatechange 事件
xhr.onreadystatechange = function() {
// readyState属性表示请求/响应过程的当前活动阶段,4为完成,已经接收到全部响应数据
if(xhr.readyState == 4) {
var status = xhr.status;
// status:响应的HTTP状态码,以2开头的都是成功
if(status >= 200 && status < 300) {
var response = '';
// 判断接受数据的内容类型
var type = xhr.getResponseHeader('Content-type');
if(type.indexOf('xml') !== -1 && xhr.responseXML) {
response = xhr.responseXML; //Document对象响应
} else if(type === 'application/json') {
response = JSON.parse(xhr.responseText); //JSON响应
} else {
response = xhr.responseText; //字符串响应
};
// 成功回调函数
params.success && params.success(response);
} else {
params.error && params.error(status);
}
};
};
// 连接和传输数据
if(params.type == 'GET') {
// 三个参数:请求方式、请求地址(get方式时,传输数据是加在地址后的)、是否异步请求(同步请求的情况极少);
xhr.open(params.type, params.url + '?' + params.data, true);
xhr.send(null);
} else {
xhr.open(params.type, params.url, true);
//必须,设置提交时的内容类型
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
// 传输数据
xhr.send(params.data);
}
}
//格式化参数
function formatParams(data) {
var arr = [];
for(var name in data) {
// encodeURIComponent() :用于对 URI 中的某一部分进行编码
arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
};
// 添加一个随机数参数,防止缓存
arr.push('v=' + random());
return arr.join('&');
}
// 获取随机数
function random() {
return Math.floor(Math.random() * 10000 + 500);
}
}
In the above code, specific comments have been added. If you want to know more , you can check the chapter in the AJAX
blogger's book " JavaScript Half-Knowledge " : AJAX usage example:AJAX
ajax({
url: 'test.php', // 请求地址
type: 'POST', // 请求类型,默认"GET",还可以是"POST"
data: {'b': '异步请求'}, // 传输数据
success: function(res){ // 请求成功的回调函数
console.log(JSON.parse(res));
},
error: function(error) {} // 请求失败的回调函数
});
Second, the reason why JSONP same-
origin policy
AJAX needs to be "cross-domain" is the browser's culprit 同源策略
. That is, the AJAX of a page can only obtain the data of the same source or the same domain of the page. How to call it "same origin" or "same domain"? — 协议、域名、端口号都必须相同
. E.g:
http://example.com 和 https://example.com 不同,因为协议不同;
http://localhost:8080 和 http://localhost:1000 不同,因为端口不同;
http://localhost:8080 和 https://example.com 不同,协议、域名、端口号都不同,根本不是一家的。
When making cross-domain requests, this error is generally seen: XMLHttpRequest cannot load http://ghmagical.com/article/?intro=jsonp%E8%AF%B7%E6%B1%82&v=5520. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
how about cross-domain requests? At this time, JSONP comes on stage!
JSONP (JSON with Padding) is a cross-domain request method. The main principle is to use the script
feature that tags can make cross-domain requests, send a request to the server by its src
attributes, the server returns the JavaScript
code, the browser accepts the response, and then executes it directly, which script
is the same as the principle of referencing external files through tags.
JSONP consists of two parts: 回调函数
and 数据
, the callback function is generally controlled by the browser and sent to the server as a parameter (of course, you can also fix the name of the callback function, but the names of the client and server must be the same). When the server responds, the server will combine the function and data into a string and return it.
JSONP request process:
- Request phase: The browser creates a
script
tag and assigns it asrc
value (similarhttp://example.com/api/?callback=jsonpCallback
). - Sending a request: When a
script
valuesrc
is assigned to , the browser will initiate a request. - Data response: The server will return the data to be returned
数据
as a parameter and函数名称
spliced together (the format is similar to "jsonpCallback({name: 'abc'})
"). When the browser receives the response data, since the request is initiatedscript
, it is equivalent to callingjsonpCallback
the method directly and passing in a parameter.
For JQuery
the JSONP request, I won't talk much about it here. I also wrote an article " JQuery's Ajax request cross-domain problem ".
Here's JavaScript
how to do it natively.
JSONP is still ajax()
added to the method, and the two will be integrated later. The configuration parameters of JSONP mainly have one more jsonp
parameter, which is the name of your callback function.
function ajax(params) {
params = params || {};
params.data = params.data || {};
var json = params.jsonp ? jsonp(params) : json(params);
// jsonp请求
function jsonp(params) {
//创建script标签并加入到页面中
var callbackName = params.jsonp;
var head = document.getElementsByTagName('head')[0];
// 设置传递给后台的回调参数名
params.data['callback'] = callbackName;
var data = formatParams(params.data);
var script = document.createElement('script');
head.appendChild(script);
//创建jsonp回调函数
window[callbackName] = function(json) {
head.removeChild(script);
clearTimeout(script.timer);
window[callbackName] = null;
params.success && params.success(json);
};
//发送请求
script.src = params.url + '?' + data;
//为了得知此次请求是否成功,设置超时处理
if(params.time) {
script.timer = setTimeout(function() {
window[callbackName] = null;
head.removeChild(script);
params.error && params.error({
message: '超时'
});
}, time);
}
};
//格式化参数
function formatParams(data) {
var arr = [];
for(var name in data) {
arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
};
// 添加一个随机数,防止缓存
arr.push('v=' + random());
return arr.join('&');
}
// 获取随机数
function random() {
return Math.floor(Math.random() * 10000 + 500);
}
}
Note : Because script
the attributes of the label src
only work when it is set for the first time, the script
label cannot be reused, so it must be removed after each operation;
use example:
ajax({
url: 'test.php', // 请求地址
jsonp: 'jsonpCallback', // 采用jsonp请求,且回调函数名为"jsonpCallbak",可以设置为合法的字符串
data: {'b': '异步请求'}, // 传输数据
success:function(res){ // 请求成功的回调函数
console.log(res);
},
error: function(error) {} // 请求失败的回调函数
});
Use PHP processing in the background here:
<?php
$data = array('type'=>'jsonp');
$callback = isset($_GET['callback']) ? trim($_GET['callback']) : '';
echo $callback.'('.json_encode($data).')';
Note : Don't forget to use the function name and data to concatenate the return.
Of course, as mentioned earlier, you can give a fixed callback function name:
function jsonpCallback() {}
<?php
echo 'jsonpCallback('.$data.
Finally I have merged AJAX
with JSONP
the request, download link: ajax.zip