常用跨域方法总结(2)——CORS

上篇文章介绍了几种常用的跨域方法:常用跨域方法总结,本片为上一篇的补充,对比较重要的Cross Origin Resource Sharing详细介绍。

CORS

出于安全原因,从脚本内发起的跨源HTTP请求会受到一定限制。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件。

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

若要利用CORS来进行跨域获取资源,还需要服务端的配合。
这里分为两种场景:简单请求和非简单请求

简单请求

什么样的请求才属于简单请求呢,让我们先来看MDN的一段定义

  • 必须使用下列方法中的一种:

    • GET
    • HEAD
    • POST
  • 请求首部字段不能超出以下几种

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (需要注意额外的限制)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • Content-Type 的值仅限于下列三者之一:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  • 请求中没有使用 ReadableStream 对象。

同时满足以上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:限制发起跨域请求的来源,*表示不限制
(请求首部字段下文详细介绍)
前端代码:

<!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

与前述简单请求不同,“非简单请求”要求必须首先使用 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已经很详细了,为了方便阅读,笔者还是整理过来了。

HTTP 请求首部字段

请注意,这些首部字段无须手动设置。 当开发者使用 XMLHttpRequest 对象发起跨域请求时,它们已经被设置就绪。
Origin首部字段表明预检请求或实际请求的源站。(注意,不管是否为跨域请求,ORIGIN 字段总是被发送。)
Access-Control-Request-Method,用于预检请求,表示实际请求的方法
Access-Control-Request-Headers,用于预检请求,表示实际请求中添加的额外的首部字段

HTTP 请求响应字段

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:指定了预检请求的结果能够被缓存多久

最后

到这里笔者对跨域算是比较熟悉了,感谢各位的阅读,如有不对的地方,欢迎大家批评指正。
还有,最好是对每个例子都有实际运行理解更深刻哦。

Reference

HTTP访问控制(CORS)

常用跨域方法总结(2)——CORS的更多相关文章

  1. 循序渐进Python3(十一) --6--  Ajax 实现跨域请求 jsonp 和 cors

    Ajax操作如何实现跨域请求?       Ajax (XMLHttpRequest)请求受到同源策略的限制.       Ajax通过XMLHttpRequest能够与远程的服务器进行信息交互,另外 ...

  2. 前端Js跨域方法汇总—剪不断,理还乱,是跨域

    1.通过jsonp跨域2.通过修改document.domain来跨子域(iframe)3.隐藏的iframe+window.name跨域4.iframe+跨文档消息传递(XDM)5.跨域资源共享 C ...

  3. 面试整理(2)跨域:jsonp与CORS

    问题:跨域有哪些方法?jsonp的原理是什么? jsonp: 先说jsonp,jsonp的主要原理是利用script标签的src可以跨域请求,据说有src属性的都可以跨域请求,但script标签返回的 ...

  4. js处理的8种跨域方法

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  5. C#进阶系列——WebApi 跨域问题解决方案:CORS

    前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题.本篇主要从实例的角度分享下CORS解决跨域问题一些细节. WebApi系列文章 C#进阶系列— ...

  6. WebApi 跨域问题解决方案:CORS

    注:本文为个人学习摘录,原文地址:http://www.cnblogs.com/landeanfen/p/5177176.html 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看W ...

  7. C#进阶系列——WebApi 跨域问题解决方案:CORS(转载)

    C#进阶系列——WebApi 跨域问题解决方案:CORS   阅读目录 一.跨域问题的由来 二.跨域问题解决原理 三.跨域问题解决细节 1.场景描述 2.场景测试 四.总结 正文 前言:上篇总结了下W ...

  8. 跨域学习笔记2--WebApi 跨域问题解决方案:CORS

    自己并不懂,在此先记录下来,留待以后学习... 正文 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题.本篇主要从实例的角度分享下CORS解决跨 ...

  9. .net webapi跨域方法整理

    方法一 在Web.Config里面加上了配置信息: <httpProtocol> <customHeaders> <add name="Access-Contr ...

随机推荐

  1. vue.js循环语句

    vue.js循环语句 循环使用 v-for 指令. v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组, site 是数组元素迭代的别名. v-for 可以 ...

  2. 后端技术杂谈4:Elasticsearch与solr入门实践

    阮一峰:全文搜索引擎 Elasticsearch 入门教程 作者:阮一峰 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://g ...

  3. Leaflet-Leafletv0.7使用leaflet-bing-layer

    digidem/leaflet-bing-layer: Bing Maps Layer for Leaflet v1.0.0:从标题就可以看出要Leaflet v1.0.0才能用.其实leaflet ...

  4. C#关于日期 月 天数 和一年有多少周及根据某年某周获取时间段的计算(转)

    /// 当前月有多少天 /// </summary> /// <param name="y"></param> /// <param na ...

  5. How to show out three rows from the same databand On A4?

    How to show out three rows from the same databand On A4? Quote Post by DoraHuang » Tue Mar 13, 2018 ...

  6. javascript获取网页宽高,屏幕宽高,屏幕分辨率等

    ​ <script> var s = ""; s += "\r\n网页可见区域宽:"+ document.body.clientWidth; s + ...

  7. 2019牛客国庆集训派对day1(A, B E F K)

    链接:https://ac.nowcoder.com/acm/contest/1099#question A:可知符合条件的图中间肯定存在一个由1构成的矩形,找到由1构成矩形的边界,判断出现的1的数量 ...

  8. k8s-启动、退出动作

    vim post.yaml apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: life ...

  9. java 重新学习 (七)

    一.mysql的InnoDB通过建立行级索确保事务完整性.,并以Oracle风格的共享锁来处理select语句.系统默认存储为InnoDB. 二. -- mysql 创建表 CREATE TABLE ...

  10. Cocos2d 之FlyBird开发---MainMenu类

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. MainMenu类主要实现的是游戏主界面的布局,它相当于一个港口,有开向各处的航道,而游戏中的MainMenu则是有跳转到各个场景的一个集 ...