2023年6月21日发(作者:)

⼀个关于image访问图⽚跨域的问题⼀、背景项⽬中遇到⼀个问题,同⼀个图⽚在 dom 节点中使⽤了 标签来加载,同时由于项⽬使⽤了 ThreeJS 3D 渲染引擎,在加载纹理时使⽤了TextureLoader 来加载了同⼀张图⽚,⽽由于图⽚是在阿⾥云服务器上的,所以最后报出了如下错误,意思是在访问图⽚时出现了跨域问题:image 跨域错误⼆、问题梳理2.1 关于图⽚的加载图⽚是来⾃于阿⾥云服务器的,和本地 localhost 必然存在跨域问题。通过 dom 节点的 标签来直接访问是没有问题,因为浏览器本⾝不会有跨域问题。问题出在通过 TextureLoader 来加载图⽚时出现了跨域问题。查看了 TextureLoader 的源码,发现其进⼀步使⽤了ImageLoader 来加载图⽚,加载图⽚的代码⼤致如下:crossOrigin: 'anonymous',......var image = ElementNS( '/1999/xhtml', 'img' );......if ( ( 0, 5 ) !== 'data:' ) { if ( rigin !== undefined ) rigin = rigin; }...... = url;这段代码所描述的⼤致思路是:1. 通过JS代码,创建⼀个 img 的 dom element,然后使⽤这个 element 来加载图⽚。2. 默认情况下,设置了 crossOrigin 的跨域属性为 'anonymous'。所以,问题的关键在于,同⼀张图⽚,先⽤ 标签去加载了,然后再在 JS 代码中,创建⼀个 并且设置了 crossOrigin 的跨域属性为 'anonymous',那么在 JS 中创建的 就会出现访问图⽚⽽产⽣跨域的问题。2.2 关于 crossOrigin关于 crossOrigin,我们看看 MDN 的解释。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.3 问题总结通过前⾯ 2 点的梳理,我们得出如下结论:1. 通过 加载的图⽚,浏览器默认情况下会将其缓存起来。2. 当我们从 JS 的代码中创建的 再去访问同⼀个图⽚时,浏览器就不会再发起新的请求,⽽是直接访问缓存的图⽚。但是由于 JS 中的 设置了 crossorigin,也就意味着它将要以 CORS 的⽅式请求,但缓存中的图⽚显然不是的,所以浏览器直接就拒绝了。连⽹络请求都没有发起。3. 在 Chrome 的调试器中,在 network ⾯板中,我们勾选了 disable cache 选项,验证了问题确实如第 2 点所述,浏览器这时发起了请求并且 JS 的 也能正常请求到图⽚。三、解决问题前⾯通过勾选 disable cache 来避免浏览器使⽤缓存图⽚⽽解决了问题,但实际⽤户不会这样使⽤啊。根据前⾯的梳理, 不跨域请求,⽽JS 中的 跨域请求,所以不能访问缓存,那么是不是可以将 JS 中的 也设置成不跨域呢,于是将 JS 中的 的 crossorigin 设置为 undefine,结果图⽚是可以加载了,但⼜得到如下错误。这段错误的意思是,这⼀个来⾃于CORS 的图⽚,是不可以再次被复⽤到 canvas 上去的。这就验证了关于 crossorigin 中的第 1 点。既然 和 JS 中的 都不加 crossorigin不能解决 canvas 重⽤的问题,那么在两边同时都加上 crossorigin 呢?果然,在 中和 JS 中的 都加上 crossorigin = "anonymous",图⽚可以正常加了,同时也可以被复⽤到 上去了。另外,需要注意的 2 个⼩问题是:1. 服务器必须加上字段,否则,客户端设置了也是没⽤的。Access-Control-Allow-Origin: *2. 如果是已经出了问题,你才看到这篇⽂章,或者才去想到这么解决。那么要记得先清理⼀下游览器所缓存的图⽚。否则你就会发现,有的图⽚可以访问,⽽有的不可以。那是因为缓存中之前存储了未 CORS 的图⽚。四、总结前⾯说了⼀框,只是想把这个过程完整的记录下来。整个问题的总结是:1. 同⼀张图⽚或者同⼀个地址,同时被 所访问,⽽随后后⼜会被如 JS 中去访问。⽽图⽚存储的地址是跨域的,那么就可能因为缓存问题⽽导致 JS 中的访问出现跨域问题。2. 解决的办法是让 标签和 JS 中的访问都⾛跨域访问的⽅式,这样既可以解决跨域访问的问题,也可以解决跨域图⽚在 canvas 中的复⽤。最后,感谢你能读到并读完此⽂章,如果分析的过程中存在错误或者疑问都欢迎留⾔讨论。如果我的分享能够帮助到你,还请记得帮忙点个赞吧,谢谢。

