原生JavaScript实现AJAX、JSONP


Posted in Javascript onFebruary 07, 2017

相信大多数前端开发者在需要与后端进行数据交互时,为了方便快捷,都会选择JQuery中封装的AJAX方法,但是有些时候,我们只需要JQuery的AJAX请求方法,而其他的功能用到的很少,这显然是没必要的。

其实,原生JavaScript实现AJAX并不难,这篇文章将会讲解如何实现简单的AJAX,还有跨域请求JSONP!

一、AJAX

AJAX的核心是XMLHttpRequest。

一个完整的AJAX请求一般包括以下步骤:

  • 实例化XMLHttpRequest对象
  • 连接服务器
  • 发送请求
  • 接收响应数据

我将AJAX请求封装成ajax()方法,它接受一个配置对象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);  
 }
}

在上面的代码中readyState的值表示请求/响应过程的当前活动阶段,其值得含义如下:

0:为初始化。尚未调用open()方法。

1:启动。已经调用open方法,但尚未调用send()方法。

2:发送。已经调用send()方法,但尚未接受到响应。

3:接收。已经接收到部分响应数据。

4:完成。已经接收到全部响应数据,并且可以在客户端使用

使用实例:

ajax({  
 url: 'test.php',  // 请求地址
 type: 'POST',  // 请求类型,默认"GET",还可以是"POST"
 data: {'b': '异步请求'},  // 传输数据
 success: function(res){  // 请求成功的回调函数
  console.log(JSON.parse(res));  
 },
 error: function(error) {}  // 请求失败的回调函数
});

二、JSONP

同源策略

AJAX之所以需要“跨域”,罪魁祸首就是浏览器的同源策略。即,一个页面的AJAX只能获取这个页面相同源或者相同域的数据。 如何叫“同源”或者“同域”呢?——协议、域名、端口号都必须相同。例如

http://example.com  和  https://example.com 不同,因为协议不同;

http://localhost:8080  和  http://localhost:1000 不同,因为端口不同;

http://localhost:8080  和  https://example.com 不同,协议、域名、端口号都不同,根本不是一家的。

当跨域请求时,一般都会看到这个错误:

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. 

那如何跨域请求呢?这时,JSONP就登场了!

JSONP是JSON with Padding(填充式JSON或参数式JSON)的简写,是一种非常常用的跨域请求方式。主要原理是利用了script 标签可以跨域请求的特性,由其 src 属性发送请求到服务器,服务器返回 JavaScript 代码,浏览器接受响应,然后就直接执行了,这和通过 script 标签引用外部文件的原理是一样的。

JSONP由两部分组成:回调函数和数据,回调函数是当响应到来时应该在页面中调用的函数,回调函数的名字一般在请求中指定。当服务器响应时,服务器端就会把该函数和数据拼成字符串返回。

JSONP的请求过程:

  • 请求阶段:浏览器创建一个 script 标签,并给其src 赋值(类似 http://example.com/api/?callback=jsonpCallback)。
  • 发送请求:当给script的src赋值时,浏览器就会发起一个请求。
  • 数据响应:服务端将要返回的数据作为参数和函数名称拼接在一起(格式类似”jsonpCallback({name: 'abc'})”)返回。当浏览器接收到了响应数据,由于发起请求的是 script,所以相当于直接调用 jsonpCallback 方法,并且传入了一个参数。

在这里讲解一下用原生JavaScript如何实现。

依旧是ajax()方法里添加JSONP,后面会将两者整合在一起,JSONP的配置参数主要多了一个jsonp参数,它就是你的回调函数名。

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);  
 }
}

注意:因为 script 标签的 src 属性只在第一次设置的时候起作用,导致 script 标签没法重用,所以每次完成操作之后要移除;

使用实例:

ajax({  
  url: 'test',  // 请求地址
 jsonp: 'jsonpCallback', // 采用jsonp请求,且回调函数名为"jsonpCallbak",可以设置为合法的字符串
 data: {'b': '异步请求'},  // 传输数据
 success:function(res){  // 请求成功的回调函数
  console.log(res);  
 },
 error: function(error) {}  // 请求失败的回调函数
});

虽然JSONP非常简单易用,不过,它也存在两点不足

  • JSONP是从其他域加载代码执行,如果其他域不安全,可能会夹带一些恶意代码,而此时除了完全放弃JSONP调用之外,没办法追究
  • 要确认JSONP请求是否失败并不容易

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
In Javascript Class, how to call the prototype method.(three method)
Jan 09 Javascript
用javascript实现在小方框中浏览大图的代码
Aug 14 Javascript
jQuery前端框架easyui使用Dialog时bug处理
Dec 05 Javascript
JavaScript模板引擎用法实例
Jul 10 Javascript
详解JavaScript正则表达式之RegExp对象
Dec 13 Javascript
AngularJS 与Bootstrap实现表格分页实例代码
Oct 14 Javascript
jquery实现弹窗功能(窗口居中显示)
Feb 27 Javascript
bootstrap multiselect下拉列表功能
Aug 22 Javascript
JavaScript实现换肤功能
Sep 15 Javascript
使用JavaScript破解web
Sep 28 Javascript
element vue Array数组和Map对象的添加与删除操作
Nov 14 Javascript
JS实现判断移动端PC端功能
Feb 21 Javascript
[原创]SyntaxHighlighter自动识别并加载脚本语言
Feb 07 #Javascript
javascript表达式和运算符详解
Feb 07 #Javascript
利用jQuery实现滑动开关按钮效果(附demo源码下载)
Feb 07 #Javascript
原生js和css实现图片轮播效果
Feb 07 #Javascript
bootstrap输入框组使用方法
Feb 07 #Javascript
angularjs使用directive实现分页组件的示例
Feb 07 #Javascript
Bootstrap下拉菜单样式
Feb 07 #Javascript
You might like
php爬取天猫和淘宝商品数据
2018/02/23 PHP
laravel框架中路由设置,路由参数和路由命名实例分析
2019/11/23 PHP
PHP rsa加密解密算法原理解析
2020/12/09 PHP
自适应图片大小的弹出窗口
2006/07/27 Javascript
js动态创建上传表单通过iframe模拟Ajax实现无刷新
2014/02/20 Javascript
JS高级调试技巧:捕获和分析 JavaScript Error详解
2014/03/16 Javascript
触屏中的JavaScript事件分析
2015/02/06 Javascript
JavaScript函数详解
2015/02/27 Javascript
javascript中的altKey 和 Event属性大全
2015/11/06 Javascript
JavaScript实现打开链接页面的方式汇总
2016/06/02 Javascript
Angular 应用技巧总结
2016/09/14 Javascript
基于JavaScript实现前端文件的断点续传
2016/10/17 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
源码分析Vue.js的监听实现教程
2017/04/23 Javascript
js制作简单的音乐播放器的示例代码
2017/08/28 Javascript
Vue项目组件化工程开发实践方案
2018/01/09 Javascript
ES6入门教程之let、const的使用方法
2019/04/13 Javascript
js找出5个数中最大的一个数和倒数第二大的数实现方法示例小结
2020/03/04 Javascript
原生JavaScript实现轮播图
2021/01/10 Javascript
python实现图片批量剪切示例
2014/03/25 Python
Python转换HTML到Text纯文本的方法
2015/01/15 Python
解决python3在anaconda下安装caffe失败的问题
2017/06/15 Python
使用Python的turtle模块画图的方法
2017/11/15 Python
Python3.5 创建文件的简单实例
2018/04/26 Python
python sys.argv[]用法实例详解
2018/05/25 Python
python之django母板页面的使用
2018/07/03 Python
利用pandas读取中文数据集的方法
2018/07/25 Python
网购亚洲时装、美容产品和生活百货:YesStyle
2016/09/15 全球购物
面向对象编程的优势是什么
2015/12/17 面试题
十八大感想感言
2014/02/10 职场文书
副总经理岗位职责
2014/03/16 职场文书
小学生开学第一课活动方案
2014/03/27 职场文书
遵纪守法演讲稿
2014/05/23 职场文书
停电放假通知
2015/04/14 职场文书
好员工观后感
2015/06/17 职场文书
巾帼建功标兵先进事迹材料
2016/02/29 职场文书