您的位置:首页 > 其它

跨域问题总结

2015-10-29 16:46 417 查看

什么叫做跨域访问jsonp的出现是因为浏览器有个同源策略js来说,它在执行时不能请求不同源的资源。什么是源呢,这里是指协议名(如http://)+主机名(api.flickr.com)+端口号(:80,http协议默认端口号是80,可省略),这三个组合在一起就是一个源,同源的话是指这3个必须和发起请求的网页的源必须一样。因为js是不能请求不同源的资源,所以如果你的脚本不在这个源(http://api.flickr.com)的网页上,是没法请求的它的图片的。但为什么jsonp可以?那是因为同源策略有个例外,如果网页上通过<scriptsrc="不同源的地址"></script>,<img>以及<link>这样的标签来引用不同源的资源是可以的。结合这个例外,一些(个)聪明的人就想到一个办法,如果请求资源时,异源服务器能返回这样的脚本,请求异源资源的问题就得到解决:fnName({theDataUWanted});因为这样,浏览器得到这个脚本后会立即执行它,而这个函数实际上就是包含了你定义的回调函数的函数,而这个fnName就是jsoncallback参数的值,也就是jQuery自动替换的名字。这个异源请求的完成,要求异源服务器也必须配合你的脚本才行,如果它不支持jsonp,那即使用jsonp也无法请求异源的资源。
如果指定为 html 类型,任何内嵌的 JavaScript 都会在 HTML 作为一个字符串返回之前执行。类似地,指定 script 类型的话,也会先执行服务器端生成 JavaScript,然后再把脚本作为一个文本数据返回。JSON 数据是一种能很方便通过 JavaScript 解析的结构化数据。如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp 类型。使用这种类型的话,会创建一个查询字符串参数 callback=?,这个参数会加在请求的 URL 后面。服务器端应当在 JSON 数据前加上回调函数名,以便完成一个有效的 JSONP 请求。如果要指定回调函数的参数名来取代默认的 callback,可以通过设置 $.ajax() 的 jsonp 参数。解决跨域的问题:方法一:通过服务器解决跨域的安全限制都是指浏览器端来说的.服务器端是不存在跨域安全限制的,所以通过本机服务器端通过类似httpclient方式完成“跨域访问”的工作,然后在浏览器端用AJAX获取本机服务器端“跨域访问”对应的url.来间接完成跨域访问也是可以的.但很显然开发量比较大,但限制也最少,很多widget开放平台server端(如sohu博客开放平台)其实就么搞的.不在本次讨论范围.方法二:$.ajax() type = get dataType=jsonp要讨论的是浏览器端的真正跨域访问,推荐的是目前jQuery $.ajax()支持get方式的跨域,这其实是采用jsonp的方式来完成的. http://www.jb51.net/article/29180.htm
var qsData = {'searchWord':$("#searchWord").attr("value"),
'currentUserId':$("#currentUserId").attr("value"),
'conditionBean.pageSize':$("#pageSize").attr("value")};
$.ajax({
async:false,
url: "http://跨域的dns/document!searchJSONResult.action",
type: "GET",
dataType: 'jsonp',
jsonp: 'jsoncallback',
data: qsData,
timeout: 5000,
beforeSend: function(){
//jsonp 方式此方法不被触发.原因可能是dataType如果指定为jsonp的话,就已经不是ajax事件了
},
success: function (json) {//客户端jquery预先定义好的callback函数,成功获取跨域服务器上的json数据后,会动态执行这个callback函数
if(json.actionErrors.length!=0){
alert(json.actionErrors);
}
genDynamicContent(qsData,type,json);
},
complete: function(XMLHttpRequest, textStatus){
$.unblockUI({ fadeOut: 10 });
},
error: function(xhr){
//jsonp 方式此方法不被触发.原因可能是dataType如果指定为jsonp的话,就已经不是ajax事件了
//请求出错处理
alert("请求出错(请检查相关度网络状况.)");
}
});
------------------------------------下面是简单写法--------------------------------------------
var qsData = {'searchWord':$("#searchWord").attr("value"),
'currentUserId':$("#currentUserId").attr("value"),
'conditionBean.pageSize':$("#pageSize").attr("value")};
$.getJSON(
"http://跨域的dns/document!searchJSONResult.action?key1="+value1+"&key2="+value2+"&jsoncallback=?",
function(json){
if(json.属性名==值){
// 执行代码
}
});
//这种方式其实是上例$.ajax({..}) api的一种高级封装,有些$.ajax api底层的参数就被封装而不可见了.
//这样,jquery就会拼装成如下的url get请求
//http://跨域的dns/document!searchJSONResult.action?
//&jsoncallback=jsonp1236827957501
//&searchWord=%E7%94%A8%E4%BE%8B¤tUserId=5351
//¤tUserId=1236828192549
//&conditionBean.pageSize=15

// 在响应端(http://跨域的dns/document!searchJSONResult.action),
// 通过 jsoncallback = request.getParameter("jsoncallback") 得到jquery端随后要回调的js function name:jsonp1236827957501
// 然后 response的内容为一个Script Tags:"jsonp1236827957501("+按请求参数生成的json数组+")";
// jquery就会通过回调方法动态加载调用这个js tag:jsonp1236827957501(json数组);
// 这样就达到了跨域数据交换的目的.

// jsonp的最基本的原理是:动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了.
// 这样其实"jQuery AJAX跨域问题"就成了个伪命题了,jquery $.ajax方法名有误导人之嫌.

// 如果设为dataType: 'jsonp', 这个$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议.

// JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求,我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。这种跨域的通讯方式称为JSONP。

// jsonCallback 函数jsonp1236827957501(....): 是浏览器客户端注册的,获取跨域服务器上的json数据后,回调的函数
服务器端示例代码,以java为例:服务器端代码,是重点,开始以为,只要客户端通过jsonp就可以直接跨域访问,其实不然,需要服务器端的支持才行。
public
void
jsonpTest()
throws
IOException{
HttpServletRequest
request = ServletActionContext.getRequest();
 
HttpServletResponse
response = ServletActionContext.getResponse();
 
//根据html指定的jsonp回调函数的参数名,获取回调函数的名称
 
//callbackName的值其实就是:success_jsonpCallback
 
String
callbackName = (String)request.getAttribute(
"jsoncallback"
);
 
//简单模拟一个json字符串,实际可使用google的gson进行转换,次数通过字符串拼接
//{"name":"张三","age":28}
 
//\是对"号进行转义
StringjsonStr = 
"{\"name\":\"张三\",\"age\":28}"
;
11
 
//最终返回的数据为:success_jsonpCallback({"name":"张三","age":28})
12
 
StringrenderStr = callbackName+
"("
+jsonStr+
")"
;
13
 
response.setContentType(
"text/plain;charset=UTF-8"
);
14
response.getWriter().write(renderStr);
户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,作为参数,传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里.(动态执行回调函数)可以说jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的) .JSONP是一种脚本注入(Script Injection)行为,所以也有一定的安全隐患.注意,jquey是不支持post方式跨域的.为什么呢?虽然采用post +动态生成iframe是可以达到post跨域的目的(有位js牛人就是这样把jquery1.2.5 打patch的),但这样做是一个比较极端的方式,不建议采用.也可以说get方式的跨域是合法的,post方式从安全角度上,被认为是不合法的, 万不得已还是不要剑走偏锋..注意:JSONP是一个非常强大的构建mashp的方法,可是不是一个解决跨域访问问题的万能药。它也有一些缺点:第一:也是最重要的:JSONP不提供错误处理。如果动态插入的代码正常运行,你可以得到返回,但是如果失败了,那么什么都不会发生。你无法获得一个404的错误,也不能取消这个请求。第二:如果使用了不信任的服务会造成很大的安全隐患。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: