AJAX 的出现使得网页可以通过在后台与服务器进行少量数据交换,实现网页的局部刷新。但是出于安全的考虑,ajax不允许跨域通信。如果尝试从不同的域请求数据,就会出现错误。如果能控制数据驻留的远程服务器并且每个请求都前往同一域,就可以避免这些安全错误。但是,如果仅停留在自己的服务器上,Web 应用程序还有什么用处呢?如果需要从多个第三方服务器收集数据时,又该怎么办?

一、关于ajax跨域的思考

  1、Ajax为什么不能跨域?到底是卡在哪个环节了?(下面项目中具体说,这里先说下结论)。 Ajax其实就是向服务器发送一个GET或POST请求,然后取得服务器响应结果,返回客户端。理论上这是没有任何问题的,然而普通ajax跨域请求,在服务器端不会有任何问题,只是服务端响应数据返回给浏览器的时候,浏览器根据响应头的Access-Control-Allow-Origin字段的值来判断是否有权限获取数据,一般情况下,服务器端如果没有在这个字段做特殊处理的话,跨域是没有权限访问的,所以响应数据被浏览器给拦截了,所以在ajax回调函数里是获取不到数据的(来自园友补充)。所以现在ajax跨域的问题可以转化为数据怎么拿回客户端的问题。

  2、既然不能直接访问第三方站点,我们可以在服务器上面做代理,通过ajax向代理发送请求,代理获得数据后在返回给客户端,当然这是一种解决办法,但是一次请求要从客户端经过代理到第三方站点,然后再原路返回,响应速度是个问题。

  3、我们发现我们可以将一些js、css等文件放在第三方的服务器上面,如CDN等来加快网页的打开速度,这样是没有任何问题的,也就是说web页面可以加载放在任意站点的js、css、图片等资源,不会受到"跨域"的影响。这个时候,我们会想到:既然我们可以调用第三方站点的js,那么如果我们将数据放到第三方站点的js中不就可以将数据带到客户端了吗?

下面我们来做一个实验,来验证一下我们的猜想成不成立:

  打开Visual Studio,新建一个Web项目,这里用WebForm,然后我们在项目中添加一个名为remoteJs的js文件,写入如下代码:

function GetRemoteData() {
return "remote data";
}

很简单,就一个方法,返回一个字符串,下面我们来写一个客户端调用,既然是跨域,那就写个html静态页面来测试吧,新建local.html,输入以下代码:

<!DOCTYPE html>
<html>
<head>
<title>本地站点</title>
<meta charset="UTF-8">
<script type="text/javascript" src="http://localhost:4071/remoteJs.js"></script>
</head>
<script type="text/javascript">
var data = GetRemoteData();
alert(data);
</script>
<body> </body>
</html>

让我们的Web项目跑起来,然后打开local.html,可以看到弹出一个窗口,显示信息remote data。这里证明我们的想法是正确的。接下来的问题是,我们如何根据需要发送请求和获取请求的结果呢?下面我们来认识一下JSONP。

二、JSONP

 1、什么是JSONP

  JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。其核心思想是利用JS标签里面的跨域特性进行跨域数据访问,在JS标签里面存在的是一个跨域的URL,实际执行的时候通过这个URL获得一段字符串,这段返回的字符串必须是一个合法的JS调用,通过EVAL这个字符串来完成对获得的数据的处理。

  JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。

2、JSONP的实现

  下面我们通过一个例子来说明一下JSONP是如何实现ajax跨域请求的。这里我们模拟图书馆图书的查询,在刚刚我们建立的web项目里面添加一个名为SearchBook的一般处理程序,写入如下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace BookLibrary
{
public class SearchBook : IHttpHandler
{ public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string callback = context.Request["callback"];
context.Response.Write(callback + "({'BookName':'English','Pages':562})");
} public bool IsReusable
{
get
{
return false;
}
}
}
}

暂时先不解释,我们写完客户端看到效果后在详细说明,然后修改刚刚的local.html,代码如下:

<!DOCTYPE html>
<html>
<head>
<title>跨域请求</title>
<meta charset="UTF-8">
</head>
<body>
<input type="button" value="发送请求" onclick="GetAjaxData();" />
</body>
<script type="text/javascript">
var GetData = function (data) {
alert(data.BookName + " " + data.Pages);
};
function GetAjaxData(){
var url = "http://localhost:4071/SearchBook.ashx?callback=GetData";
var script = document.createElement('script');
script.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(script);
} </script>
</html>
  

这个html页面有一个按钮,绑定方法GetAjaxData,当我们单击发送请求时,就会向Web站点发送请求,获取查询的数据,我们让Web站点跑起来,然后打开local.html,单击按钮,看到弹出如下信息:

我们成功的取得了web站点的数据,实现了跨域请求。下面我们来说一下他的实现原理:

var url = "http://localhost:4071/SearchBook.ashx?callback=GetData";

这一行代码我们定义了请求的url,问号前面的是web站点一般处理程序SearchBook的地址,问号后面我们传入了一个参数callback,值为GetData,也就是我们上面定义的方法名,及回调函数名称。当然我们可以传入更多的参数。

var script = document.createElement('script');
script.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(script);

这三行代码就是添加script节点,url指向第三方站点

3、普通Ajax请求在哪个环节出错了

