同源策略:

是由NetScape提出的著名的安全策略,所有支持javaScript的浏览器都使用这个策略。同源策略限制了一个源中加载文本或脚本与来自其它源中资源的交互方式。

IE特例:

  • 授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),不遵守同源策略的限制。

  • 端口:IE未将端口号加入到同源策略的组成部分之中,因此 http://company.com:81/index.htmlhttp://company.com/index.html 属于同源并且不受任何限制。

以上参考自MDN

所谓同源是指:域名、协议、端口都相同。同源策略是浏览器最核心也最基本的安全功能
这是知乎上关于同源策略的一篇文章。。但是浏览器在安全性和实用性上做出了让步,img/script/style/iframe等有src属性的都可以跨域引用资源。

方案一——通过JSONP跨域

jsonp是JSON with padding的简写,看起来与json差不多,但是包含在函数调用中的json,利用动态script元素来使用(具有src属性的如img,iframe,srcipt都不受同源策略的影响)。该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

如果使用jquery,可以在type为get的时候dataType设为jsonp,就可以了。

$.ajax({
url: 'http://www.qdaily.com/get_user_and_radar.json?winWidth=1280&winHeight=800',
type: 'get',
dataType: 'jsonp',
data: {},
})
.done(function(data) {
console.log(data.status);
})

然后,很幸运的就可以看到这个:

 
Paste_Image.png

但是可以看出其实是请求到数据的,只是没有执行我们的callBack函数。

 
Paste_Image.png

因为前面有提到:服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,也就是服务端的返回需要拼接成这样(比如函数名叫做haddleData):

haddleData({"status":true,subscribes:["12","23"]})

另外:jquery的ajax方法可以传入两个参数

jsonp : "callback"//设置这个会替换浏览器发送请求时地址后面自动添加的?callback=xxx中的callback这个字,一般情况下不用传这个参数
jsonpCallback: "success_jsonpCallback"//这个值将用来取代jQuery自动生成的随机函数名,也就是上句话中的'xxx'。

【这儿遗留了一个问题,还请各位解决】如果jsonpCallback不手动设置的话,jquery是会自动生成个随机的字符串的,但是服务器那边的函数名要写什么,回调函数才会正确的执行呢?

看一个运行成功的实例:

$.ajax({
url: 'http://localhost:8000/remote/remote.js',
type: 'get',
dataType: 'jsonp',
jsonp: 'back',
jsonpCallback: "haddleData",
data: {},
})
.done(function(data) {
console.log(data.status);
})
//这段程序运行在8080端口的

remote.js作为远端其中写了句

haddleData({"status":true,subscribes:["12","23"]})
 
Paste_Image.png

对于大部分js初学者,大多使用jquery,而对原生不太熟悉。但是须知,ajax和jsonp其实本质上是不同的东西,ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本,利用脚本下载下来后立即执行的事实实现callback方法的调用。

原生js的jsonp简单实现:

<script>
function haddleData(data){
console.log(data.status);
}
</script>
<script type="text/javascript" src="http://localhost:8000/remote/remote.js"></script>

当然有多个本地函数需要处理的时候,加上回调函数名才是方便的,像这样:

<script type="text/javascript" src="http://localhost:8000/remote/remote.js?callback=haddleData"></script>

加上callback参数,可以使得服务器端根据前端指定的方法名cb动态返回cb(data);而不是都写死handleData(data);

【总结下jsonp】:

  • 优点:
    简单,函数回调在本地处理;
  • 缺点:
    1、安全性(存在注入漏洞,如CSRF,XSS);
    2、如果出现错误,不会像http请求那样有状态码;
    3、只能使用get请求;

方案二——CORS(Cross-Origin Resource Sharing)

这是一个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 字段,来表明本次请求来自哪个域。

 
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');

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

 
Paste_Image.png

第二次请求

 
Paste_Image.png

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

服务器端配置(rails为例)

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

【问题:】

当我请求方式为put时,却出现了404错误,是因为没有为options提供路由么?

rails中使用CORS中的功能和细节还有很多,等到需要时再行挖掘吧,欢迎使用过的各位一起交流问题。

作者:RichardBillion
链接:https://www.jianshu.com/p/7257e7c60ef5
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

