本文为HTML标准解读系列文章,其他文章详见这里。

你是否曾经遇到过这样的问题?

  • 使用canvasgetImageData() 方法,却报错:The canvas has been tainted by cross-origin data
  • 使用canvastoDataURL()方法,却报错:Tainted canvases may not be exported;
  • 使用document.styleSheets[0].cssRules访问样式表的css规则,却报错:Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules

如果你上网找解决方案,会发现他们都跟一个HTML属性密切关联:crossorigincrossorigin是CORS在HTML标签上的应用。 很多的元素,包括imgvideoaudiolinkscript都有这个属性:

<img src="https://example.com/test.png" crossorigin="anonymous"></img>
<video src="https://example.com/test.mp4" crossorigin="anonymous"></video>
<link href="https://example.com/test.css" rel="stylesheet" crossorigin="anonymous" />
<script src="https://example.com/test.js" crossorigin="anonymous"></script>

幸运的是,在不同的元素上,crossorigin发挥作用的机理几乎是一样的,也就是说,只要明白它在一个元素上是如何发挥作用的,其他元素上的使用也就明白了。

本文我将会基于HTML标准2.5.4 CORS settings attribute,力求给你讲清楚:

  • crossorigin属性有哪些值?分别是干什么用的?

  • crossorigin是如何解决开篇的三个问题的?

  • 如何使用js的fetch API,来模拟不同crossorigin的值所发起的请求?

一些必要的前置知识

同源策略 是浏览器执行的一种安全机制,这个策略的一个重要方面就是限制使用js脚本访问不同源的资源。而CORS(Cross-Origin Resource Sharing/跨域资源共享)就是同源策略开的一道口子,只要客户端与服务端(通过HTTP头)按照一定的规则进行协商,那么客户端就能正常使用js访问不同源的服务端资源。

我在这里不会讲他们是如何进行协商的,因为像这样的文章满天飞。我为你准备的是一段服务端代码,这段代码使用expressJS实现了服务端资源的跨域共享,以便你在阅读本文的时候可以方便的在本地进行测试:

const express = require('express')
const app = express()// 支持跨域的关键代码
app.use(function(req, res, next) {res.header("Access-Control-Allow-Origin", "*"); // 第二个参数可以换成你的域名res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");next();
});// host静态资源,如图片等等
app.use(express.static('./public'))app.get('/', function(req, res, next) {res.send('Hello World')
});// 测试跨域请求的时候记得使用其他的端口,比如http://localhost:8080
app.listen(3000)

请求的三种状态

我们都知道,使用imgvideoaudiolinkscript 等HTML元素可以请求外部的资源。

根据标准,这些元素所发出的请求可以根据是否支持CORS划分为3种状态:

No CORS

Anonymous

Use Credentials

  • 状态No CORS表示不支持CORS的请求。 在这种情况下,不管服务端对应的资源是否也支持CORS, 虽然浏览器依然会拿到资源,这个资源也会正常加载和显示,但使用js访问其资源的能力会受到限制,具体表现为:

    • 对于imgaudiovideo元素:当这些元素的资源放在canvas上使用的时候,这些资源会被标记为tainted ,于是getImageData()toDataURL()方法就会被禁用;

    • 对于script元素:使用window.onerror访问其错误信息的的能力会被限制,比如在Chrome上只是统一报一个Script error.的错误文本;

    • 对于link元素:资源无法被js访问,如样式表中的cssRule

  • 状态Anonymous表示这是一个支持CORS的请求:

    • 如果服务端对应的资源不支持CORS,就会报诸如Access to XXX from origin 'YYY' has been blocked by CORS policy的错误。

    • 如果服务端对应的资源支持CORS,那么你就能拿到这个资源完整的访问权,也就是可以通过js脚本操作这个资源。

  • 状态Use Credentials表示这是一个支持CORS的请求,并且会在请求头中附带相关的身份凭证(如Cookie信息),其他地方与状态Anonymous一样。 Anonymous在英文中是匿名的意思,而Use Credentials则表明你要像服务端表明你的身份。

