crossorigin属性:为什么它是避免tainted canvases的关键?
本文为HTML标准解读系列文章,其他文章详见这里。
你是否曾经遇到过这样的问题?
- 使用
canvas
的getImageData()
方法,却报错:The canvas has been tainted by cross-origin data
; - 使用
canvas
的toDataURL()
方法,却报错:Tainted canvases may not be exported
; - 使用
document.styleSheets[0].cssRules
访问样式表的css规则,却报错:Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
。
如果你上网找解决方案,会发现他们都跟一个HTML属性密切关联:crossorigin
。crossorigin
是CORS在HTML标签上的应用。 很多的元素,包括img
、video
、audio
、link
、script
都有这个属性:
<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)
请求的三种状态
我们都知道,使用img
、video
、audio
、link
、script
等HTML元素可以请求外部的资源。
根据标准,这些元素所发出的请求可以根据是否支持CORS划分为3种状态:
No CORS
Anonymous
Use Credentials
状态
No CORS
表示不支持CORS的请求。 在这种情况下,不管服务端对应的资源是否也支持CORS, 虽然浏览器依然会拿到资源,这个资源也会正常加载和显示,但使用js访问其资源的能力会受到限制,具体表现为:对于
img
、audio
、video
元素:当这些元素的资源放在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
会报错。只有一种例外情况,当link
和script
与module
一起使用的时候,默认请求状态会设置为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" />
值得一提的是,虽然object
、embed
、iframe
等元素虽然也可以发起资源请求,但是他们都不支持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的关键?相关推荐
- 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- ...
- 使用canvas的toDataURL方法将图片转为base64报错:Tainted canvases may not be exported
toDataURL()报错 在使用Canvas对图片进行裁切功能时,用到了toDataURL方法. 在调试过程中,发现执行到该方法是会报以下错误: Uncaught DOMException: Fai ...
- Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported [已解决]...
原文链接: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported [已解 ...
- canvas跨域:Tainted canvases may not be exported.
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may no ...
- 头像裁剪和Uncaught DOMException: Failed to execute ‘toDataURL‘ on ‘HTMLCanvasElement‘: Tainted canvases m
此文是半原创. 头像裁剪的主要实现是同事找来发我的,用着还不错. 记一下,可以用作以后研究. 此文主要记录一个要点: 当用户上传已上传头像,裁剪头像弹窗获取到图片,当调用canvas的toDataUR ...
- Tainted canvases may not be exported
Tainted canvases may not be exported. 场景 解决方法 总结 场景 在使用html canvas进行绘画,之后想通过canvas的Api toDataURL toB ...
- 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 ...
- html里面的crossorigin属性,HTML5 标签里的 crossorigin 属性到底有什么用? | Chrisyue's Blog...
最近 Bootstrap 4 已经正式发布了,可能已经有爱尝鲜的小伙伴在 alpha 阶段就尝试过 BS4.不过今天要说的不是 BS4,而是官网里引入 BS4 框架依赖的 jQuery 的代码: cr ...
- html完整性检测,html - 什么是完整性和crossorigin属性?
integrity - 定义必须匹配的资源的哈希值(如校验和),以使浏览器执行它. 哈希确保文件未经修改并包含预期数据. 这样浏览器就不会加载不同的(例如恶意的)资源. 想象一下你的JavaScrip ...
最新文章
- 深度学习(5)感知机(神经元)与神经网络
- code blocks 快捷键
- C/C++版数据结构之链表三
- 昨天电脑问题 补昨日8-3复习内容 异常与文件操作
- 动态规划走楼梯_负重爬楼梯、过草地,服贸会六足机械人展示“送水到家”
- 翻转二叉树—leetcode226
- 主/辅DNS服务器详细配置
- [html] html如何启动本地的exe应用?
- 阅读类app界面设计UI可临摹素材模板
- vite方式创建vue项目
- MATLAB中的光照处理
- 楼宇智能化工程设计、施工、验收规范目录
- python 爬取生意参谋数据_用Excel实现生意参谋爬虫,伪装登陆状态
- 2022年前端自学全套路线总结(黑马版)
- IDEA中amend
- 奈式准则和香农定理(附例题)
- blender新手入门教程中文 编辑后属性选项显示
- vue子组件mounted不执行_vue 页面回退mounted函数不执行的解决方案
- Gitblit团队协作
- Stata:固定效应模式必须加入时间固定效应吗?
热门文章
- SCI文献采集方法:SCI,CSCI等各个期刊论文检索方法以及文献分类管理的方法
- 打造最具创新力的开源数据库社区 | 【重庆】openGauss Meetup圆满结束
- 用于制作电视广告和音乐视频的计算机,基于BS方式实现视音频编辑的系统及方法专利_专利查询 - 天眼查...
- Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现
- LSTM之父发文:我眼中的深度学习十年简史!
- 政府部门网络建设解决方案全过程
- 第17家图商名落宽凳,正式获导航电子地图制作甲级资质
- 街边小投资冷门暴利行业有哪些?做什么生意利润高?
- 中断服务程序执行顺序
- 真实案例:一个渠道、一本书,狠狠赚了200万