同源策略:

是由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. PHP在Linux下的套件LNMP

    LNMP官网:https://lnmp.org/install.html 另外不要忘了Azkaban和WhereHows

  2. gcc编译工具生成动态库和静态库之一----介绍

     1.库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. ...

  3. hadoop-n.x.y.tar.gz、hadoop-n.x.y.tar.gz.asc 、hadoop-n.x.y.tar.gz.md5 、hadoop-n.x.y.tar.gz.mds分别是什么?

    不多说,直接上干货! 我这里,以hadoop-2.6.0为例. hadoop-n.x.y.tar.gz.mds,此mds文件是为了检验在下载和移动文件过程中文件的完整性. 通过验证文件的md5值去检验 ...

  4. Foxmail Gmail Outlook

    三个邮件客户端都比较好,但是作为用户精力是非常有限地,必须优中选优. 我选outlook,非常值得拥有. 理由如下: (1)和office完美契合 (2)和生产环境完美契合 (3)免费 (4)良好地任 ...

  5. mongodb 的一些基本命令以及 导入、导出,待更新

    基本命令参考: https://blog.csdn.net/cckevincyh/article/details/78702674 导入导出参考:https://blog.csdn.net/djy37 ...

  6. Android定位服务关闭和定位(悬浮)等权限拒绝的判断

    public void checkLocationPermission() { if (!PermissionHelper.isLocServiceEnable(this)) {//检测是否开启定位服 ...

  7. linux下开启某个端口的方法:可用于SQL

  8. browserify 不打包某些文件或者把公共文件提取出来教程

    var gulp = require('gulp') var fs = require("fs") var babelify = require('babelify') var b ...

  9. How The Kernel Manages Your Memory.内核是如何管理内存的

    原文标题:How The Kernel Manages Your Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩 ...

  10. WPF Image Source 设置相对路径图片

    BitmapImage bt = new BitmapImage(new Uri("Images\\3_u10484.png", UriKind.Relative));this.I ...