jquery中ajax处理跨域的三大方式


Posted in Javascript onJanuary 05, 2016

由于JS同源策略的影响,因此js只能访问同域名下的文档。因此要实现跨域,一般有以下几个方法:

一、处理跨域的方式:

1.代理

2.XHR2

HTML5中提供的XMLHTTPREQUEST Level2(及XHR2)已经实现了跨域访问。但ie10以下不支持

只需要在服务端填上响应头:

header("Access-Control-Allow-Origin:*");
 /*星号表示所有的域都可以接受,*/
 header("Access-Control-Allow-Methods:GET,POST");

3.jsonP

原理:

 ajax本身是不可以跨域的,
通过产生一个script标签来实现跨域。因为script标签的src属性是没有跨域的限制的。

其实设置了dataType: 'jsonp'后,$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议。JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问。

 ajax的跨域写法:

(其余写法和不跨域的一样):

比如 

/*当前网址是localhost:3000*/
 js代码
 
 $.ajax({
 type:"get",
 url:"http://localhost:3000/showAll",/*url写异域的请求地址*/
 dataType:"jsonp",/*加上datatype*/
 jsonpCallback:"cb",/*设置一个回调函数,名字随便取,和下面的函数里的名字相同就行*/
 success:function(){
 。。。
 }
 });

 /*而在异域服务器上,*/
 app.js
 app.get('/showAll',students.showAll);/*这和不跨域的写法相同*/
 
 
 /*在异域服务器的showAll函数里,*/

 var db = require("./database");

 exports.showAll = function(req,res){

 /**设置响应头允许ajax跨域访问**/
 res.setHeader("Access-Control-Allow-Origin","*");
 /*星号表示所有的异域请求都可以接受,*/
 res.setHeader("Access-Control-Allow-Methods","GET,POST");

 var con = db.getCon();
 con.query("select * from t_students",function(error,rows){
 if(error){
 console.log("数据库出错:"+error);
 }else{
 /*注意这里,返回的就是jsonP的回调函数名+数据了*/
 res.send("cb("+JSON.stringify(r)+")");
 }
 });
 }

二、解决ajax跨域访问、 JQuery 的跨域方法

 JS的跨域问题,我想很多程序员的脑海里面还认为JS是不能跨域的,其实这是一个错误的观点;有很多人在网上找其解决方法,教其用IFRAME去解决的文章很多,真有那么复杂吗?其实很简单的,如果你用JQUERY,一个GETJSON方法就搞定了,而且是一行代码搞定。

下面开始贴出方法。

//跨域(可跨所有域名)
$.getJSON("http://user.hnce.com.cn/getregion.aspx?id=0&jsoncallback=?",function(json){ 
//要求远程请求页面的数据格式为: ?(json_data) //例如: //?([{"_name":"湖南省","_regionId":134},{"_name":"北京市","_regionId":143}]) alert(json[0]._name); 
}); 

$.getJSON("http://user.hnce.com.cn/getregion.aspx?id=0&jsoncallback=?",function(json){ 
//要求远程请求页面的数据格式为: ?(json_data) //例如: //?([{"_name":"湖南省","_regionId":134},{"_name":"北京市","_regionId":143}]) alert(json[0]._name); 
});

 注意,getregion.aspx中,在输出JSON数据时,一定要用Request.QueryString["jsoncallback"],将获取的内容放到返回JSON数据的前面,假设实际获取的值为42342348,那么返回的值就是 42342348([{"_name":"湖南省","_regionId":134},{"_name":"北京市","_regionId":143}])

因为getJSON跨域的原理是把?随机变一个方法名,然后返回执行的,实现跨域响应的目的。

下面一个是跨域执行的真实例子:

<script src="http://common.cnblogs.com/script/jquery.js" type="text/javascript"></script> 
<script type="text/javascript"> 
//跨域(可跨所有域名) 
$.getJSON("http://e.hnce.com.cn/tools/ajax.aspx?jsoncallback=?", { id: 0, action: 'jobcategoryjson' }, function(json) { alert(json[0].pid); alert(json[0].items[0]._name); });  
 </script>
<script src="http://common.cnblogs.com/script/jquery.js" type="text/javascript"></script> 
<script type="text/javascript"> 
//跨域(可跨所有域名) 
$.getJSON("http://e.hnce.com.cn/tools/ajax.aspx?jsoncallback=?", { id: 0, action: 'jobcategoryjson' }, function(json) { alert(json[0].pid); alert(json[0].items[0]._name); });  
 </script>

jQuery跨域原理:

浏览器会进行同源检查,这导致了跨域问题,然而这个跨域检查还有一个例外那就是HTML的<Script>标记;我们经常使用<Script>的src属性,脚本静态资源放在独立域名下或者来自其它站点的时候这里是一个url;这个url响应的结果可以有很多种,比如JSON,返回的Json值成为<Script>标签的src属性值.这种属性值变化并不会引起页面的影响.按照惯例,浏览器在URL的查询字符串中提供一个参数,这个参数将作为结果的前缀一起返回到浏览器;

看下面的例子:

<script type="text/javascript" src="http://domain2.com/getjson?jsonp=parseResponse"> </script> 
响应值:parseResponse({"Name": "Cheeso", "Rank": 7}) 
<script type="text/javascript" src="http://domain2.com/getjson?jsonp=parseResponse"> </script> 
响应值:parseResponse({"Name": "Cheeso", "Rank": 7})

这种方式被称作JsonP;(如果链接已经失效请点击这里:JSONP);即:JSON with padding 上面提到的前缀就是所谓的“padding”。那么jQuery里面是怎么实现的呢?

貌似并没有<Script>标记的出现!?OKay,翻看源码来看:

页面调用的是getJSON:

getJSON: function( url, data, callback ) {
 return jQuery.get(url, data, callback, "json");
 },

 继续跟进

get: function( url, data, callback, type ) {
 // shift arguments if data argument was omited
 if ( jQuery.isFunction( data ) ) {
  type = type || callback;
  callback = data;
  data = null;
 }
 
 return jQuery.ajax({
  type: "GET",
  url: url,
  data: data,
  success: callback,
  dataType: type
 });

跟进jQuery.ajax,下面是ajax方法的代码片段:

// Build temporary JSONP function
 if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
 jsonp = s.jsonpCallback || ("jsonp" + jsc++);
 
 // Replace the =? sequence both in the query string and the data
 if ( s.data ) {
 s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
 }
 
 s.url = s.url.replace(jsre, "=" + jsonp + "$1");
 
 // We need to make sure
 // that a JSONP style response is executed properly
 s.dataType = "script";
 
 // Handle JSONP-style loading
 window[ jsonp ] = window[ jsonp ] || function( tmp ) {
 data = tmp;
 success();
 complete();
 // Garbage collect
 window[ jsonp ] = undefined;
 
 try {
  delete window[ jsonp ];
 } catch(e) {}
 
 if ( head ) {
  head.removeChild( script );
 }
 };
 }
 
 if ( s.dataType === "script" && s.cache === null ) {
 s.cache = false;
 }
 
 if ( s.cache === false && type === "GET" ) {
 var ts = now();
 
 // try replacing _= if it is there
 var ret = s.url.replace(rts, "$1_=" + ts + "$2");
 
 // if nothing was replaced, add timestamp to the end
 s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
 }

 // If data is available, append data to url for get requests
 if ( s.data && type === "GET" ) {
 s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
 }
 
 // Watch for a new set of requests
 if ( s.global && ! jQuery.active++ ) {
 jQuery.event.trigger( "ajaxStart" );
 }
 
 // Matches an absolute URL, and saves the domain
 var parts = rurl.exec( s.url ),
 remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
 
 // If we're requesting a remote document
 // and trying to load JSON or Script with a GET
 if ( s.dataType === "script" && type === "GET" && remote ) {
 var head = document.getElementsByTagName("head")[0] || document.documentElement;
 var script = document.createElement("script");
 script.src = s.url;
 if ( s.scriptCharset ) {
 script.charset = s.scriptCharset;
 }
 
 // Handle Script loading
 if ( !jsonp ) {
 var done = false;
 
 // Attach handlers for all browsers
 script.onload = script.onreadystatechange = function() {
  if ( !done && (!this.readyState ||
  this.readyState === "loaded" || this.readyState === "complete") ) {
  done = true;
  success();
  complete();
 
  // Handle memory leak in IE
  script.onload = script.onreadystatechange = null;
  if ( head && script.parentNode ) {
  head.removeChild( script );
  }
  }
 };
 }
 
 // Use insertBefore instead of appendChild to circumvent an IE6 bug.
 // This arises when a base node is used (#2709 and #4378).
 head.insertBefore( script, head.firstChild );
 
 // We handle everything using the script element injection
 return undefined;
 }

