JS、JQuery和ExtJs的跨域处理

时间:2022-02-28 02:24:14

1.什么是跨域?
跨域,JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当一个百度浏览器执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。
更详细的说明可以看下表:

URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不同域名 不允许

特别注意两点:
(1).如果是协议和端口造成的跨域问题“前台”是无能为力的,
(2).在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

2.跨域请求数据解决方案
(1).document.domain+iframe的设置
对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。
(2).动态创建Script
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以*执行引入的JS文件中的function(包括操作cookie、Dom等等)。
(3).利用iframe和location.hash
这个办法比较绕,但是可以解决完全跨域情况下的脚步置换问题。原理是利用location.hash来进行传值。
(4).Window.name实现的跨域数据传输
iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
(5).使用HTML5 postMessage
HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。
(6).利用flash
上述,六种方式都可以处理JavaScript的跨域请求数据问题,详细参见:Rain Man的《JavaScript跨域总结与解决办法》。
除了上面六种方式,大家平时估计都在用脚本框架开发,在JQuery框架和ExtJs框架中处理JS跨域问题,常用JSONP来处理。

3.什么是JSONP?
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script Tags返回至客户端,通过Javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
由于同源策略的限制,XMLHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。

4..JSONP如何产生的?
(1).跨域访问无权限。
众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,不管是静态页面、动态网页、web服务、WCF,只要是跨域请求,都无权限;
(2)."src"属性标签有跨域能力。
发现在Web页面上调用js文件时则不受是否跨域的影响(不仅如此,拥有"src"属性的标签都拥有跨域能力,比如<script>、<img>、<iframe>);
(3).将数据装进JS格式数据。
如果想通过纯Web端(ActiveX控件、服务端代理、HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,就是在远程服务器上设法把数据装进js格式的数据里,供客户端调用和进一步处理;
(4).JSON格式承载数据适合。
有一种JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被JS原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
(5).动态生成JSON格式数据。
Web客户端可以通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件,显而易见,服务器之所以要动态生成JSON文件,目的在于把客户端需要的数据装入进去。
(6).JSON数据成功回调到客户端。
客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但实质上是不一样。
(7).形成一种非正式传输协议JSONP。
为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回的数据。

5.JSONP的工作原理
JSONP的原理:创建一个回调函数,动态创建Script标签,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。将JSON数据填充进回调函数,进行相关的逻辑处理,或许这就是JSONP的JSON+Padding的含义。
(1).跨域简单原理
新建一个asp.net的web程序,添加sample.html网页和一个test.js文件,代码如下:
sample.html的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>test</title>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
</body>
</html>

test.js的代码:

 alert("success");

打开sample.html后会跳出"success”这样的这样的信息框,这似乎并不能说明什么, 跨域问题到底怎么解决呢?
现在模拟非同源的环境,把上面的Web程序叫做A程序,再新建一个Web程序叫做B程序,将A程序的test.js文件移除然后拷贝到B程序中。将两个程序都运行起来,Visual Studio会启动内置服务器,假设A程序是localhost:20001,B程序是localhost:20002,这就模拟了一个非同源的环境了(虽然域名相同但端口号不同,所以是非同源的)。

现在改下A程序sample.html里的代码,因为test.js文件在B程序上了,url也就变成了localhost:20002。

sample.html部分代码:

<script type="text/javascript" src="http://localhost:20002/test.js"></script>

请保持AB两个Web程序的运行状态,当你再次刷新A程序localhost:20001/sample.html的时候,和原来一样跳出了"success"的对话框,这样就成功访问到了非同源的B程序localhost:20002/test.js这个所谓的远程服务了。到这里,大家应该已经大概明白如何跨域访问的原理了。
<script>标签的src属性并不被同源策略所约束,所以可以获取任何服务器上脚本并执行。

(2).跨域实现CallBack
继续修改代码,实现JSONP的JavaScript callback形式。
修改程序A中sample的代码:

<script type="text/javascript">
//回调函数
function callback(data) {
alert(data.message);
}
</script>
<script type="text/javascript" src="http://localhost:20002/test.js"></script>

程序B中test.js的代码:

//调用callback函数,并以json数据形式作为阐述传递,完成回调
callback({message:"success"});

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
(3).跨域实现动态JS脚本
怎么让远程js知道它应该调用的本地函数叫什么名字?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同。只要服务端提供的js脚本是动态生成的就可以,这样调用者可以传一个参数过去告诉服务端“我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来动态生成js脚本并响应了。
程序A中sample的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
   script.setAttribute("type","text/javascript");
   script.setAttribute('src', url);
    // 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>

这样不直接把远程js文件写死,而是编码实现动态查询,而这也正是jsonp客户端实现的核心部分,其重点也就在于如何完成jsonp调用的全过程。
看到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,本地回调函数叫做flightHandler,所以请把查询结果传入这个函数*本地调用。
程序B中test.js的代码:

flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});

