上篇文章介绍了几种经常使用的跨域方法:经常使用跨域方法总结,本片为上一篇的补充,对比较重要的Cross Origin Resource Sharing
详细介绍。html
出于安全缘由,从脚本内发起的跨源HTTP请求会受到必定限制。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件。跨域资源共享标准新增了一组 HTTP 首部字段,容许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生反作用的 HTTP 请求方法(特别是 GET 之外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否容许该跨域请求。服务器确认容许以后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也能够通知客户端,是否须要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。前端
若要利用CORS来进行跨域获取资源,还须要服务端的配合。
这里分为两种场景:简单请求和非简单请求segmentfault
什么样的请求才属于简单请求呢,让咱们先来看MDN的一段定义跨域
必须使用下列方法中的一种:浏览器
请求首部字段不能超出如下几种缓存
Content-Type 的值仅限于下列三者之一:安全
同时知足以上5种条件,则能够视为简单请求。
先跑例子吧。
首先上服务端代码:服务器
var http = require('http'); http.createServer(function (req, res) { res.setHeader("Access-Control-Allow-Origin","*"); res.end(JSON.stringify({'success':true,msg:'今天,我就是要用cors来跨域'+Math.random()})); }).listen(8080)
很简单有没有,Access-Control-Allow-Origin
:限制发起跨域请求的来源,*表示不限制
(请求首部字段下文详细介绍)
前端代码:app
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var xhr = new XMLHttpRequest() xhr.open('get', 'http://localhost:8080') xhr.onreadystatechange = function () { if (xhr.readyState === 4) { console.log(JSON.parse(xhr.responseText)) } } xhr.send() </script> </body> </html>
结果确定是请求成功啦cors
简单来讲吧,不符合简单请求的都是非简单请求(怎么感受这么大白话呢- -)详见CORS
与前述简单请求不一样,“非简单请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否容许该实际请求。"预检请求“的使用,能够避免跨域请求对服务器的用户数据产生未预期的影响。
仍是先上代码
服务端:
var http = require('http'); http.createServer(function (req, res) { res.setHeader("Access-Control-Allow-Origin","*"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); res.setHeader("Access-Control-Allow-Methods","PUT,GET,POST,DELETE,OPTIONS"); res.end(JSON.stringify({'success':true,msg:'今天,我就是要用cors来跨域'+Math.random()})); }).listen(8080) console.log('正在监听8080')
Access-Control-Allow-Headers
::预检请求响应的首部字段定义了实际请求中容许携带的额外的首部字段。Access-Control-Allow-Methods
:预检请求响应的首部字段定义了实际请求所容许使用的 HTTP 方法。(笔者作实验的遇到了一个小插曲,simple method会不受此限制,详见为何 Access-Control-Allow-Methods 不起做用?)
前端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var xhr = new XMLHttpRequest() xhr.open('get', 'http://localhost:8080') xhr.setRequestHeader('Content-type','text/html') // 添加了非简单请求的Content-Type xhr.onreadystatechange = function () { if (xhr.readyState === 4) { console.log(JSON.parse(xhr.responseText)) } } xhr.send() </script> </body> </html>
结果确定也是请求成功啦。
这里有一点要注意的地方,这里仍是说一下吧
通常而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。若是要发送凭证信息,须要设置 XMLHttpRequest 的某个特殊标志位。
也就是前端请求的时候:xhr.withCredentials = true
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“ ”。若请求的首部中携带了 Cookie 信息,若是 Access-Control-Allow-Origin 的值为“”,请求将会失败。
这块内容MDN已经很详细了,为了方便阅读,笔者仍是整理过来了。
请注意,这些首部字段无须手动设置。 当开发者使用 XMLHttpRequest 对象发起跨域请求时,它们已经被设置就绪。Origin
首部字段代表预检请求或实际请求的源站。(注意,不论是否为跨域请求,ORIGIN 字段老是被发送。)Access-Control-Request-Method
,用于预检请求,表示实际请求的方法Access-Control-Request-Headers
,用于预检请求,表示实际请求中添加的额外的首部字段
Access-Control-Allow-Method
,预检请求的响应,表示容许的接下来的实际请求的方法。(笔者作实验的遇到了一个小插曲,simple method会不受此限制,详见为何 Access-Control-Allow-Methods 不起做用?)Access-Control-Allow-Origin
,指定了容许访问该资源的外域 URI。对于不须要携带身份凭证的请求,服务器能够指定该字段的值为通配符,表示容许来自全部域的请求。Access-Control-Allow-Credentials
,当浏览器(好比xhr)的credentials设置为true时是否容许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可使用credentials(若是请求credentials为true时,该响应首部字段须要设置为true)。Access-Control-Allow-Headers
,预检请求的响应,表示容许的接下来的实际请求的额外的首部字段。预检请求的响应。其指明了实际请求中容许携带的首部字段。Access-Control-Expose-Headers
,在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,若是要访问其余头,则须要服务器设置本响应头。Access-Control-Max-Age
:指定了预检请求的结果可以被缓存多久
到这里笔者对跨域算是比较熟悉了,感谢各位的阅读,若有不对的地方,欢迎你们批评指正。
还有,最好是对每一个例子都有实际运行理解更深入哦。