文章目录
  1. 1. 解决方案
  2. 2. 何为跨域
  3. 3. 其他解决方法

今天在使用ajax(http://localhost:8080)调用nodejs写的restful API(http://localhost:3000)时,报了如下一个错误:

XMLHttpRequest cannot load http://localhost:3000/mock/items. 
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8080' is therefore not allowed access.

晚上说不能跨域访问,完全不懂这个概念啊,所以简单介绍一下。

解决方案

首先给大家介绍一下这个问题的解决方案,我是在node代码中设置跨域访问。

var app = express();  
//设置跨域<strong>访问</strong>  
app.all('*', function(req, res, next) {  
    res.header("Access-Control-Allow-Origin", "*");  
    res.header("Access-Control-Allow-Headers", "X-Requested-With");  
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  
    res.header("X-Powered-By",' 3.2.1')  
    res.header("Content-Type", "application/json;charset=utf-8");  
    next();  
}); 

把Access-Control-Allow-Origin设置为‘*’,表示任意origin可以访问该API. 在实际应用中这样是不安全的,需要制定具体的origin。

当然也可以只对某些url设置跨域访问:

router.get('/', function(req, res) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.send('respond with a resource');
});

何为跨域

域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系(即Trust Relation)。信任关系是连接在域与域之间的桥梁。当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可以跨网分配文件和打印机等设备资源,使不同的域之间实现网络资源的共享与管理。

跨域请求,顾名思义,就是一个站点中的资源去访问另外一个不同域名站点上的资源。这种情况很常见,比如说通过style标签加载外部样式表文件、通过 img 标签加载外部图片、通过 script 标签加载外部脚本文件、通过 Web font 加载字体文件等等。默认情况下,脚本访问文档属性等数据采用的是同源策略(Same origin policy)。

同源策略:如果两个页面的协议、域名和端口是完全相同的(IE的同源策略不包含端口),那么它们就是同源的。同源策略是为了防止从一个地址加载的文档或脚本访问或者设置从另外一个地址加载的文档的属性。如果两个页面的主域名相同,则还可以通过设置document.domain 属性将它们认为是同源的。

出于安全性考虑,浏览器将不允许跨域页面间的JS相互操作,如:主页面和跨域IFrame之间的JS操作,也不允许XMLHttprequest请求跨域内容。

在浏览器中不能直接来跨域访问,而在服务器端没有跨域安全限制。

其他解决方法

  1. 主域名相同的跨域情形

    设置document.domain属性。如果想做到数据的交互,那么www.aa.com和book.aa.com必须由你来开发才可以。可以将book.aa.com用iframe添加到 www.aa.com的某个页面下,在www.aa.com和iframe里面都加上document.domain = “aa.com”,这样就可以统一域了,可以实现跨域访问。就和平时同一个域中镶嵌iframe一样,直接调用里面的JS就可以了。

  2. HASH传值

    当两个域不同时,如果想相互调用,那么同样需要两个域都是由你来开发才可以。用iframe可以实现数据的互相调用。解决方案就是用window.location对象的hash属性。hash属性就是http://domian/web/a.htm#dshakjdhsjka 里面的#dshakjdhsjka。利用JS改变hash值网页不会刷新,可以这样实现通过JS访问hash值来做到通信。不过除了IE之外其他大部分浏览器只要改变hash就会记录历史,你在前进和后退时就需要处理,非常麻烦。不过再做简单的处理时还是可以用的。大体的过程是页面a和页面b在不同域下,b通过iframe添加到a里,a通过JS修改iframe的hash值,b里面做一个监听(因为JS只能修改hash,数据是否改变只能由b自己来判断),检测到b的hash值被修改了,得到修改的值,经过处理返回a需要的值,再来修改a的hash值(这个地方要注意,如果a 本身是那种查询页面的话比如http://domian/web/a.aspx?id=3,在b中直接parent.window.location是无法取得数据的,同样报没有权限的错误,需要a把这个传过来,所以也比较麻烦),同样a里面也要做监听,如果hash变化的话就取得返回的数据,再做相应的处理。

  3. JS脚本植入

    通过页面动态加载<script>标签实现,该标签的SRC属性设置为跨域请求的URL地址,返回的内容为method(…)形式,其中method为页面内的JS回调函数,通过执行该函数来实现改变。

  4. JQuery实现

    function jsonpajax_1() {
    
        $.ajax({
    
            url: "http://192.168.1.105:8123/Handler.ashx?callback=?",
    
            type: "get",
    
            dataType: "jsonp",
    
            jsonp: "callback",
    
            success: function(data) {
    
                var tt = '';
    
                $.each(data, function(k, v) {
    
                    tt += k + ":" + v + "<br/>";
    
                });
    
                $("#divmessage").html(tt);
    
            }
    
        });
    
    }
    

此时,跨域的Web1中的ashx文件数据提供要改一下:

string callback = context.Request.Params["callback"];
context.Response.Write(callback+"("+strJson+")");

jsonp的最基本的原理是:动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了.

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

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

JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求,

我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。

这种跨域的通讯方式称为JSONP。

文章目录
  1. 1. 解决方案
  2. 2. 何为跨域
  3. 3. 其他解决方法