您的位置:首页 > Web前端 > JQuery

跨域解决方案之一---->JQuery.Ajax JSONP解决跨域访问

2015-02-02 13:33 711 查看
     出于安全方面的考虑,各大浏览器都使用同源策略,禁止跨域访问。所谓同源策略,简单地说,就是要求动态内容(如JavaScript)只能阅读与之同源的那些HTTP应答和cookies,而不能阅读来自不同源的内容。同源的判断,应该把握住 协议、域名和端口,只有同协议、同域名、同端口才可以算的上是同源,只要这三者中有一个不同,则两个源就属于不同的源,两者之间的访问则属于跨域访问。关于同源与非同源的判断,可以参照下表(from http://blog.sina.com.cn/s/blog_62d3ddc00101al1b.html)



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

       同源策略虽然在安全性方面起到了很大的作用,但是在开发的工程中,也不可避免地会需要跨域访问资源。如目前在很多大型Web项目的开发中,为了应对大并发,常常会采取前后端分开部署,这样就涉及到跨域访问的问题。JSONP是目前应用比较广泛的一种跨域解决方案。JSONP的核心思想是利用JS标签的src属性不受跨域限制进行跨域访问的。其主要执行过程可以总结为:首先在客户端注册一个回调函数,然后把回调函数的名字传给服务器;服务器端将要返回给客户端的数据生成为json格式,同时获取到客户端传过来的回调函数的名字,将要传递的json数据以实参的方式,放到回调函数中,然后将组合成的数据返回给客户端,这样返回给客户端的数据格式则形如:回调函数名(data);客户端则会解析返回的数据,执行预先定义好的回调函数。
        JQuery.Ajax中使用JSONP很简单,只需要指定datatype为jsonp格式,至于回调函数,可以采用默认形式,JQuery会自动生成随机函数名,并以默认参数名callback=函数名附加在请求的url后,当然,也可以通过jsonp和jsonpcallback自己定义回调函数的参数名和回调函数名称,这两个参数含义如下(w3c):

---------------------------------------------------------

        jsonp
        类型:String
       在一个 jsonp 请求中重写回调函数的名字。这个值用来替代在
"callback=?" 这种 GET 或 POST 请求中 URL 参数里的 "callback" 部分,比如 {jsonp:'onJsonPLoad'} 会导致将 "onJsonPLoad=?" 传给服务器。
       jsonpCallback
       类型:String
       为 jsonp 请求指定一个回调函数名。这个值将用来取代
jQuery 自动生成的随机函数名。这主要用来让 jQuery 生成度独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。你也可以在想让浏览器缓存 GET 请求的时候,指定这个回调函数名。

---------------------------------------------------------
       在后端,只需要通过request.getParameter("callback")获取到回调函数名,并将数据封装成"回调函数名(data)"的形式返回即可,前端在收到返回结果后,若返回的数据格式正确,则调用success方法,对数据做相应处理,否则调用fail方法。

 
     下面是一个简单的示例,后端使用servlet实现,前端页面部署在http://localhost:8086/容器中,后端代码部署在http://localhost:8080/容器中,由于端口号不同,所以前端页面请求后端servlet时为跨域访问。

前端页面代码如下(部署在http://localhost:8086/):

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript"  src="js/jquery-1.11.1.min.js"></script>
<script type="text/javascript"  src="js/jquery.easyui.min.js"></script>
<script type="text/javascript">
$(function(){
$.ajax({
type : "get",
url : "http://localhost:8080/testApp/testServlet",
dataType : "jsonp",
success : function(data) {//客户端jquery预先定义好的callback函数,成功获取跨域服务器上的json数据后,会动态执行这个callback函数
alert(JSON.stringify(data));
},
error : function() {//数据加载失败
alert("fail");
error.apply(this, arguments);
}
});

})
</script>
</head>
<body>
this is the first page.....
</body>
</html>


       上述页面发出的请求URL最后形如:
http://localhost:8080/testApp/testServlet?callback=jQuery111107367232164833695_1422853667572,回调函数设置采用JQuery的默认设置。
后端代码如下(部署在http://localhost:8080):

web.xml代码:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>testApp</display-name>
<welcome-file-list>
<welcome-file>/testServlet</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>com.founder.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
</web-app>

       servlet代码:

package com.founder.servlet;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
/**
* 测试servlet
*/
public class TestServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Map<String,String> map=new HashMap<String,String>();
map.put("name", "sherry");
JSONObject json=JSONObject.fromObject(map);
String callback=req.getParameter("callback");//得到回调函数名
String s=json.toString();
resp.getWriter().write(callback+"("+s+")");//封装成 回调函数名(data)形式

}

}

 

     
 使用jsonp方式解决跨域问题,编码简单,而且其兼容性很好,在一些古老的浏览器中都可以运行,不需要XMLHttpRequest或者ActiveX的支持,但是它只支持get请求,所以在应用上也有一定的局限性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: