欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IT忍者神龟之什么叫跨域访问

程序员文章站 2022-07-10 17:38:43
...
1.什么是跨域访问
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。
首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:
URL                             说明            是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js         同一域名下            允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js  同一域名下不同文件夹    允许
http://www.a.com:8000/a.js
http://www.a.com/b.js         同一域名,不同端口     不允许
http://www.a.com/a.js
https://www.a.com/b.js        同一域名,不同协议     不允许
http://www.a.com/a.js
http://70.32.92.74/b.js       域名和域名对应ip      不允许
http://www.a.com/a.js
http://script.a.com/b.js      主域相同,子域不同     不允许
http://www.a.com/a.js
http://a.com/b.js             同一域名,不同二级域名(同上)    不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js         不同域名             不允许

跨域的解决方案:
   1.jsonp比较常用
   2.CORS(Cross-Origin Resource Sharing)
JOSNP解决方案:
就是利用<script>标签没有跨域限制来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形如:
<script src=”http://www.example.net/api?param1=1&param2=2″></script>
并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。
第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如:
callback({“name”:”hax”,”gender”:”Male”})
这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。
跨域访问:
地址:http://p.3.cn/prices/mgets?skuIds=J_2146845&type=1&callback=setPrice
回调:setPrice
数据格式:[{"id":"J_2146845","p":"139.00","m":"159.00"}]
html代码:
<button id="btn">按钮</button>
<div id="div"></div>
js代码:
var div = document.
        getElementById("div");
var oScript = null;
var btn = document.getElementById("btn").onclick = function () {
    //伪造一个script加载过程
    oScript = document.createElement("script");
    oScript.src = "http://p.3.cn/prices/mgets?skuIds=J_2325379&type=1&callback=setPrice";
    document.body.appendChild(oScript);
};

function setPrice(str){
    div.innerHTML = str[0].p;
    console.log(str[0].m);
    document.body.removeChild(oScript);
}

cors解决方案:

这是一个W3C标准(显然比jsonp背景深厚许多),同样需要浏览器和服务器同时支持,但是整个通信过程,都是浏览器自动完成,不需要用户参与,就像平时写Ajax一样(如果使用的是jquery的话)。
下面是原生js实现CORS的代码

function createCORSRequest(method,url){
        var xhr=new XMLHttpRequest();
        if("withCredentials" in xhr){
            xhr.open(method,url,true);
        }else if(typeof XDomainRequest != "undefined"){//IE10之前的版本使用XDmainRequest支持CORS
            xhr=new XDomainRequest();
            xhr.open(method,url);
        }else{
            xhr=null;
        }
        return xhr;
    }
    var request=createCORSRequest("get","待访问的地址");
    if(request){
        request.onload=function(data){
            //do sth
        };
        request.send();
    }

适用场景:

承载的信息量大,get形式搞不定,需选用post传输。CORS支持所有类型的传输。

兼容性:

移动端全面支持(除opera mini),PC上IE8+。

CORS思想:

使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。(请求和响应都不包含cookie)

当然如果设置成下面这样,所有的跨域都可以实现了,但这样毕竟太不安全。
“Access-Control-Allow-Origin:*”;//允许任何域向我们的服务器发送请求

一般情况下,浏览器发送一个额外的Origin头部(由浏览器自动生成发送)

Origin:http://localhost:8080//本地网址

然后由服务器发送一个响应表头:Access-Control-Allow-Origin,如果服务器接收该请求,返回值(只能是通配符或单域名。)就和请求值一样。

Access-Control-Allow-Origin:http://localhost:8080

=>CORS方案的重点其实就在于服务器端的配置。

简单请求

  • 只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。
  • 不会使用自定义请求头(类似于 X-Modified 这种)。HTTP头部信息不超出以下{Accept,Accept-Language,Content-Language,Last-Event-ID,content-type(只限于上面提到的3种类型)}

对于简单请求,浏览器直接发出CORS请求。浏览器会自动在头信息(Request Headers)中,添加一个Origin 字段,来表明本次请求来自哪个域。

IT忍者神龟之什么叫跨域访问

Paste_Image.png

如果这个源不在许可范围内,会报错: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

如果Origin指定的域名在许可范围内(必须是跨域了的),Response Headers中会多出几个头信息字段。

Access-Control-Allow-Credentials:true//值为true表示允许发送cookie
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8080
Access-Control-Max-Age:1728000
withCredentials属性

因为CORS默认不发送cookie和http认证,如果要把Cookie发到服务器,就要指定Access-Control-Allow-Credentials:true;
另外AJAX中也要打开withCredentials属性。

var xhr=new XMLHttpRequest();
xhr.withCredentials=true;

jquery ajax请求参数中加入

xhrFields: {
  withCredentials: true
}

非简单请求

除了上面说的简单请求外都是非简单请求,比如:请求方法是PUT
或DELETE,或者Content-Type字段的类型是application/json,又或者有自定义请求头Access-Control-Request-Headers: X-Custom-Header。

比如,我添加自定义请求头

xhr.setRequestHeader('Some-Custom-Response-Header', 'value');

就会发现连续向同一地址请求了两次,而第一次请求什么值也没拿到

IT忍者神龟之什么叫跨域访问

Paste_Image.png

第二次请求

IT忍者神龟之什么叫跨域访问

Paste_Image.png

这是因为浏览器发现,这是一个非简单请求,就自动发出一个”预检”请求,要求服务器确认可以这样请求。”预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。”预检”请求之后,浏览器球会进行正常CORS请求。

服务器端配置(rails为例)

1、可以参考这个方法:为 RESTful API 配置 CORS 实现跨域请求,写的挺详细的。然而对于rails并不算熟悉的我来说,有gem包,怎么可能放着不用呢~
2、这是Rack CORS 中间件的项目地址,按照文档的说明1分钟就可以基本搞

相关标签: 跨域