本文目录一览:
【http】什么是cors跨域
前端开发中,常常需要进行跨域请求。既然提到跨域,首先我们的知道什么是“同源策略”。
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。
如果协议,端口(如果指定了一个)和域名对于两个页面是相同的,则两个页面具有相同的源。
同一个源内,资源的访问是很自由的。就跟在自己家中,想开冰箱开冰箱,想干啥干啥。如果你想访问不同源的资源,可就没那么自由了,这就是跨域。
关于跨域,常用的JSONP应该都知道。JSONP的原理是什么呢?我们来看看大神贺师俊的解释:
很简单,就是利用script标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个script元素,地址指向第三方的API网址,并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。 第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。
可以知道JSONP就是个bug般的存在啊,如果你是一个有洁癖的程序员回想说:这不合理,这部干净。因此我们引出cors。
那么,什么是cors呢?
我们来看看互动百科的解释:
CORS(跨来源资源共享)是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是JSONP模式的现代版。
维基百科的解释(手动谷歌):
Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another domain outside the domain from which the first resource was served.
这样看来,其实嘛,cors就是一个规范,机制,基于这个规范,不同源之间才可以请求资源。相当于一个江湖规矩,大家都按规矩来嘛不是?不讲规矩?信不信小拳拳捶你。
所以呢,要想使用cors跨域访问,你就得讲规矩。下面我们来看看有哪些规矩。
跨域资源共享标准( cross-origin sharing standard )允许在下列场景中使用跨域 HTTP 请求:
cors中有个术语叫 “简单请求” ,若请求满足所有下述条件,则该请求可视为“简单请求”:
使用下列方法之一:
之所以区分简单请求,是因为cors需要处理一些“非简单请求”,这种特殊处理叫做“预检请求”。大人物来了,总要提前准备准备吧,封路啥的blabla。
预检请求的作用是 提前获知服务器是否允许该实际请求 。“预检请求”的使用,可以 避免跨域请求对服务器的用户数据产生未预期的影响 。
一张图可以清晰看到提前发送预检请求的cors请求
Request Headers:
Response Header:
cors在koa中的使用:
相关链接:
web前端跨域的一些解决方案
没有归纳之前对跨域的一些说法是模糊的,什么jsonp啊,跨域原理啊,心里只有一个大概的说法,知道这个东西,然后用的时候直接百度Ctrl+C,后来闲下来决定整理一波这些知识点,需知其所以然。
那么,其实这是浏览器对我们的一种保护机制,把坏人挡在门外。那么,问题来了,我们怎么确定门外的人到底是好人还是坏人呢?浏览器关上了坏人的一扇门,留给了我们好人一扇窗。
JSONP跟JSON没有关系..就好像JavaScript和Java一样
浏览器对script、img(这些标签的请求方式都是 GET ,所以jsonp不支持 POST )这种标签没有限制,我们就可以这样干
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
服务器端对于CORS的支持,主要就是通过设置 Access-Control-Allow-Origin 来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。 更多有关跨域资源共享 CORS 的知识
浏览器中可以查看对应的响应头,举个例子,如下
服务端允许CORS,服务端需要针对接口设置的一系列响应头 (Response Headers)
1.简单请求
目前大多数情况都采用这种方式。简单请求只需要设置 Access-Control-Allow-Origin 即可。满足以下两个条件,就属于简单请求。
2.非简单请求
非简单请求会发出一次预检测请求,返回码是204,预检测通过才会真正发出请求,这才返回200。来看栗子:
非简单请求需要根据不同情况配置不同的响应头,一系列响应头配置项见上方
这个说法相信不陌生,我们依然使用前端域名请求,然后有一个 中介商---代理 把这个请求转发到真正的后端域名上,那也就不存在跨域问题了。
比较普遍的Nginx,简单的配置一下就可以了。了解更多的配置信息: nginx详解
然后前端这边的请求地址是 ,然后Nginx监听到地址是 localhost:9099/api 的请求,就帮我们转发到真正的服务端地址
CORS与JSONP的使用目的相同,但是比JSONP更强大。JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及在服务端同意jsonp方式时,可以向不支持CORS的网站请求数据。Nginx可以说是最方便的,不过需要部署Nginx才行,需要对服务器有一定的理解,不太适合刚入门的同学,当然也可以请后台同学帮忙部署。
window.postMessage(data,origin) 是 HTML5 的一个接口,专注实现不同窗口不同页面的跨域通讯。
现在是这么一个情况,由于同源策略的限制下, a.html 不能操作iframe( b.html )里面的dom,那么使用postMessage就可以解决这一情况
然后 b.html 页面通过message事件监听并接受消息:
这种方式只适合主域名相同,但子域名不同的iframe跨域。
比如主域名是 ,子域名是 ,这种情况下给两个页面设置相同的document.domain即document.domain = baidu.com 就可以访问各自的window对象了。
前端跨域整理
不要再问我跨域的问题了
Network出现两次相同请求?我来解答
Network中出现了两个相同的请求(如图),两个发起了同样的请求,花的时间却不同,一个55ms,一个花了294ms。
什么情况啊?研究了一番,我发现有一个地方是不同的,Request Method!
请求时间短的Request Method是OPTIONS,并且返回值为空。
请求时间长的Request Method是GET。
原以为ajax请求只有HTTP的Request Method只有GET与POST两种,后来发现还有HEAD、PUT、DELETE、OPTIONS……的区别。
本地环境跑公司项目的时候,每次POST之前,为啥浏览器还偷偷给我来一次没有返回的OPTIONS请求?
原来,浏览器在某些请求中,在正式通信前会增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发XMLHttpRequest请求,从而克服了AJAX只能 同源 使用的限制。
浏览器将CORS请求分为两类:简单请求(simple request)和非简单请求(not-so-simple request)。
同时满足以下条件,就是简单请求:
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。都以Access-Control- 开头:
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
在页面域名与接口域名不一致的情况下,就出现了每次请求前先发送一个options请求的问题。
OPTIONS请求头信息中,除了Origin字段,还至少会多两个特殊字段:
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
至于其他乱七八糟的字段,现在的我还用不到也不懂,将会慢慢深入了解。
服务器收到预检请求后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示 可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。
如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。
XMLHttpRequest cannot load
Origin is not allowed by Access-Control-Allow-Origin.
其他字段中 Access-Control-Max-Age 用来指定本次预检请求的有效期,单位为秒。该字段可选。
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,JSONP的优势在于支持老旧浏览器。
解决Network出现两次相同请求的问题使用简单请求就不会遇到了。
前端跨域方式有哪些
处理跨域方法一——JSONP
1.JSONP原理
利用script元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。
2.JSONP和AJAX对比
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
3.JSONP优缺点
JSONP优点是兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性。
4.JSONP的流程(以第三方API地址为例,不必考虑后台程序)
声明一个回调函数,其函数名(如fn)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。
创建一个
服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是fn,它准备好的数据是fn([{“name”:“jianshu”}])。
最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(fn),对返回的数据进行操作。
处理跨域方法二——CORS
1.CORS原理
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
2.CORS优缺点
CORS要求浏览器(IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。
优点在于功能更加强大支持各种HTTP Method,缺点是兼容性不如JSONP。
处理跨域方法三——WebSocket
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
处理跨域方法四——postMessage
如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。