cors跨域问题的更多相关文章

  1. 如何在ASP.NET Core中实现CORS跨域

    注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...

  2. ajax——CORS跨域调用REST API 的常见问题以及前后端的设置

    RESTful架构是目前比较流行的一种互联网软件架构,在此架构之下的浏览器前端和手机端能共用后端接口. 但是涉及到js跨域调用接口总是很头疼,下边就跟着chrome的报错信息一起来解决一下. 假设:前 ...

  3. Web APi之手动实现JSONP或安装配置Cors跨域(七)

    前言 照理来说本节也应该讲Web API原理,目前已经探讨完了比较底层的Web API消息处理管道以及Web Host寄宿管道,接下来应该要触及控制器.Action方法,以及过滤器.模型绑定等等,想想 ...

  4. Web API 实现JSONP或者安装配置Cors跨域

    前言 照理来说本节也应该讲Web API原理,目前已经探讨完了比较底层的Web API消息处理管道以及Web Host寄宿管道,接下来应该要触及控制器.Action方法,以及过滤器.模型绑定等等,想想 ...

  5. CORS 跨域 实现思路及相关解决方案

    本篇包括以下内容: CORS 定义 CORS 对比 JSONP CORS,BROWSER支持情况 主要用途 Ajax请求跨域资源的异常 CORS 实现思路 安全说明 CORS 几种解决方案 自定义CO ...

  6. 解决ajax请求cors跨域问题

    ”已阻止跨源请求:同源策略禁止读取位于 ***** 的远程资源.(原因:CORS 头缺少 'Access-Control-Allow-Origin').“ ”已阻止跨源请求:同源策略禁止读取位于 ** ...

  7. Asp.Net WebApi 启用CORS跨域访问指定多个域名

    1.后台action指定 EnableCors指定可访问的域名多个,使用逗号隔开 //支持客户端凭据提交,指定多个域名,使用逗号隔开 [EnableCors("http://localhos ...

  8. Cors 跨域Access-Control-Allow-Origin

    1.Access-Control-Allow-Origin 指定格式 The Origin header field has the following syntax: origin = " ...

  9. Asp.Net WebApi+Microsoft.AspNet.WebApi.Core 启用CORS跨域访问

    WebApi中启用CORS跨域访问 1.安装 Nugget包Microsoft.AspNet.WebApi.Cors This package contains the components to e ...

  10. jsonp与cors跨域的一些理解

    浏览器的同源策略,即是浏览器之间要隔离不同域的内容,禁止互相操作. 比如,当你打开了多个网站,如果允许多个网站之间互相操作,那么其中一个木马网站就可以通过这种互相操作进行一系列的非法行为,获取你在各个 ...

随机推荐

  1. C++进阶--结构体和类

    // 单纯从语言上来说,两者唯一的区别是,默认成员是公有还是私有 // 从使用习惯上 // 小的消极对象,包含公有数据,没有或仅有很少的基本的成员函数 -- 数据容器 struct Person_t ...

  2. PyQt训练BP模型时,显示waiting动图(多线程)

    1.实现效果 2.相关代码 实现BP训练模型的线程类 class WorkThread(QtCore.QThread): finish_trigger = QtCore.pyqtSignal() # ...

  3. python学习疑问

    1.(已解决) test = [1, 2, 3, 4] ", id(test)) def func(a): ", id(a)) a = a.remove(1) ", id ...

  4. Qt 常用类 (4)—— QPoint

    转载:落叶知秋时 QPoint 类代表一个坐标点,实现在 QtCore 共享库中.它可以认为是一个整型的横坐标和一个整型的纵坐标的组合. 构造 QPoint 类支持以下两种构造方式: QPoint() ...

  5. 一篇对OAuth2.0开发实例的介绍

    今天看到了博友对SSO的文章,SSO单点登录的讲解突然想写一篇关于OAuth2.0用户授权的介绍. 应用场景:在APP或者网页接入一些第三方应用时,时长会需要用户登录另一个合作平台,比如QQ,微博,微 ...

  6. 阿里云安装kubernetes-UI报错endpoints \"kubernetes-dashboard\" not found解决方法

    问题:阿里云ECS安装kube-ui v5后,访问 http://master_ip:8080/ui/跳转到http://master_ip:8080/api/v1/proxy/namespaces/ ...

  7. RPM包安装软件 -- 详细解读

    一.RPM包命名规则 1.RPM包在哪 RPM包在光盘中 2.RPM包命名原则 httpd-2.2.15-15.e16.centos.1.i686.rpm httpd 软件包名 2.2.15 软件版本 ...

  8. 1118 Birds in Forest (25 分)

    1118 Birds in Forest (25 分) Some scientists took pictures of thousands of birds in a forest. Assume ...

  9. servlet简单的小例子

    去我云盘下载: https://pan.baidu.com/s/1E2yoZ2Nmk2FE2XjuPOCvjA 访问方式:http://localhost:8080/testServlet/index ...

  10. 2018年最新PHP面试题

    面试之前多看看公司的资料,可以看出面试的公司主要做什么,电商,数据库,php函数,sql的优化,接口,session和cookie等经常会问到,都是必问之题,这其中有一部分题目摘抄自网络,回答也不错 ...