注意:以上说的都是针对不同源的请求而言的。如果是同源的请求,资源不会受到同源策略的限制,默认就是有完整的访问权限。

使用crossorigin改变请求的状态

大部分情况下,No CORS 是HTML元素发起请求的默认状态。这也就是为什么在不做任何配置的情况下,在canvas使用上不同源的img会报tainted canvases的错误,访问不同源的cssRule会报错。只有一种例外情况,当linkscriptmodule一起使用的时候,默认请求状态会设置为Anonymous

而你可以通过crossorigin属性改变默认的请求状态

  • 如果crossorigin="anonymous",就会创建一个状态为Anonymous的CORS请求。
  • 如果crossorigin="use-credentials",就会创建一个状态为Use Credentials的CORS请求。
  • 其他任何属性值,包括空字符串"",都会创建一个状态为Anonymous的CORS请求。

于是,对于文章开头的几个问题,解法已经很清晰了:你必须使用crossorigin属性修改请求的状态,使其支持跨域。这样如果服务端也做了跨域支持,那么你就可以拿到资源完整的访问权。

也就是说,在服务端已经支持跨域的情况下,为了避免tainted canvases,你需要给img赋予一个crossorigin属性,如:

<img src="https://example.com/test.png" crossorigin="anonymous"></img>

为了访问cssRule,你需要给link赋予一个crossorigin属性,如:

<link href="https://example.com/test.css" rel="stylesheet" crossorigin="anonymous" />

值得一提的是,虽然objectembediframe等元素虽然也可以发起资源请求,但是他们都不支持crossorigin属性,所以他们的请求状态都是No CORS

使用fetch api模拟三种请求状态

fetch(resource,options)options参数有两个属性可以用来模拟不同状态:

  • mode属性,可以用来设置是否支持CORS,具体的值在这里列出了。
  • credentials属性,可以控制是否发送身份认证信息,具体的值在这里列出了。

于是,你可以在JS中使用fetch模拟HTML元素请求三种状态:

// No CORS request
fetch('https://example.com/test', {mode: 'no-cors'})
// Anonymous request
fetch('https://example.com/test', {mode: 'cors'})
// Use Credentials request
fetch('https://example.com/test', {mode: 'cors', credentials: 'include'})

与HTML元素不同的是,一般情况下mode的默认值是cors,也就是说一般情况下fetch请求默认支持CORS。

当你发送的是一个状态为No CORS 的跨域请求,你会发现返回的response里的body为null,也就是说,虽然请求成功,但你仍然无法访问返回的资源。

当你发送的是一个状态为Anonymous 的跨域请求,你可以从开发者工具看到你的请求头并没有Cookies 这一项。

当你发送的是一个状态为Use Credentials的跨域请求,你可以从开发者工具看到你的请求头附上了Cookies

总结

我在HTML常见微语句提到过,有一种HTML属性叫「可枚举属性」。这种属性有有限的状态,并且定义了一个关键词/状态映射的集合,一个关键词对应一个状态。两个特殊的状态是missing value default 以及 invalid value default,分别表示属性没有出现时使用的状态以及属性值非法(不匹配任一关键词)时的使用的状态。与「可枚举属性」相反的是像class这种属性,有无限的状态。

crossorigin就是一种可枚举属性。下面我用一张表为你总结了这个属性:

状态 特殊状态归属 关键词 服务端支持跨域 服务端不支持跨域
No CORS missing value default js访问其资源的能力受限制 js访问其资源的能力受限制
Anonymous invalid value default anonymous 获得完整的访问权限 报跨域错误:无法获得资源
Use Credentials use-credentials 获得完整的访问权限 报跨域错误:无法获得资源