上面的代码第1行到第10行:判断是JSON类型调用,为本次调用创建临时的JsonP方法,并且添加了一个随机数字,这个数字源于用日期值;

 关注第14行,这一行相当关键,注定了我们的结果最终是<Script> ;然后是构造Script片段,第95行在Head中添加该片段,修成正果;

 不仅仅是jQuery,很多js框架都是用了同样的跨域方案,这就是getJSON跨域的原理。

更多精彩内容,请点击《ajax跨域技术汇总》,进行深入学习和研究。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery实现省市select下拉框的替换(示例代码)
Feb 22 Javascript
javascript日期格式化方法汇总
Oct 04 Javascript
jquery遍历函数siblings()用法实例
Dec 24 Javascript
Javascript的表单验证长度
Mar 16 Javascript
AngularJS 面试题集锦
Sep 06 Javascript
神级程序员JavaScript300行代码搞定汉字转拼音
May 20 Javascript
详解通过JSON数据使用VUE.JS
May 26 Javascript
Express下采用bcryptjs进行密码加密的方法
Feb 07 Javascript
微信小程序实现跳转的几种方式总结(推荐)
Apr 24 Javascript
vue中使用mxgraph的方法实例代码详解
May 17 Javascript
vue项目中播放rtmp视频文件流的方法
Sep 17 Javascript
浅谈Vue使用Cascader级联选择器数据回显中的坑
Oct 31 Javascript
基于JavaScript代码实现随机漂浮图片广告
Jan 05 #Javascript
多个js毫秒倒计时同时进行效果
Jan 05 #Javascript
在WordPress中加入Google搜索功能的简单步骤讲解
Jan 04 #Javascript
实例详解jQuery结合GridView控件的使用方法
Jan 04 #Javascript
jQuery EasyUI之DataGrid使用实例详解
Jan 04 #Javascript
JavaScript原型及原型链终极详解
Jan 04 #Javascript
jQuery实现简单的点赞效果
May 29 #Javascript
You might like
php Undefined index和Undefined variable的解决方法
2008/03/27 PHP
使用PHP+MySql实现微信投票功能实例代码
2017/09/29 PHP
PHP实用小技巧之调用录像的方法
2019/12/05 PHP
用js写了一个类似php的print_r输出换行功能
2013/02/18 Javascript
如何使用jQUery获取选中radio对应的值(一句代码)
2013/06/03 Javascript
jquery中的事件处理详细介绍
2013/06/24 Javascript
A标签触发onclick事件而不跳转的多种解决方法
2013/06/27 Javascript
javaScript 动态访问JSon元素示例代码
2013/08/30 Javascript
js实现俄罗斯方块小游戏分享
2014/01/31 Javascript
JS实现FLASH幻灯片图片切换效果的方法
2015/03/04 Javascript
jQuery实现简单的间隔向上滚动效果
2015/03/09 Javascript
基于Bootstrap重置输入框内容按钮插件
2016/05/12 Javascript
javascript实现任务栏消息提示的简单实例
2016/05/31 Javascript
关于Javascript回调函数的一个妙用
2016/08/29 Javascript
javascript实现QQ空间相册展示源码
2017/12/12 Javascript
Vue 2.0学习笔记之使用$refs访问Vue中的DOM
2017/12/19 Javascript
jQuery实现带右侧索引功能的通讯录示例【附源码下载】
2018/04/17 jQuery
Webpack中雪碧图插件使用详解
2018/05/25 Javascript
解决echarts的多个折现数据出现坐标和值对不上的问题
2018/12/28 Javascript
python学习——内置函数、数据结构、标准库的技巧(推荐)
2019/04/18 Python
Pycharm同步远程服务器调试的方法步骤
2020/11/04 Python
纯CSS3实现的8种Loading动画效果
2014/07/05 HTML / CSS
国际知名设计师时装商店:Coggles
2016/09/05 全球购物
Shopee菲律宾:在线购买和出售
2019/11/25 全球购物
英国领先的电动可调床制造商:Laybrook
2019/12/26 全球购物
巴西购物网站:Submarino
2020/01/19 全球购物
大学军训感言800字
2014/02/27 职场文书
大学生入党推荐书范文
2014/05/17 职场文书
2015元旦联欢晚会结束语
2014/12/14 职场文书
预防艾滋病宣传活动总结
2015/05/09 职场文书
2015年销售助理工作总结
2015/05/11 职场文书
辞职信格式范文
2015/05/13 职场文书
2015年社区宣传工作总结
2015/05/20 职场文书
Python爬取某拍短视频
2021/06/11 Python
Golang使用Panic与Recover进行错误捕获
2022/03/22 Golang
mysql 子查询的使用
2022/04/28 MySQL