2023年6月21日发(作者:)

⼀个关于image访问图⽚跨域的问题⼀、背景项⽬中遇到⼀个问题,同⼀个图⽚在 dom 节点中使⽤了 标签来加载,同时由于项⽬使⽤了 ThreeJS 3D 渲染引擎,在加载纹理时使⽤了TextureLoader 来加载了同⼀张图⽚,⽽由于图⽚是在阿⾥云服务器上的,所以最后报出了如下错误,意思是在访问图⽚时出现了跨域问题:image 跨域错误⼆、问题梳理2.1 关于图⽚的加载图⽚是来⾃于阿⾥云服务器的,和本地 localhost 必然存在跨域问题。通过 dom 节点的 标签来直接访问是没有问题,因为浏览器本⾝不会有跨域问题。问题出在通过 TextureLoader 来加载图⽚时出现了跨域问题。查看了 TextureLoader 的源码,发现其进⼀步使⽤了ImageLoader 来加载图⽚,加载图⽚的代码⼤致如下:crossOrigin: 'anonymous',......var image = ElementNS( '/1999/xhtml', 'img' );......if ( ( 0, 5 ) !== 'data:' ) { if ( rigin !== undefined ) rigin = rigin; }...... = url;这段代码所描述的⼤致思路是:1. 通过JS代码,创建⼀个 img 的 dom element,然后使⽤这个 element 来加载图⽚。2. 默认情况下,设置了 crossOrigin 的跨域属性为 'anonymous'。所以,问题的关键在于,同⼀张图⽚,先⽤ 标签去加载了,然后再在 JS 代码中,创建⼀个 并且设置了 crossOrigin 的跨域属性为 'anonymous',那么在 JS 中创建的 就会出现访问图⽚⽽产⽣跨域的问题。2.2 关于 crossOrigin关于 crossOrigin,我们看看 MDN 的解释。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.3 问题总结通过前⾯ 2 点的梳理,我们得出如下结论:1. 通过 加载的图⽚,浏览器默认情况下会将其缓存起来。2. 当我们从 JS 的代码中创建的 再去访问同⼀个图⽚时,浏览器就不会再发起新的请求,⽽是直接访问缓存的图⽚。但是由于 JS 中的 设置了 crossorigin,也就意味着它将要以 CORS 的⽅式请求,但缓存中的图⽚显然不是的,所以浏览器直接就拒绝了。连⽹络请求都没有发起。3. 在 Chrome 的调试器中,在 network ⾯板中,我们勾选了 disable cache 选项,验证了问题确实如第 2 点所述,浏览器这时发起了请求并且 JS 的 也能正常请求到图⽚。三、解决问题前⾯通过勾选 disable cache 来避免浏览器使⽤缓存图⽚⽽解决了问题,但实际⽤户不会这样使⽤啊。根据前⾯的梳理, 不跨域请求,⽽JS 中的 跨域请求,所以不能访问缓存,那么是不是可以将 JS 中的 也设置成不跨域呢,于是将 JS 中的 的 crossorigin 设置为 undefine,结果图⽚是可以加载了,但⼜得到如下错误。这段错误的意思是,这⼀个来⾃于CORS 的图⽚,是不可以再次被复⽤到 canvas 上去的。这就验证了关于 crossorigin 中的第 1 点。既然 和 JS 中的 都不加 crossorigin不能解决 canvas 重⽤的问题,那么在两边同时都加上 crossorigin 呢?果然,在 中和 JS 中的 都加上 crossorigin = "anonymous",图⽚可以正常加了,同时也可以被复⽤到 上去了。另外,需要注意的 2 个⼩问题是:1. 服务器必须加上字段,否则,客户端设置了也是没⽤的。Access-Control-Allow-Origin: *2. 如果是已经出了问题,你才看到这篇⽂章,或者才去想到这么解决。那么要记得先清理⼀下游览器所缓存的图⽚。否则你就会发现,有的图⽚可以访问,⽽有的不可以。那是因为缓存中之前存储了未 CORS 的图⽚。四、总结前⾯说了⼀框,只是想把这个过程完整的记录下来。整个问题的总结是:1. 同⼀张图⽚或者同⼀个地址,同时被 所访问,⽽随后后⼜会被如 JS 中去访问。⽽图⽚存储的地址是跨域的,那么就可能因为缓存问题⽽导致 JS 中的访问出现跨域问题。2. 解决的办法是让 标签和 JS 中的访问都⾛跨域访问的⽅式,这样既可以解决跨域访问的问题,也可以解决跨域图⽚在 canvas 中的复⽤。最后,感谢你能读到并读完此⽂章,如果分析的过程中存在错误或者疑问都欢迎留⾔讨论。如果我的分享能够帮助到你,还请记得帮忙点个赞吧,谢谢。