转发自:http://blog.csdn.net/marksinoberg/article/details/73500628

跨域

同源策略限制

同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。

解决方式

通常来说,比较通用的有如下两种方式,一种是从服务器端下手,另一种则是从客户端的角度出发。二者各有利弊,具体要使用哪种方式还需要具体的分析。

  • 服务器设置响应头
  • 服务器代理
  • 客户端采用脚本回调机制。

方式一

Access-Control-Allow-Origin关键字只有在服务器端进行设置才
会生效。也就是说即使再客户端使用

   
   
  • 1
  • 1
xmlhttprequest.setHeaderREquest('xx','xx');

也不会有什么效果。

正常ajax请求

下面来模拟一下ajax非跨域请求的案例实现。

test1.html

    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    <!DOCTYPE html> <html lang="en"> head> Meta charset="UTF-8"> title>ajax 测试</title> head> body> input type="button" value="Test" onclick="crossDomainRequest()"> div id="content">div> script> var xhr = new XMLHttpRequest(); var url = 'http://localhost/learn/ajax/test1.PHP'; function crossDomainRequest() { document.getElementById('content').innerHTML = "<font color='red'>loading...</font>"; // 延迟执行 setTimeout(function () { if (xhr) { xhr.open('GEt',url,true); xhr.onreadystatechange = handle_response; xhr.send(null); } else { document.getElementById('content').innerText = "不能创建XMLHttpRequest对象"; } },3000); } function handle_responsevar container = document.getElementById('content'); if (xhr.readyState == 4) { if (xhr.status == 200 || xhr.status == 304) { container.innerHTML = xhr.responseText; } else { container.innerText = '不能跨域请求'; } } } script> body> html>

    同级目录下的test1.PHP内容如下:

        
        
  • 1
  • 2
  • 3
  • 4
  • 5
    • 1
    • 2
    • 3
    • 4
    • 5
    <?PHP echo "It Works."; ?>

    跨域请求

    刚才是HTML文件和php文件都在Apache的容器下,所以没有出现跨域的情形,现在把HTML文件放到桌面上,这样再次请求PHP数据的话,就营造了这样一个“跨域请求”了。

    注意看浏览器的地址栏信息
    再次进行访问,发现会出现下面的错误信息。

    针对这种情况,比较常见的一个操作就是设置Access-Control-Allow-Origin

    格式: Access-Control-Allow-Origin: domain.com/xx/yy.*

    如果知道客户端的域名或者请求的固定路径,则最好是不使用通配符的方式,来进一步保证安全性。如果不确定,那就是用*通配符好了。

    后端开发语言为PHP的时候可以再文件开始处这么设置:

        
        
  • 1
  • 2
    • 1
    • 2
    header("Access-Control-Allow-Origin: *");

    如果是ASPX页面的话,要这么设置(Java与之类似):

        
        
  • 1
  • Response.AddHeader("Access-Control-Allow-Origin",0);">"*");

    这时,再次来访问一下刚才的路径。

    服务器代理模式

    这种方式应该算是比较常用的,而且被广泛采纳的一个方式了。说代理有点太过于书面化了,其实就是传话儿的。来举个小例子:

    小明喜欢三班一个叫小红的女孩儿,但是不好意思去要人家的QQ,微信号。然后就托和自己班的女生–小兰。来帮自己去要。所以小兰就相当于一个代理。帮助小明获取原本不能直接获取的小红的联系方式。

    下面来举个例子说明这个问题。

    直接的跨域请求

    修改一下刚才的URL即可,让ajax直接去请求其他网站的数据。

    new XMLHttpRequest(); // var url = 'http://localhost/learn/ajax/test1.PHP'; 'http://api.qingyunke.com/api.PHP?key=free&appid=0&msg=%E5%93%92%E5%93%92'; html>

    结果如下:

    启用代理模式

    刚才的HTML页面,咱们还是用自己的接口:

        
        
  • 1
  • url = 'http://localhost/learn/ajax/test1.PHP';

    具体如下:

    'http://localhost/learn/ajax/test1.PHP'; // var url = 'http://api.qingyunke.com/api.PHP?key=free&appid=0&msg=%E5%93%92%E5%93%92'; html>

    然后对应的test1.PHP应该帮助我们实现数据请求这个过程,把“小红的联系方式”要到手,并返回给“小明”

        
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    <?PHP $url = 'http://api.qingyunke.com/api.PHP?key=free&appid=0&msg=hello%20world.'; $result = file_get_contents($url); echo $result; ?>

    下面看下代码执行的结果。


    jsonp方式

    JSONP(JSON with Padding)灵感其实源于在HTML页面中script标签内容的加载,对于script的src属性对应的内容,浏览器总是会对其进行加载。于是:

    克服该限制更理想方法是在 Web 页面中插入动态脚本元素,该页面源指向其他域中的服务 URL 并且在自身脚本中获取数据。脚本加载时它开始执行。该方法是可行的,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。但如果该脚本尝试从另一个域上加载文档,就不会成功。

    实现的思路就是:
    在服务器端组装出客户端预置好的json数据,通过回调的方式传回给客户端。

    原生实现

        
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    title> script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js" "text/javascript">script> "text" name="talk" "talk"> "btn"> "text/javascript"> function jsonpcallback(result) { for(var i in result) { alert(i+":"+result[i]); } } var JSONP = document.createElement("script"); JSONP.type='text/javascript'; JSONP.src='http://localhost/learn/ajax/test1.PHP?callback=jsonpcallback'; document.getElementsByTagName('head')[0].appendChild(JSONP); html>

    服务器端test1.PHP内容如下:

    $arr = [1,102);">2,102);">3,102);">4,102);">5,102);">6]; $result = json_encode($arr); "jsonpcallback(".$result.")"; ?>

    需要注意的是最后组装的返回值内容。

    来看下最终的代码执行效果。

    JQuery方式实现

    采用原生的JavaScript需要处理的事情还是蛮多的,下面为了简化操作,决定采用jQuery来代替一下。

        
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    div> function later_action(msg) { var element = $("<div><font color='green'>"+msg+"</font><br /></div>"); $("#content").append(element); } $("#btn").click(function(){ // alert($("#talk").val()); $.ajax({ url: 'http://localhost/learn/ajax/test1.PHP',method: 'post',dataType: 'jsonp',data: {"talk": $("#talk").val()},jsonp: 'callback',success: (callback){ console.log(callback.content); later_action(callback.content); },error: (err){ console.log(JSON.stringify(err)); },}); }); html>

    相应的,test1.PHP为了配合客户端聊天的需求,也稍微做了点改变。

        
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    $requestparam = isset($_GET['callback'])?'callback']:'callback'; // 青云志聊天机器人接口: http://api.qingyunke.com/api.PHP?key=free&appid=0&msg=hello // 接收来自客户端的请求内容 $talk = $_REQUEST['talk']; $result = file_get_contents("http://api.qingyunke.com/api.PHP?key=free&appid=0&msg=$talk"); // 拼接一些字符串 $requestparam . "($result)"; ?>

    最后来查看一下跨域的效果吧。


    总结

    至此,关于简单的ajax跨域问题,就算是解决的差不多了。对我个人而言,对于这三种方式有一点点自己的看法。

    • 服务器设置Access-Control-Allow-Origin的方式适合信用度高的小型应用或者个人应用。

    • 代理模式则比较适合大型应用的处理。但是需要一个统一的规范,这样管理和维护起来都会比较方便。

    • JSONP方式感觉还是比较鸡肋的(有可能是我经验还不足,没认识到这个方式的优点吧(⊙﹏⊙)b)。自己玩玩知道有这么个东西好了。维护起来实在是优点麻烦。


    参考链接:

    • Ajax跨域请求:http://justcoding.iteye.com/blog/1366102

    • 服务器端跨域设置:http://blog.sina.com.cn/s/blog_bd26b6d20102vjv6.html

    • Ajax高级笔记:http://www.cnblogs.com/slowsoul/archive/2013/05/04/3059844.html

    ajax跨域问题解决方案的更多相关文章

    1. html5录音功能实战示例

      这篇文章主要介绍了html5录音功能实战示例的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    2. 有没有办法知道购买哪个iTunes帐户? – iOS

      我的应用程序提供应用内购买非消耗类型.该应用程序具有登录功能.是否可以根据登录用户购买我的应用程序?

    3. ios – Apple应用程序内购买收据 – 在服务器端验证

      我想验证它,并确保这是独一无二的.我担心的是:如果有人会收到一张有效收据,他就可以破解我们的服务器端API,并使用相同的有效收据进行无限数量的应用内购买.我应该以某种方式解密并检查transaction_id的“原始”收据,即我发送给Apple进行验证的收据?

    4. ios – 服务器端接收验证失败时是否应该调用finishTransaction?

      我们应该调用finishTransaction吗?这导致无效的交易永远活在队列中?就像在这个问题上说的那样:iPhonein-apppurchase:receiptverificationButifyoufindoutthatareceiptisinvalid,youshouldfinishtheassociatedtransaction.Ifnot,youmayhaveextra-transactionslivingforeverinthetransactionqueue.Thatmeansthatea

    5. ios – CLGeocoder错误. GEOErrorDomain代码= -3

      有没有关于apple的地理编码请求的文档?谢谢你提前.更新这是我的整个代码请求解决方法在搜索到答案后,它在Apples文档中!

    6. 应用程序关闭时的iOS任务

      我正在构建一个应用程序,通过ajax将文件上传到服务器.问题是用户很可能有时不会有互联网连接,并且客户希望在用户重新连接时安排ajax调用.这可能是用户在离线时安排文件上传并关闭应用程序.应用程序关闭时可以进行ajax调用吗?

    7. ios – 调用异步方法的方法的单元测试

      我想我有这些代码行:我想为该代码编写一个单元测试.对于initializeHomeData和initializeAnythingElse,我可以编写单元测试,如:我的问题是,如何测试reset()?我应该在testReset()中调用它们,如:但我认为这不是适当的实施.解决方法你是对的.要测试重置,您需要调用reset,而不是内部方法.话虽这么说,重置目前的编写方式使其不可测试.您能够如此轻松地测

    8. swift - The Facade Pattern

      Facade(外观)模式为子系统中的各类提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。

    9. swift - The Proxy Pattern

      我在实际工作中vc也仿照过Foundation的delegate:button:内涵业务逻辑,底层实现;每个button是一个类,业务逻辑需要未知的参数和处理之后未知的结果反馈UI:点击button之后界面的改变,UI实现未知的参数和未知的结果反馈,也就是实现这个代理这样以来UI的定制,很灵活很容易,代码思路依然清晰如初。哪个是主体哪个是代理并不重要关键是看定义所说whichisusedwhenanobjectisrequiredtoactasaninterfacetoanotherobjectorres

    10. Project Perfect让Swift在服务器端跑起来-引言一

      你认识Swift或者是在客户端,因为它是苹果用来开发客户端的新一代语言。可以说Swift已经是一个完整的跨平台语言了。Perfect让Swift在服务器端跑起来了,它是开源的。添加完后你打开Xcode就可以看到Perfect模版了。PerfectLib你可以理解成Perfect框架,而PerfectServer是启动支持Perfect的类似IIS/Apache的容器,MysqL是需要介入MysqLConnector5.利用Perfect模版创建PerfectWeb项目,如图我创建了一个HelloWorld

    随机推荐

    1. xe-ajax-mock 前端虚拟服务

      最新版本见Github,点击查看历史版本基于XEAjax扩展的Mock虚拟服务插件;对于前后端分离的开发模式,ajax+mock使前端不再依赖后端接口开发效率更高。CDN使用script方式安装,XEAjaxMock会定义为全局变量生产环境请使用xe-ajax-mock.min.js,更小的压缩版本,可以带来更快的速度体验。

    2. vue 使用 xe-ajax

      安装完成后自动挂载在vue实例this.$ajaxCDN安装使用script方式安装,VXEAjax会定义为全局变量生产环境请使用vxe-ajax.min.js,更小的压缩版本,可以带来更快的速度体验。cdnjs获取最新版本点击浏览已发布的所有npm包源码unpkg获取最新版本点击浏览已发布的所有npm包源码AMD安装require.js安装示例ES6Module安装通过Vue.use()来全局安装示例./Home.vue

    3. AJAX POST数据中文乱码解决

      前端使用encodeURI进行编码后台java.net.URLDecoder进行解码编解码工具

    4. Koa2框架利用CORS完成跨域ajax请求

      实现跨域ajax请求的方式有很多,其中一个是利用CORS,而这个方法关键是在服务器端进行配置。本文仅对能够完成正常跨域ajax响应的,最基本的配置进行说明。这样OPTIONS请求就能够通过了。至此为止,相当于仅仅完成了预检,还没发送真正的请求呢。

    5. form提交时,ajax上传文件并更新到&lt;input&gt;中的value字段

    6. ajax的cache作用

      filePath="+escape;},error:{alert;}});解决方案:1.加cache:false2.url加随机数正常代码:网上高人解读:cache的作用就是第一次请求完毕之后,如果再次去请求,可以直接从缓存里面读取而不是再到服务器端读取。

    7. 浅谈ajax上传文件属性contentType = false

      默认值为contentType="application/x-www-form-urlencoded".在默认情况下,内容编码类型满足大多数情况。在这里,我们主要谈谈contentType=false.在使用ajax上传文件时:在其中先封装了一个formData对象,然后使用post方法将文件传给服务器。说到这,我们发现在JQueryajax()方法中我们使contentType=false,这不是冲突了吗?这就是因为当我们在form标签中设置了enctype=“multipart/form-data”,

    8. 909422229_ajaxFileUpload上传文件

      ajaxFileUpload.js很多同名的,因为做出来一个很容易。我上github搜AjaxFileUpload出来很多类似js。ajaxFileUpload是一个异步上传文件的jQuery插件传一个不知道什么版本的上来,以后不用到处找了。语法:$.ajaxFileUploadoptions参数说明:1、url上传处理程序地址。2,fileElementId需要上传的文件域的ID,即的ID。3,secureuri是否启用安全提交,默认为false。4,dataType服务器返回的数据类型。6,error

    9. AJAX-Cache:一款好用的Ajax缓存插件

      原文链接AJAX-Cache是什么Ajax是前端开发必不可少的数据获取手段,在频繁的异步请求业务中,我们往往需要利用“缓存”提升界面响应速度,减少网络资源占用。AJAX-Cache是一款jQuery缓存插件,可以为$.ajax()方法扩展缓存功能。

    10. jsf – Ajax update/render在已渲染属性的组件上不起作用

      我试图ajax更新一个有条件渲染的组件。我可以确保#{user}实际上是可用的。这是怎么引起的,我该如何解决呢?必须始终在ajax可以重新呈现之前呈现组件。Ajax正在使用JavaScriptdocument.getElementById()来查找需要更新的组件。但是如果JSF没有将组件放在第一位,那么JavaScript找不到要更新的内容。解决方案是简单地引用总是渲染的父组件。

    返回
    顶部