下面,我们用JQuery的ajax来说明一下ajax请求到底是卡在哪个环节了,修改GetAjaxData方法如下:

           $.ajax({
type: "get",
async: false,
url: "http://localhost:4071/SearchBook.ashx",
dataType: "text",
success: function (data) {
alert(data.BookName + " " + data.Pages);
},
error: function () {
alert('fail');
}
});

在SearchBook里面context.Response.Write(callback + "({'BookName':'English','Pages':562})");这行下断点,然后运行,会发现可以走到断点,然后就出错了。

4、用JQuery实现ajax跨域

其实JQuery里面也封装了跨域的ajax方法,我们来看一下上面的方法用JQuery怎么写:

<script type="text/javascript">
function GetAjaxData() {
$.ajax({
type: "get",
async: false,
url: "http://localhost:4071/SearchBook.ashx",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,标识jsonp回调函数名(一般为:callback)
jsonpCallback: "GetData",//callback的function名称
success: function (data) {
alert(data.BookName + " " + data.Pages);
},
error: function () {
alert('fail');
}
});
}
</script>

下面我们来看一下,我们自己写的js执行后的DOM结构:

三、总结

   1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

  2、ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是通过HTTP来动态添加<script>标签来调用服务器提供的js脚本。

  3、其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

  4、jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

  5、jsonp整个过程中,本地站点一直处于主动的地位,主动的发送请求,主动的加载远程js.而第三方站点则处于被动的响应。

其他跨域请求相关博文

http://www.cnblogs.com/zuqing/p/5470238.html

http://www.cnblogs.com/shy1766IT/p/7077104.html

JQuery实现ajax跨域的更多相关文章

  1. JQuery的Ajax跨域请求的

    JQuery的Ajax跨域请求的(Ajax) 什么是jsonp格式呢?API原文:假设获取的数据文件存放在远程server上(域名不同.也就是跨域获取数据),则须要使用jsonp类型.使用这样的类型的 ...

  2. PHP+JQuery实现ajax跨域

    jQuery实现ajax跨域 1.dataType:'jsonp'2.type: 'get'3.把要传的参数以url方式传出去  url:'http://gameapi.feiliu.com/lqzg ...

  3. jQuery使用ajax跨域请求获取数据

    jQuery使用ajax跨域请求获取数据  跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的 ...

  4. JQuery的Ajax跨域请求原理概述及实例

    今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发 JQuer ...

  5. [转载]JQuery的Ajax跨域请求的解决方案

    今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发现JQuer ...

  6. JQuery实现Ajax跨域访问--Jsonp原理

    JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于Java ...

  7. jQuery的ajax跨域 Jsonp原理

    1.Jsonp Jsonp(json with padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题. Jsonp是为了解决ajax跨域发送http请求出现的,利用S ...

  8. JQuery的Ajax跨域请求的解决方式

            今天在项目中须要做远程数据载入并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究 ...

  9. jQuery的ajax跨域实现

    今天有人问我跨域ajax请求是否可以发送,之前没接触过此类问题,没答上,后来查了下,以下备忘. 我在本地建了三个站点,并设置了host文件模拟跨子域和跨全域 coolkissbh.com blog.c ...

随机推荐

  1. ZOJ 3332 Strange Country II (竞赛图构造哈密顿通路)

    链接:http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3332 本文链接:http://www.cnblogs.com/Ash-l ...

  2. 蒟蒻的9个背包的浩大工程(更新中)(无限延期)(太长了不舍删虽然写的lj的一匹)

    所以说这就是一篇写炸的废文!!!! 所以说背包直接看dd大神的就好了,算了瞎写写吧. 0/1背包 有n件物品和一个容量为C的背包.第i件物品的重量是w[i],价值是v[i].求解将哪些物品放入背包可使 ...

  3. 洛谷——P1154 奶牛分厩

    P1154 奶牛分厩 题目描述 农夫约翰有N(1<=N<=5000)头奶牛,每头奶牛都有一个唯一的不同于其它奶牛的编号Si,所有的奶牛都睡在一个有K个厩的谷仓中,厩的编号为0到K-1.每头 ...

  4. Linux命令之install

    install [选项] 源文件 目标文件 install [选项] 源文件 目录 install [选项] –t 目录 源文件 install [选项] –d 目录 install作用是安装或升级软 ...

  5. [Codeforces 15E] Triangle

    Brief Introduction: 求从N出发,回到N且不包含任何黑色三角的路径数 Algorithm:假设从N点到第二层中间的节点M的路径数为k,易知总路径数为(k*k+1)*2 而从第第四层开 ...

  6. [SPOJ]DIVCNT3

    别人写的讲得挺好的博客 洲阁筛,一种快速求积性函数前缀和的算法 求$\sum\limits_{i=1}^nF(i)$,其中$F(x)$是积性函数,并且$F(p^c)$是关于$p$的低阶多项式 我们把$ ...

  7. 浙南联合训练赛 B-Laptops

    One day Dima and Alex had an argument about the price and quality of laptops. Dima thinks that the m ...

  8. iOS开发——检测屏幕旋转

    步骤一.注册通知 1: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrien ...

  9. Android之Activity 生命周期

    作用:用户界面的组件,主要用于和用户进行交互.可以理解为手机屏幕的一屏. 生命周期: Resume:“继续”的意思. 由此可见, Activity有四种基本状态: 1) Running:位于屏幕最前端 ...

  10. Lucene的学习及使用实验

    实验一下Lucene是怎么使用的. 参考:http://www.importnew.com/12715.html (例子比较简单) http://www.yiibai.com/lucene/lucen ...