zoukankan      html  css  js  c++  java
  • 图片跨域规律探寻

    先说结论:

    1. canvas.toDataURL API中用到的图片,必须添加crossOrigin属性设置,否则会报被污染的canvas无法被导出的错误

    2. url相同,crossOrigin属性的图,在页面中通过html img标签和js-dom Image对象不管加载多少次,浏览器只请求服务器一次。从缓存中读取时,多次加载也只读取一次。

    3. 页面加载多幅url相同的图片,如果这些图片中有些设置了跨域属性,有的未跨域属性,只要设置了跨域属性的图之后会加载没有跨域属性的图,那么最后缓存的就是没有跨域属性的图。

    4. 如果缓存的是没有跨域属性的图片,设置了跨域属性的html img标签,js-dom Image对象从缓存中加载图片,会报跨域错误。如果缓存的是设置了跨域属性的图片,html img标签,js-dom Image对象 无论是否设置跨域属性,都可以从缓存中正常加载图片。

    再看实验过程:

    1.分别加载没有设置crossOrigin属性的html-img和js-img图片,调用canvas.toDataURL转换data URI,执行时都会报错-被污染的canvas无法被导出,这个错误是由于canvas使用了未设置跨域的图片资源引起的,只有设置了crossOrigin属性的图片资源,才能被canvas复用。

    1.1 加载没有设置crossOrigin="anonymous"属性的html-img图片,执行canvas.toDataURL

    <img  alt=""  id="html-img"
      src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div  id="js-canvas-box"></div>
    <script>
        // 将图片绘制在canvas画布上
        function convertCanvasToImage(image) {
          const canvas = document.createElement('canvas');
          canvas.width = image.width;
          canvas.height = image.height;
          canvas.getContext('2d').drawImage(image, 0, 0);
          // 从canvas画布导出图片
          const img = new Image();
          img.src = canvas.toDataURL('image/png');
          return img;
        }
        
        // 通过html-img标签加载图片
        const htmlImg = document.querySelector('#html-img');
        htmlImg.onload = function () {
          const img=convertCanvasToImage(this);
          document.querySelector('#js-canvas-box').appendChild(img);
        };
        </script>

    报如下错误:

    1.2 加载没有设置crossOrigin="anonymous"属性的js-image图片,执行canvas.toDataURL

    <div id="js-canvas-box" />
    <script>
        // 将图片绘制在canvas画布上
        function convertCanvasToImage(image) {
          const canvas = document.createElement('canvas');
          canvas.width = image.width;
          canvas.height = image.height;
          canvas.getContext('2d').drawImage(image, 0, 0);
          // 从canvas画布导出图片
          const img = new Image();
          img.src = canvas.toDataURL('image/png');
          return img;
        }
        
        // 通过js-dom加载图片
        const jsImg = new Image();
        jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
        jsImg.onload = function () {
          const img=convertCanvasToImage(this);
          document.querySelector('#js-canvas-box').appendChild(img);
        };
        </script>

    报如下错误:

    2.分别加载设置crossOrigin属性时html-img和js-img图片,调用canvas.toDataURL执行都正常。

    crossOrigin可以有下面两个值:

    anonymous 元素的跨域资源请求不需要凭证标志设置。
    use-credentials 元素的跨域资源请求需要凭证标志设置,意味着该请求需要提供凭证

    只要crossOrigin的属性值不是use-credentials,全部都会解析为anonymous,包括空字符串。

    2.1 加载设置crossOrigin属性时html-img图片,执行canvas.toDataURL,结果正确。

    <img  alt=""  id="html-img" crossOrigin=""
      src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div id="js-canvas-box" />
    <script>
        // 将图片绘制在canvas画布上
        function convertCanvasToImage(image) {
          const canvas = document.createElement('canvas');
          canvas.width = image.width;
          canvas.height = image.height;
          canvas.getContext('2d').drawImage(image, 0, 0);
          // 从canvas画布导出图片
          const img = new Image();
          img.src = canvas.toDataURL('image/png');
          return img;
        }
        
        // 通过html-img标签加载图片
        const htmlImg = document.querySelector('#html-img');
        htmlImg.onload = function () {
          const img=convertCanvasToImage(this);
          document.querySelector('#js-canvas-box').appendChild(img);
        };
        </script>

    2.2 加载设置crossOrigin属性时js-img图片,执行canvas.toDataURL,结果正确。

    <div id="js-canvas-box" />
    <script>
        
        function convertCanvasToImage(image) {
          // 将图片绘制在canvas画布上
          const canvas = document.createElement('canvas');
          canvas.width = image.width;
          canvas.height = image.height;
          canvas.getContext('2d').drawImage(image, 0, 0);
    
          // 从canvas画布导出图片
          const img = new Image();
          img.src = canvas.toDataURL('image/jpg');
          return img
        }
        
        // 通过js-dom加载图片
        const jsImg = new Image();
        // 只要crossOrigin的属性值不是use-credentials,全部都会解析为anonymous,包括空字符串。
        jsImg.crossOrigin=""
        jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
        jsImg.onload = function () {
          const image=convertCanvasToImage(jsImg);
          document.querySelector('#js-canvas-box').appendChild(image);
        };
    </script>

    3.再看看从缓存加载,会不会报错。启用缓存,分别加载设置crossOrigin属性时html-img和js-img图片,执行canvas.toDataURL,也都没有报错。

    3.1 启用缓存,加载设置crossOrigin属性时html-img图片,执行canvas.toDataURL,结果正确。

    <img  alt=""  id="html-img"
     crossOrigin="anonymous"
     src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div id="js-canvas-box" />
    <script>
        
        function convertCanvasToImage(image) {
          // 将图片绘制在canvas画布上
          const canvas = document.createElement('canvas');
          canvas.width = image.width;
          canvas.height = image.height;
          canvas.getContext('2d').drawImage(image, 0, 0);
    
          // 从canvas画布导出图片
          const img = new Image();
          img.src = canvas.toDataURL('image/jpg');
          return img
        }
        // 通过html-img加载图片
        const htmlImg = document.querySelector('#html-img');
        htmlImg.onload = function () {
          const image=convertCanvasToImage(this);
          document.querySelector('#js-canvas-box').appendChild(image);
        };
    </script>

    3.2 启用缓存,加载设置crossOrigin属性时js-img图片,执行canvas.toDataURL,结果正确。

    <div id="js-canvas-box" />
    <script>
        
        function convertCanvasToImage(image) {
          // 将图片绘制在canvas画布上
          const canvas = document.createElement('canvas');
          canvas.width = image.width;
          canvas.height = image.height;
          canvas.getContext('2d').drawImage(image, 0, 0);
    
          // 从canvas画布导出图片
          const img = new Image();
          img.src = canvas.toDataURL('image/jpg');
          return img
        }
        
     // 通过js-dom加载图片
        const jsImg = new Image();
        // 只要crossOrigin的属性值不是use-credentials,全部都会解析为anonymous,包括空字符串。
        jsImg.crossOrigin=""
        jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
        jsImg.onload = function () {
          const image=convertCanvasToImage(this);
          document.querySelector('#js-canvas-box').appendChild(image);
        };
    </script>

     

    4. 通过html-img和js-img加载url相同,crossOrigin属性的图,只加载一次。从缓存中读取时,也只读取一次

    4.1 html-img和js-img都未设置crossOrigin,加载同一幅图,只加载一次。

    <img
      alt="img"
      id="html-img"
      src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div id="js-canvas-box"></div>
    <script>
      const jsImg = new Image();
      jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
      jsImg.onload = function () {
        document.querySelector('#js-canvas-box').appendChild(jsImg);
      };
    </script>

    从缓存中读取,只读取了一次。

    4.2 html-img和js-img都设置crossOrigin,加载同一幅图,只加载一次。

    <img
      alt="img"
      id="html-img"
      crossOrigin=""
      src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div id="js-canvas-box"></div>
    <script>
      const jsImg = new Image();
      jsImg.crossOrigin=""
      jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
      jsImg.onload = function () {
        document.querySelector('#js-canvas-box').appendChild(this);
      };
    </script>

    从缓存中读取,只读取一次。

    5. 再看看通过html-img的方式加载url相同,crossOrigin属性不同的情景,页面加载多个url一样的html-img图片,如果在跨域属性图片之后加载了没有跨域属性的图片,那么最后缓存的是未设置crossOrigin属性的图片,刷新页面,那些设置了crossOrigin属性的图片,从缓存中加载图片时,会报跨域错误

    这是因为:

    • 在页面加载的过程中,图片会被浏览器缓存,如果再次遇到url和crossOrigin属性相同的图片,直接会从缓存中读取,如果url相同,crossOrigin属性与之前缓存的图片不同,浏览器会重新请求,并重新缓存,覆盖之前缓存的同一张图。可是缓存中的图片跨域属性一旦从跨域变成不跨域,之后浏览器便不会在覆盖之前的缓存。缓存的图片始终保持为不跨域。
    • 缓存的图片如果是未设置跨域属性的图片,html-img标签设置了crossOrigin属性,从缓存加载,会触发跨域问题。缓存的图片如果是设置了跨域属性的图片,无论html-img标签是否设置crossOrigin属性,从缓存加载,都不会触发跨域问题。

    5.1 最后缓存的是没有设置crossOrigin属性的图片, 从缓存中加载时,触发了html img标签中设置了crossOrigin属性图片的跨域。

    <!-- 缓存的是没有跨域属性的图片 -->
    <img
    alt="img-3-no"
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    
    <!-- 缓存被覆盖,缓存的是有跨域属性的图片 -->
    <img
    alt="img-2-anonymous"
    crossOrigin="anonymous"
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    
    
    <!-- 缓存再次被覆盖,缓存的是没有跨域属性的图片 -->
    <img
    alt="img-3-no"
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <!-- 缓存中同一幅图的跨域属性一旦由跨域变成不跨域,之后浏览器不会再修改图片的跨域属性 -->
    <img
    alt="img-4-anonymous"
    crossOrigin="anonymous"
    
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />

    1.5kb的图片是没有跨域属性的图片,1.6kb的图片是设置了跨域属性的图片,从网络请求面板可以看到,最后请求的是没有跨域属性的图片,意味着最后缓存的也是没有跨域属性的图片。

    设置了跨域属性的html img标签,从缓存中加载没有跨域属性的图片,浏览器会报跨域错误。

    5.2 最后缓存的图是设置了crossOrigin的图片,从缓存中加载时,  不会触发html img标签中未设置crossOrigin属性图片的跨域。

    <!-- 缓存的是没有跨域属性的图片 -->
    <img
    alt="img-3-no"
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    
    <!-- 缓存过,不再缓存 -->
    <img
    alt="img-2-no"
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    
    
    <!-- 缓存过,不再缓存 -->
    <img
    alt="img-3-no"
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <!-- 缓存被覆盖,缓存的是有跨域属性的图片 -->
    <img
    alt="img-4-anonymous"
    crossOrigin="anonymous"
    
    src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />

     从网络请求面板可以看出,最后请求的是1.6kb的设置了跨域属性的图片,意味着缓存中最后保持的也是有跨域属性的图片

     html img标签即使未设置跨域属性,也能利用缓存中保存的设置了跨域属性的图片,不会报错。

    6.再看看html-img和js-img混搭加载的情景, 页面加载多个url相同的html-img和js-img混搭图片,前面的结论依旧成立。

    6.1 最后缓存的是没有设置crossOrigin属性的图片,从缓存加载时,设置了crossOrigin属性的图片会报跨域错误。

    <img
      alt="img"
      id="html-img"
      crossOrigin="anonymous"
      src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div id="js-canvas-box"></div>
    <script>
      const jsImg = new Image();
      jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
      jsImg.onload = function () {
        document.querySelector('#js-canvas-box').appendChild(jsImg);
      };
    </script>

     

    6.2 最后缓存的是设置了crossOrigin属性的图片,从缓存加载时,不会触发没有设置crossOrigin属性的图片跨域错误。

    <img
      alt="img"
      id="html-img"
      src="https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png"
    />
    <div id="js-canvas-box"></div>
    <script>
      const jsImg = new Image();
      jsImg.crossOrigin="anonymous"
      jsImg.src ='https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/app-install.81ece51.png';
      jsImg.onload = function () {
        document.querySelector('#js-canvas-box').appendChild(jsImg);
      };
    </script>

  • 相关阅读:
    matlab中padarray函数在numpy、python中的实现
    MAC卸载/删除 Parallels Desktop虚拟机的方法
    CNMeM is disabled
    UbuntuServer14.04+CUDA7.5+CuDNNv3+Caffe+OpenCV3.0+配置
    npy数据的保存与读取
    update_TypeError
    Git操作流程,基本命令演示
    CSS 的优先级机制[总结]
    Git 进阶 —— 远程仓库
    Git实现从本地添加项目到远程仓库
  • 原文地址:https://www.cnblogs.com/wangpenghui522/p/14470760.html
Copyright © 2011-2022 走看看