在Chrome浏览器中,即使<img crossOrigin=anonymous>也会被同源策略拦截

强转露台
• 阅读 1678

在一次开发中,遇到了生成海报的需求:在图片相册界面用户选择若干张图片,在海报编辑界面用户通过拖动这些图片生成一张海报,供用户下载。

在图片相册界面,图片均展示正常且无报错发生。当用户选择若干张图片之后,进入海报编辑界面前,添加cors属性<img crossOrigin=anonymous>重新加载这些图片,以便canvas处理这些图片数据(图片添加cors属性原因)。神奇的是:所有的图片均无法显示,报错 `......has been blocked by CORS policy: No
Access-Control-Allow-Origin header is present on the
requested resource.`,原来被浏览器的同源策略拦截了。

这些图片存放在Amazon S3,都配置了允许跨域访问。添加了cors参数的img不应该被同源策略拦截,而无法显示。

抽象问题,并探究

添加图片的方法:

const appendImage = (imageUrl, crossOrigin = 'anonymous') => {
    const image = document.createElement('img')

    if (crossOrigin) image.crossOrigin = crossOrigin
    image.src = imageUrl

    document.body.append(image)
}

当在Chrome浏览器中添加全新的图片时,显示正常:
在Chrome浏览器中,即使<img crossOrigin=anonymous>也会被同源策略拦截

清空浏览器缓存之后,当在浏览器中加载需要cors属性的图片时,显示正常:
在Chrome浏览器中,即使<img crossOrigin=anonymous>也会被同源策略拦截

清空浏览器缓存之后,当在浏览器中添加该图片时,显示正常;添加cors属性然后加载该图片时,无法显示:
在Chrome浏览器中,即使<img crossOrigin=anonymous>也会被同源策略拦截

通过Response Headers可以看到:因为没有响应Access-Control-Allow-Origin字段,被浏览器的CORS策略拦截了。

初步结论:通过以上三个现象可以得知,开发需求时的异常现象应该与Chrome浏览器的缓存有关。

原因

通过查询相关文档,发现早在2014年就有人给chromium提出issue:图片资源(url)会缓存在浏览器中,下次访问相同的图片资源(url)时,返回被缓存资源的response。

结合上面的开发需求,可以得出原因:

  1. 图片相册界面中的图片,均以未添加cors属性的方式请求,response返回无跨域头的数据,加载之后便被浏览器缓存;
  2. 海报编辑界面中的图片,均以添加cors属性的方式请求,浏览器返回已有的缓存数据;
  3. 由于缓存数据无跨域头,导致以添加cors属性的方式请求的图片资源,被浏览器的同源策略屏蔽掉。

然而Chromium的开发团队将该问题标记为WontFix(Closed),可能是因为比较符合Chromium引擎的预期行为。

解决方案

在得知原因之后,便着手解决方案:为图片url的search部分添加一个字段,用来区分无cors属性的请求。

const appendImage = (imageUrl, crossOrigin = 'anonymous') => {
    const image = document.createElement('img')
    let src = imageUrl

    if (crossOrigin) {
        src = new URL(src)
        src.searchParams.append(`cors-type`, crossOrigin)
        src = src.toString()

        image.crossOrigin = crossOrigin
    }

    image.src = src

    document.body.append(image)
}

修改appendImage函数之后,再次请求图片,有无cors属性的图片均展示:
在Chrome浏览器中,即使<img crossOrigin=anonymous>也会被同源策略拦截

总结

Chrome浏览器的图片缓存,只按url来区分,因此有无cors属性的图片在请求时是无差别的。若缓存数据无响应Access-Control-Allow-Origin字段,而图片资源需要该字段时就会产生问题。

在url-search里添加字段,用以区分有无cors属性,使缓存能匹配期望的响应。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
java 代码生成分享海报,仅供参考
为了生成一个活动海报,不得不根据海报底图通过java代码手动生成一张海报(包含用户名,用户简介,商品图,商品价格,商品二维码宣传语等),通过千辛万苦后,终于画成功了,我强了但也秃了,这不是因为强而秃,而是我的同事告诉我,为什么不用通过网页htmlcss写出一张海报,然后java代码通过url保存为图片(?????)  我秃了
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
使用taro+canvas实现微信小程序的图片分享功能 | 京东云技术团队
业务场景二轮充电业务中,用户充电完成后在订单详情页展示订单相关信息,用户点击分享按钮唤起微信小程序分享菜单,将生成的图片海报分享给微信好友或者下载到本地,好友可通过扫描海报中的二维码加群领取优惠。使用场景及功能:微信小程序生成海报图片分享好友下载图片使用技
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(