crossorigin属性:为什么它是避免tainted canvases的关键?相关推荐

  1. he canvas has been tainted by cross-origin data and tainted canvases may not be exported

    来自: https://ourcodeworld.com/articles/read/182/the-canvas-has-been-tainted-by-cross-origin-data-and- ...

  2. 使用canvas的toDataURL方法将图片转为base64报错:Tainted canvases may not be exported

    toDataURL()报错 在使用Canvas对图片进行裁切功能时,用到了toDataURL方法. 在调试过程中,发现执行到该方法是会报以下错误: Uncaught DOMException: Fai ...

  3. Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported [已解决]...

    原文链接: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported [已解 ...

  4. canvas跨域:Tainted canvases may not be exported.

    Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may no ...

  5. 头像裁剪和Uncaught DOMException: Failed to execute ‘toDataURL‘ on ‘HTMLCanvasElement‘: Tainted canvases m

    此文是半原创. 头像裁剪的主要实现是同事找来发我的,用着还不错. 记一下,可以用作以后研究. 此文主要记录一个要点: 当用户上传已上传头像,裁剪头像弹窗获取到图片,当调用canvas的toDataUR ...

  6. Tainted canvases may not be exported

    Tainted canvases may not be exported. 场景 解决方法 总结 场景 在使用html canvas进行绘画,之后想通过canvas的Api toDataURL toB ...

  7. Fabric.js Failed to execute ‘toDataURL‘ on ‘HTMLCanvasElement‘: Tainted canvases may not be exported

    Fabric.js Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported ...

  8. html里面的crossorigin属性,HTML5 标签里的 crossorigin 属性到底有什么用? | Chrisyue's Blog...

    最近 Bootstrap 4 已经正式发布了,可能已经有爱尝鲜的小伙伴在 alpha 阶段就尝试过 BS4.不过今天要说的不是 BS4,而是官网里引入 BS4 框架依赖的 jQuery 的代码: cr ...

  9. html完整性检测,html - 什么是完整性和crossorigin属性?

    integrity - 定义必须匹配的资源的哈希值(如校验和),以使浏览器执行它. 哈希确保文件未经修改并包含预期数据. 这样浏览器就不会加载不同的(例如恶意的)资源. 想象一下你的JavaScrip ...

最新文章

  1. 深度学习(5)感知机(神经元)与神经网络
  2. code blocks 快捷键
  3. C/C++版数据结构之链表三
  4. 昨天电脑问题 补昨日8-3复习内容 异常与文件操作
  5. 动态规划走楼梯_负重爬楼梯、过草地,服贸会六足机械人展示“送水到家”
  6. 翻转二叉树—leetcode226
  7. 主/辅DNS服务器详细配置
  8. [html] html如何启动本地的exe应用?
  9. 阅读类app界面设计UI可临摹素材模板
  10. vite方式创建vue项目
  11. MATLAB中的光照处理
  12. 楼宇智能化工程设计、施工、验收规范目录
  13. python 爬取生意参谋数据_用Excel实现生意参谋爬虫,伪装登陆状态
  14. 2022年前端自学全套路线总结(黑马版)
  15. IDEA中amend
  16. 奈式准则和香农定理(附例题)
  17. blender新手入门教程中文 编辑后属性选项显示
  18. vue子组件mounted不执行_vue 页面回退mounted函数不执行的解决方案
  19. Gitblit团队协作
  20. Stata:固定效应模式必须加入时间固定效应吗?

热门文章

  1. SCI文献采集方法:SCI,CSCI等各个期刊论文检索方法以及文献分类管理的方法
  2. 打造最具创新力的开源数据库社区 | 【重庆】openGauss Meetup圆满结束
  3. 用于制作电视广告和音乐视频的计算机,基于BS方式实现视音频编辑的系统及方法专利_专利查询 - 天眼查...
  4. Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现
  5. LSTM之父发文:我眼中的深度学习十年简史!
  6. 政府部门网络建设解决方案全过程
  7. 第17家图商名落宽凳,正式获导航电子地图制作甲级资质
  8. 街边小投资冷门暴利行业有哪些?做什么生意利润高?
  9. 中断服务程序执行顺序
  10. 真实案例:一个渠道、一本书,狠狠赚了200万