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

来源:互联网 发布:压缩感知 算法 翻译 编辑:程序博客网 时间:2024/06/07 23:14

   出于安全方面的考虑,各大浏览器都使用同源策略,禁止跨域访问。所谓同源策略,简单地说,就是要求动态内容(如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/):

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <title>Insert title here</title>  
  6. <script type="text/javascript"  src="js/jquery-1.11.1.min.js"></script>  
  7. <script type="text/javascript"  src="js/jquery.easyui.min.js"></script>  
  8. <script type="text/javascript">  
  9.     $(function(){  
  10.         $.ajax({  
  11.             type : "get",  
  12.             url : "http://localhost:8080/testApp/testServlet",  
  13.             dataType : "jsonp",  
  14.             success : function(data) {//客户端jquery预先定义好的callback函数,成功获取跨域服务器上的json数据后,会动态执行这个callback函数  
  15.                 alert(JSON.stringify(data));  
  16.             },  
  17.             error : function() {//数据加载失败  
  18.                 alert("fail");  
  19.                 error.apply(this, arguments);  
  20.             }  
  21.         });  
  22.       
  23.     })  
  24. </script>  
  25. </head>  
  26. <body>  
  27.     this is the first page.....  
  28. </body>  
  29. </html>  

       上述页面发出的请求URL最后形如:

http://localhost:8080/testApp/testServlet?callback=jQuery111107367232164833695_1422853667572,回调函数设置采用JQuery的默认设置。

后端代码如下(部署在http://localhost:8080)

web.xml代码:

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <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">  
  3.   <display-name>testApp</display-name>  
  4.   <welcome-file-list>  
  5.     <welcome-file>/testServlet</welcome-file>  
  6.     <welcome-file>index.htm</welcome-file>  
  7.   </welcome-file-list>  
  8.   <servlet>  
  9.     <servlet-name>testServlet</servlet-name>  
  10.     <servlet-class>com.founder.servlet.TestServlet</servlet-class>  
  11.     </servlet>  
  12.   <servlet-mapping>  
  13.     <servlet-name>testServlet</servlet-name>  
  14.     <url-pattern>/testServlet</url-pattern>  
  15.   </servlet-mapping>  
  16. </web-app>  

       servlet代码:

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package com.founder.servlet;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServlet;  
  9. import javax.servlet.http.HttpServletRequest;  
  10. import javax.servlet.http.HttpServletResponse;  
  11. import net.sf.json.JSONObject;  
  12. /** 
  13.  * 测试servlet 
  14.  */  
  15. public class TestServlet extends HttpServlet {  
  16.   
  17.     private static final long serialVersionUID = 1L;  
  18.   
  19.     @Override  
  20.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
  21.             throws ServletException, IOException {  
  22.         this.doPost(req, resp);  
  23.     }  
  24.   
  25.     @Override  
  26.     protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
  27.             throws ServletException, IOException {  
  28.         Map<String,String> map=new HashMap<String,String>();  
  29.         map.put("name""sherry");  
  30.         JSONObject json=JSONObject.fromObject(map);  
  31.         String callback=req.getParameter("callback");//得到回调函数名  
  32.         String s=json.toString();  
  33.         resp.getWriter().write(callback+"("+s+")");//封装成 回调函数名(data)形式  
  34.   
  35.     }  
  36.   
  37. }  

 

       使用jsonp方式解决跨域问题,编码简单,而且其兼容性很好,在一些古老的浏览器中都可以运行,不需要XMLHttpRequest或者ActiveX的支持,但是它只支持get请求,所以在应用上也有一定的局限性。

0 0