Native JavaScript implements AJAX, JSONP

I believe that when most front-end developers need to interact with the back-end data, for convenience and speed, they will choose JQuerythe method encapsulated in the middle AJAX, but sometimes, we only need JQuerythe AJAXrequest method, and other functions are rarely used, which is obviously is not necessary. 
In fact, the native JavaScriptimplementation AJAXis not difficult. This article will explain how to implement simple AJAXand cross-domain requests JSONP
First, 
the core of AJAX AJAX is XMLHttpRequest
A complete AJAXrequest generally includes the following steps:

  • instantiated XMLHttpRequestobject
  • connect to the server
  • send request
  • receive response data


I AJAXencapsulate 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 AJAXblogger'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 a src value (similar  http://example.com/api/?callback=jsonpCallback ).
  • Sending a request: When a scriptvalue srcis 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 initiated  script, it is equivalent to calling  jsonpCallback the method directly and passing in a parameter.


For JQuerythe JSONP request, I won't talk much about it here. I also wrote an article " JQuery's Ajax request cross-domain problem ". 
Here's JavaScripthow 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 jsonpparameter, 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 AJAXwith JSONPthe request, download link:  ajax.zip 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324985248&siteId=291194637