avatar

image访问图片跨域的问题

背景

项目(vue项目)中遇到一个问题,有一个需求,在一个图片预览的组件中,左边是图片的缩略图,右边是一个图片的可编辑区域(用canvas画布实现的,图片的放大/缩小/旋转/移动/镜像等操作),开发人员在开发的时候发现: 如果打开F12,则不会报跨域问题,如果关闭F12,就会报跨域问题,报错如下:

意思是在访问图片时出现了跨域问题

问题梳理

这里先给出结论: 同一个图片在 dom 节点中使用了 img标签来加载,同时在其他地方用了脚本去生成一个同src 的 img 标签, 就会出现此问题

我们项目中即是这样, 又在 dom 节点中使用了 img 标签来加载, 同时在右侧canvas组件中用了脚本去生成一个 img 标签

图片的加载分析

图片是来自于客户的问题存储服务器的,和本地 localhost 必然存在跨域问题。通过 dom 节点的 img 标签来直接访问是没有问题,因为浏览器本身不会有跨域问题。问题出在了我们自己写的一个canvas图片展示和编辑的组件中, 使用了new Image(); img.src = xxx; 来创建图片, 代码大致如下:

1
2
3
4
5
6
7
8
9
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
// ...
};
img.onerror = () => {
// ...
};
img.src = this.imgs;

这段代码所描述的大致思路是:

  1. 通过JS代码,创建一个 img 的 dom ,然后使用这个 img 标签来加载图片。

  2. 默认情况下,设置了 crossOrigin 的跨域属性为 ‘anonymous’。

所以,问题的关键在于,同一张图片

① 先用 img 标签去加载了(此img标签没有设置 crossOrigin 属性为 ‘anonymous’)

② 再在 JS 代码中,创建一个 img 并且设置了 crossOrigin 的跨域属性为 ‘anonymous’,那么在 JS 中创建的 img 就会出现访问图片而产生跨域的问题。

关于crossOrigin

  1. 加了 crossorigin 属性,则表明图片就一定会按照 CORS 来请求图片。而通过CORS 请求到的图片可以再次被复用到 canvas 上进行绘制。换言之,如果不加 crossorigin 属性的话,那么图片是不能再次被复用到 canvas 上去的。

  2. 可以设置的值有 anonymous 以及 use-credentials,2 个 value 的作用都是设置通过 CORS 来请求图片,区别在于 use-credentials 是加了证书的 CORS。

  3. 如果默认用户不进行任何设置,那么就不会发起 CORS 请求。但如果设置了除 anonymous 和 use-credentials 以外的其他值,包括空字串在内,默认会当作 anonymous来处理。

问题总结

通过前面 2 点的梳理,我们得出如下结论:

  1. 通过 ‘img’ 加载的图片,浏览器默认情况下会将其缓存起来。

  2. 当我们从 JS 的代码中创建的 ‘img’ 再去访问同一个图片时,浏览器就不会再发起新的请求,而是直接访问缓存的图片。但是由于 JS 中的 ‘img’ 设置了 crossorigin,也就意味着它将要以 CORS 的方式请求,但缓存中的图片显然不是的,所以浏览器直接就拒绝了。连网络请求都没有发起。

  3. 在 Chrome 的调试器中,在 network 面板中,我们勾选了 disable cache 选项,验证了问题确实如第 2 点所述,浏览器这时发起了请求并且 JS 的 ‘img’ 也能正常请求到图片。

解决问题

前面通过勾选 disable cache 来避免浏览器使用缓存图片而解决了问题,但实际用户不会这样使用啊。根据前面的梳理,’img’ 不跨域请求,而 JS 中的 ‘img’ 跨域请求,所以不能访问缓存,那么是不是可以将 JS 中的 ‘img’ 也设置成不跨域呢,于是将 JS 中的 ‘img’ 的 crossorigin 设置为 undefine,结果图片是可以加载了,但又报错, 错误的意思是,这一个来自于CORS 的图片,是不可以再次被复用到 canvas 上去的。这就验证了关于 crossorigin 中的第 1 点。

既然 ‘img’ 和 JS 中的 ‘img’ 都不加 crossorigin不能解决 canvas 重用的问题,那么在两边同时都加上 crossorigin 呢?果然,在 ‘img’ 中和 JS 中的 ‘img’ 都加上 crossorigin = “anonymous”,图片可以正常加了,同时也可以被复用到 ‘canvas’ 上去了。

另外,需要注意 2 个小问题是:

  1. 服务器必须加上字段,否则,客户端设置了也是没用的。
1
Access-Control-Allow-Origin: *
  1. 如果是已经出了问题,你才看到这篇文章,或者才去想到这么解决。那么要记得先清理一下游览器所缓存的图片。否则你就会发现,有的图片可以访问,而有的不可以。那是因为缓存中之前存储了未 CORS 的图片。
文章作者: Kwin
文章链接: http://kw1n.cn/2020/03/25/20191212-image访问图片跨域的问题/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Kwin 's Blog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论