我们看到,传递给flightHandler函数的是一个json,它描述了航班的基本信息。运行一下页面,成功弹出提示窗口,jsonp的执行全过程顺利完成!

6.JQuery和ExtJs实现JSONP
(1).JQuery的JSONP跨域实现
<1>.$.getJSON
jQuery框架支持JSONP,可以使用$.getJSON(url,[data],[callback])方法(详细可以参考http://api.jquery.com/jQuery.getJSON/)。继续修改程序A的代码,改用jQuery的getJSON方法来实现(下面的例子没用用到向服务传参,所以只写了getJSON(url,[callback])):

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$.getJSON("http://localhost:20002/MyService.ashx?callback=?",function(data){
alert(data.name + " is a a" + data.sex);
});
</script>

要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个问号是内部自动生成的一个回调函数名。这个函数名可以debug看一下,比如jQuery17207481773362960666_1332575486681。

<2>.$.ajax
假如说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?可以使用$.ajax方法来实现(参数较多,详细可以参见http://api.jquery.com/jQuery.ajax)。

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$.ajax({
url:"http://localhost:20002/MyService.ashx?callback=?",
dataType:"jsonp",
jsonpCallback:"person",
success:function(data){
alert(data.name + " is a a" + data.sex);
}
});
</script>

jsonpCallback就是指定我们自己的回调方法名person,远程服务接受callback参数的值就不再是自动生成的回调名,而是person。dataType是指定按照JSOPN方式访问远程服务。

(2).ExtJs的JSONP跨域实现
<1>.Ext.data.JsonP.request
ExtJS4.1的Ext.data.JsonP.request实现跨域访问:

//跨域请求,MsgUrl为其他站点地址
Ext.data.JsonP.request({
url: MsgUrl + '/Home/InitializeComet',
timeout: 300000,
params: { loginId: LoginId },
callbackKey: "jsonPCallback",
success: function(result) {
if (result.rettype == 'true') {
me.Comet.privateToken = result.msg;
me.RegisterComet();
} else {
alert(result.msg);
}
},
failure: function(result) {
alert(result);
}
});

其中跨域请求的要点是类名:Ext.data.JsonP和callbackKey的参数。
“jsonPCallback”该名称将作为Jsonp请求的方法名传递到服务器端,获取该请求的URL:
http://10.0.13.64:89/Home/InitializeComet?loginId=0001&jsonPCallback=Ext.data.JsonP.callback1&_dc=1370687739484

<2>.Ext.data.ScriptTagProxy

var ss = new Ext.data.ScriptTagProxy({
  //url: 'http://10.128.3.104/edi/rest/GetBillCaseInfo',
url: 'testjson.do',
callbackParam: "_callback",
headers: { 'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=' }
});
ss.load({ '_out': 'json' },
  new Ext.data.JsonReader(
{ root: "ROWSET.ROW" },
[{ name: 'CaseCode', mapping: 'CaseCode' },{ name: 'CaseName', mapping: 'CaseName'}]),
function (recordsBlock, arg, isok) {
alert(Ext.encode(recordsBlock));
alert(Ext.encode(recordsBlock.records[0].data));
}
);
Ext.Ajax.request({
url: 'http://10.128.3.104/edi/rest/GetBillCaseInfo',
//url: 'testjson.do',
scriptTag: true,
success: function (req) {
alert(req.responseText);
},
failure: function (req) {
alert(req.responseText);
},
headers: { 'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=' },
params: { _out: 'json' }
});

7.AJAX与JSONP的异同
(1).Ajax和Jsonp是两种技术。
Ajax和Jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个URL,然后把服务器返回的数据进行处理,因此JQuery和EXT等框架都把Jsonp作为Ajax的一种形式进行了封装;
(2).Ajax和Jsonp实现原理不同。
Ajax和Jsonp在本质实现上有差别。Ajax的核心是通过XmlHttpRequest获取非本页内容,而Jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。所以说,其实Ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,Jsonp本身也不排斥同域的数据的获取;
(3).Ajax和Jsonp都是非强制性协议。
Jsonp是一种方式或者说非强制性协议,如同Ajax一样,它也不一定非要用Json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用Jsonp提供公开服务。
总而言之,Jsonp不是Ajax的一个特例,哪怕Jquery、Ext等巨头把Jsonp封装进了Ajax,也不能改变这一点!

参考博客:
Ajax与JSON的一些总结
JavaScript跨域总结与解决办法
深入浅出JSONP--解决ajax跨域问题
说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
Jquery跨域请求
ExtJs学习笔记(23)-ScriptTagProxy+XTemplate+WCF跨域取数据
ExtJs与WCF之间的跨域访问
jQuery与Extjs的Ajax的跨域访问

JS、JQuery和ExtJs的跨域处理的更多相关文章

  1. 利用jquery的ajax实现跨域,内部其实是jsonp协议了,不是XHRhttp协议

    一.同源策略 要理解跨域,先要了解一下“同源策略”.所谓同源是指,域名,协议,端口相同.所谓“同源策略“,简单的说就是基于安全考虑,当前域不能访问其他域的东西. 一些常见的是否同源示例可参照下表: 在 ...

  2. js中ajax如何解决跨域请求

    js中ajax如何解决跨域请求,在讲这个问题之前先解释几个名词 1.跨域请求 所有的浏览器都是同源策略,这个策略能保证页面脚本资源和cookie安全 ,浏览器隔离了来自不同源的请求,防上跨域不安全的操 ...

  3. jQuery之ajax的跨域获取数据

    如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型.使用这种类型的话,会创建一个查询字符串参数 callback=? ,这个参数会加在请求的URL后面.服务 ...

  4. jQuery的Ajax的跨域请求

    今天碰到一个Ajax跨域请求的问题,我把源码down下来,然后在服务器端写了一个http请求的代理(因为服务器端是不存在跨域问题的),说白了就是用BufferedReader写了个IO流,然后读取到目 ...

  5. &lpar;转&rpar;jquery ajax使用及跨域访问解决办法

    原文地址:***/UIweb/jquery_ajax_kuayujiejue.html 最近开发中,设计到智能手机项目,给领导做几个demo.主要是用jquery和jqeury mobile. 越来越 ...

  6. jQuery的ajax jsonp跨域请求

    了解:ajax.json.jsonp.“跨域”的关系 要弄清楚以上ajax.json.jsonp概念的关系,我觉得弄清楚ajax是“干什么的”,“怎么实现的”,“有什么问题”,“如果解决存在的问题”等 ...

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

    一.处理跨域的方式: 1.代理 2.XHR2 HTML5中提供的XMLHTTPREQUEST Level2(及XHR2)已经实现了跨域访问.但ie10以下不支持 只需要在服务端填上响应头: ? 1 2 ...

  8. jQuery ajax的jsonp跨域请求

    一直在听“跨域跨域”,但是什么是跨域呢?今天做了一些了解.(利用jQuery的jsonp) jQuery使用JSONP跨域 JSONP跨域是利用script脚本允许引用不同域下的js实现的,将回调方法 ...

  9. JQuery - Ajax和Tomcat跨域请求问题解决方法!

    在JQuery里面使用Ajax和Tomcat服务器之间进行数据交互,遇到了跨域请求问题,无法成功得到想要的数据! 错误信息部分截图: 通过错误信息判断知道已经发生在Ajax跨域请求问题了! 当前Tom ...

随机推荐

  1. Java帮助文档的生成

    首先需要对代码加上文档的注释,比如下面这样: package wz.learning;        /**   * Title:Person<br>   * Description:  ...

  2. tuple只有一个元素的时候,必须要加逗号

    In [1]: a = (1) In [2]: a Out[2]: 1 In [3]: a = (1,) In [4]: a Out[4]: (1,) 这是因为括号()既可以表示tuple,又可以表示 ...

  3. SPOJ1811最长公共子串问题&lpar;后缀自动机&rpar;

    题目:http://www.spoj.com/problems/LCS/ 题意:给两个串A和B,求这两个串的最长公共子串. 分析:其实本题用后缀数组的DC3已经能很好的解决,这里我们来说说利用后缀自动 ...

  4. ZOJ 3529 A Game Between Alice and Bob(博弈论-sg函数)

    ZOJ 3529 - A Game Between Alice and Bob Time Limit:5000MS     Memory Limit:262144KB     64bit IO For ...

  5. 一些Android框架

    从网上收集一些框架,敲代码偷懒这些框架非常实用,必须记下来,为了以后少写代码,用别人好的框架 ThinkAndroid ThinkAndroid(一个ThinkAndroid教程地址:http://m ...

  6. CreateCompatibleBitmap 需要注意的问题

    不要使用CreateCompatibleDC得到的内存DC作为其参数,应使用真实DC,否则图片不能显示

  7. ABP官方文档翻译 2&period;2 ABP会话

    ABP会话 介绍 关于IAbpSession 注入会话 会话属性 覆盖当前会话值 警告! 用户标示 介绍 如果应用需要登录的话,同样也需要知道当前用户可以执行哪些操作.ABP在展现层提供了会话对象,同 ...

  8. 用count sql做jmeter的while条件

    ${__groovy(vars.get("pboc_req_record_counter_1") == "Invalid"  || vars.get(&quot ...

  9. 二、Html5元素、属性、格式化

  10. python学习笔记06-enumerate&lpar;&rpar;

    enumerate()   python 内置函数  枚举 列举的意思 对于一个可迭代的(iterable)/可遍历的对象(如列表.字符串),enumerate将其组成一个索引序列,利用它可以同时获得 ...