原生 JavaScript 实现 AJAX、JSONP
相信大多数前端开发者在需要与后端进行数据交互时,为了方便快捷,都会选择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);
}
}
在上面的代码中,已经添加具体的注释,如需了解更多AJAX,可查看博主的书籍《 JavaScript半知半解》中的 AJAX章节:AJAX
使用实例:
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) 是一种跨域请求方式。主要原理是利用了script 标签可以跨域请求的特性,由其 src 属性发送请求到服务器,服务器返回 JavaScript 代码,浏览器接受响应,然后就直接执行了,这和通过 script 标签引用外部文件的原理是一样的。
JSONP由两部分组成:回调函数和数据,回调函数一般是在浏览器控制,作为参数发往服务器端(当然,你也可以固定回调函数的名字,但客户端和服务器端的名称一定要一致)。当服务器响应时,服务器端就会把该函数和数据拼成字符串返回。
JSONP的请求过程:
- 请求阶段:浏览器创建一个
script标签,并给其src赋值(类似http://example.com/api/?callback=jsonpCallback)。 - 发送请求:当给
script的src赋值时,浏览器就会发起一个请求。 - 数据响应:服务端将要返回的
数据作为参数和函数名称拼接在一起(格式类似”jsonpCallback({name: 'abc'})”)返回。当浏览器接收到了响应数据,由于发起请求的是script,所以相当于直接调用jsonpCallback方法,并且传入了一个参数。
对于JQuery的JSONP请求,这里就不多讲了,之前也写过一篇文章《JQuery的Ajax请求跨域问题》。
在这里讲解一下用原生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.php', // 请求地址
jsonp: 'jsonpCallback', // 采用jsonp请求,且回调函数名为"jsonpCallbak",可以设置为合法的字符串
data: {'b': '异步请求'}, // 传输数据
success:function(res){ // 请求成功的回调函数
console.log(res);
},
error: function(error) {} // 请求失败的回调函数
});
在这里后台使用PHP处理:
<?php
$data = array('type'=>'jsonp');
$callback = isset($_GET['callback']) ? trim($_GET['callback']) : '';
echo $callback.'('.json_encode($data).')';
注意:别漏了用函数名与数据拼接返回。
当然,前面也说过,你可以给定固定回调函数名:
function jsonpCallback() {}
<?php
echo 'jsonpCallback('.$data.
最后我已经将AJAX和JSONP请求合并在一起了,下载链接: ajax.zip
原生 JavaScript 实现 AJAX、JSONP的更多相关文章
- 原生JavaScript实现AJAX、JSONP
相信大多数前端开发者在需要与后端进行数据交互时,为了方便快捷,都会选择JQuery中封装的AJAX方法,但是有些时候,我们只需要JQuery的AJAX请求方法,而其他的功能用到的很少,这显然是没必要的 ...
- 原生JavaScript写AJAX
前端JavaScript: function ajaxGet(url, obj) { var request; if(window.XMLHttpRequest) { request = new XM ...
- 原生javaScript完成Ajax请求
使用原生javaScript完成Ajax请求,首先应该创建一个对象XMLHttprequest,考虑到兼容低版本IE浏览器,使用ActiveXObject对象,代码入下: var request; i ...
- 原生JavaScript 封装ajax
原生JavaScript 封装ajax function myajax(options){ //新建一个局部对象 用来存放用户输入的各种参数 var opt={ type:options.type ...
- 原生JavaScript封装的jsonp跨域请求
原生JavaScript封装的jsonp跨域请求 <!DOCTYPE html> <html lang="en"> <head> <met ...
- 用原生JavaScript写AJAX
//原生js写ajax就像打电话 //打电话分下面4步//1.拿出手机//2.拨号//3.说话//4.听对方说话 //ajax也分下面4步//1.创建ajax对象//2.连接到服务器//3.发送请求( ...
- 原生javascript封装ajax和jsonp
在我们请求数据时,完成页面跨域,利用原生JS封装的ajax和jsonp: <!DOCTYPE html> <html lang="en"> <head ...
- 原生javascript实现ajax,post参数
var json = { userid: userid, cid: cid, openid: openid, type: 1 }; // 原生ajax json = (function(obj){ / ...
- 原生JavaScript封装Ajax
第一次开个人技术博客了,发的第一篇技术文章,欢迎指点…… 欢迎访问本人的独立博客:蓝克比尔 Ajax的实现主要分为四部分: 1.创建Ajax对象 // 创建ajax对象 var xhr = null; ...
随机推荐
- 在eclipse中方便的比较各个语言 资源文件—jinto的安装
一.下载与安装jinto Eclipse插件的插件,用来解决资源文件的国际化问题 用jinto编辑器打开properties文件后,就可以方便的建立出各国和各种语言的资源文件,同时可以方便的对比书写各 ...
- AWS服务学习
什么是云计算? 云计算是用户通过Internet云服务平台按需提供计算能力.数据库存储.应用程序和其他IT资源,采用按需支付定价模式 无论您是在运行拥有数百万移动用户的照片共享应用程序,还是要为您的业 ...
- Jar版本:java.lang.UnsupportedClassVersionError: ******
错误原因编译Java和运行Java所使用的Java的版本不一致导致:解决办法修改运行环境的Java版本或者修改编译环境的Java版本,让两者保持一致即可: java.lang.UnsupportedC ...
- 关于服务器端的Json文件的接收,踩了一早上的坑的问题
JSON文件的发送和接收 服务器端接收的JSON文件也是String型的文件,因此不可以直接写成如下的格式,此错误格式下无法找到发送的{}内的数据,服务器会报错提示无法找到你需要的类型数据,也就是根本 ...
- 关于Java集合类库中的几种常用队列
Java中几种常用的队列 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞 ...
- 2-8 R语言基础 日期与时间
#日期 Date > x<-date()> class(x)[1] "character" > x2 <- Sys.Date()> class( ...
- Android友盟推送
当前版本号:v3.0.5 1.下载SDK解压并导入(import module,compile project(':PushSDK')),里面有demo,用demo的包名去官网添加一个应用,然后替换d ...
- 2.2.1 LinearLayout(线性布局)
本节引言 本节开始讲Android中的布局,Android中有六大布局,分别是: LinearLayout(线性布局), RelativeLayout(相对布局), TableLayout(表格布局) ...
- windows10 + anaconda + tensorflow-1.5.0 + python-3.6 + keras-2.2.4配置和安装
windows10 + anaconda + tensorflow-1.5.0 + python-3.6 + keras-2.2.4配置和安装 (base) C:\Users\jiangshan> ...
- scrapy (四)基本配置
scrapy使用细节配置 一.建立项目 1.scrapy startproject 项目名字 2.进入项目: scrapy genspider 名字 不带http的根网址 3.默认模板(或改变模板) ...