HTML5 crossorigin 屬性是什麼
常在開發時看到 CDN 的網址中,使用上 crossorigin="anonymous" 屬性,例如:
1 2 3 4 5  | <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>  | 
MDN – CORS settings attributes 文件中說明如下:
在 HTML5 中,一些 HTML 元素提供了對 CORS 的支持, 例如 <audio>、 <img>、 <link>、 <script> 和 <video> 均有一個跨域屬性 (crossOrigin property),它允許你配置元素獲取數據的 CORS 請求。
默認情況下(即未指定 crossOrigin 屬性時),CORS 根本不會使用。在非同源情況下,設置 “anonymous” 關鍵字將不會通過 cookies,客戶端 SSL 證書或 HTTP 認證交換用戶憑據。
canvas 跨域將圖片載入使用
由 JS 產生的圖片實體,指定 canvas 動元素繪製圖片正常呈現
由圖片指定 src 路徑時載下檔案進快取,在 Image 的屬性中本身就有 crossOrigin 預設為 null。
 canvas 大小由載下的圖片檔取得高寬值後,指給 myCanvasEL 動原素,圖片由載下到進 canvas 繪製時這個過程是沒問題的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  | <canvas id="myCanvas"></canvas> <script>   var myCanvasEL = document.getElementById('myCanvas');   var context = myCanvasEL.getContext('2d');   var img = new Image();   var dataURL;  // 由 canvas 轉出的圖片實體   console.log('img.crossOrigin onload 之前', img.crossOrigin); // null   img.src = 'https://media.prod.mdn.mozit.cloud/attachments/2013/06/22/5397/7a3ec0cae64a95ad454ac3bc2c71c004/rhino.jpg';   img.onload = function () {     console.log('img.crossOrigin onload fun 內', img.crossOrigin);  // null     myCanvasEL.width = this.width;     myCanvasEL.height = this.height;     context.drawImage(img, 0, 0); // 將 img 實體使用 canvas 繪畫時不會有錯可執行,此時只是將圖片繪於畫布上   }; </script>  | 
外部圖片要處理成 base64 格式,前提要先 access-control-allow-origin: *
.toDataURL() 為 canvas 轉出畫布為一張 base64 格式的圖片,在轉換時除了圖片的標籤屬性要為 .crossOrigin = 'anonymous'; 或是空字串,讓 JS 在取圖片元素了解,這是張跨域而可不用屬名,執行時才可順利處理,但在這之前需特別注意伺服器端對於資源有設定為 access-control-allow-origin: * (跨來源資源共用)。
圖片來源:開源 pexels

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41  | <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF-8" />     <meta http-equiv="X-UA-Compatible" content="IE=edge" />     <meta name="viewport" content="width=device-width, initial-scale=1.0" />     <title>HTML 基本自定樣版</title>     <link rel="icon" href="data:;base64,iVBORw0KGgo=" />     <style>       body {         margin: 0;       }     </style>   </head>   <body>     <canvas id="myCanvas"></canvas>     <script>       let myCanvasEL = document.getElementById('myCanvas');       let ctx = myCanvasEL.getContext('2d'); // 指定渲染環境 2D       let logoImg = new Image();       logoImg.src = "https://images.pexels.com/photos/9009959/pexels-photo-9009959.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260";       /* HTML crossOrigin 屬性解決資源跨域問題,屬性值空字串會自動轉 "anonymous" */       logoImg.crossOrigin = 'anonymous';       // logoImg.crossOrigin = '';       console.log('logoImg', logoImg);       logoImg.onload = function(){         // console.log('logoImg.onload', logoImg, this);         console.log('img.crossOrigin onload fun 內', logoImg.crossOrigin);         myCanvasEL.width = this.width;         myCanvasEL.height = this.height;         ctx.drawImage(this, 0, 0);         dataURL = myCanvasEL.toDataURL();         console.log('dataURL', dataURL);       }     </script>   </body> </html>  | 
改以 Google 的 logo 為例,伺服器對於圖傳送設定上本身就沒有 access-control-allow-origin: * (跨來源資源共用),也因此會產生非同源的錯誤提示。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41  | <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF-8" />     <meta http-equiv="X-UA-Compatible" content="IE=edge" />     <meta name="viewport" content="width=device-width, initial-scale=1.0" />     <title>HTML 基本自定樣版</title>     <link rel="icon" href="data:;base64,iVBORw0KGgo=" />     <style>       body {         margin: 0;       }     </style>   </head>   <body>     <canvas id="myCanvas"></canvas>     <script>       let myCanvasEL = document.getElementById('myCanvas');       let ctx = myCanvasEL.getContext('2d'); // 指定渲染環境 2D       let logoImg = new Image();       logoImg.src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png";       /* HTML crossOrigin 屬性解決資源跨域問題,屬性值空字串會自動轉 "anonymous" */       logoImg.crossOrigin = 'anonymous';       // logoImg.crossOrigin = '';       console.log('logoImg', logoImg);       logoImg.onload = function(){         // console.log('logoImg.onload', logoImg, this);         console.log('img.crossOrigin onload fun 內', logoImg.crossOrigin);         myCanvasEL.width = this.width;         myCanvasEL.height = this.height;         ctx.drawImage(this, 0, 0);         dataURL = myCanvasEL.toDataURL();         console.log('dataURL', dataURL);       }     </script>   </body> </html>  | 
img.crossOrigin 預設 null,若使用 canvas 操作轉換圖片,就會產生 The operation is insecure. 錯誤提示
現代的瀏覽器會預設規定 canvas 只能按照 tainted 方式讀取非同域名下的圖片資源。
taint 中文為 污染意指上色、貼膜的意思,比如給汽車車窗貼膜。可理解成瀏覽器以貼膜方式,應該是指只能將圖片貼在 canvas 上,但不能將圖片作為數據讀出來,從而防止某些隱私信息隨著圖片傳到別的地方。
此時的 canvas 畫版中,已將圖片指於畫版繪製出畫面,在透過 .getImageData() & .toDataURL() 相關圖片操作方法轉出圖片,此時就會出現錯誤提示 The operation is insecure.,這主要將所繪製的畫面,限定於不能以數據的方式直接讀出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  | <canvas id="myCanvas"></canvas> <script>   var myCanvasEL = document.getElementById('myCanvas');   var context = myCanvasEL.getContext('2d');   var img = new Image();   var dataURL;  // 由 canvas 轉出的圖片實體   // img.crossOrigin = 'anonymous';   // img.crossOrigin = '';  // HTML crossOrigin 屬性解決資源跨域問題,屬性值空字串會自動轉 "anonymous"   console.log('img.crossOrigin onload 之前', img.crossOrigin);  // null   img.src = 'https://media.prod.mdn.mozit.cloud/attachments/2013/06/22/5397/7a3ec0cae64a95ad454ac3bc2c71c004/rhino.jpg';   img.onload = function () {     console.log('img.crossOrigin onload fun 內', img.crossOrigin); // null     myCanvasEL.width = this.width;     myCanvasEL.height = this.height;     context.drawImage(img, 0, 0); // 將 img 實體使用 canvas 繪畫時不會有錯可執行,此時只是將圖片繪於畫布上     dataURL = myCanvasEL.toDataURL();   }; </script>  | 
指定來原圖片屬性 crossOrigin = ‘anonymous’,修正 canvas 無法跨域轉出圖片的安全性錯誤提示
當使用到 canvas 的相關圖片操作方法 .getImageData() & .toDataURL() 時
 img crossOrigin 屬性為 null 時就會出現錯誤提示 The operation is insecure.。
 需在 .onload 產生圖片實體前,先指定圖片屬性 img.crossOrigin = 'anonymous’ 就不會在出現錯誤中斷的提示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25  | <canvas id="myCanvas"></canvas> <script>   var myCanvasEL = document.getElementById('myCanvas');   var context = myCanvasEL.getContext('2d');   var img = new Image();   var dataURL;  // 由 canvas 轉出的圖片實體   img.crossOrigin = 'anonymous';   // img.crossOrigin = '';  // HTML crossOrigin 屬性解決資源跨域問題,屬性值空字串會自動轉 "anonymous"   console.log('img.crossOrigin onload 之前', img.crossOrigin);   img.src = 'https://media.prod.mdn.mozit.cloud/attachments/2013/06/22/5397/7a3ec0cae64a95ad454ac3bc2c71c004/rhino.jpg';    img.onload = function () {     console.log('img.crossOrigin onload fun 內', img.crossOrigin);     myCanvasEL.width = this.width;     myCanvasEL.height = this.height;     context.drawImage(img, 0, 0); // 將 img 實體使用 canvas 繪畫時不會有錯可執行,此時只是將圖片繪於畫布上     /** 當使用到 canvas 的相關圖片操作方法 .getImageData() & .toDataURL() 時      * img crossOrigin 屬性為 null 時 就會出現錯誤提示 The operation is insecure.      * 需在 .onload 產生圖片實體前,先指定圖片屬性 img.crossOrigin = 'anonymous' 就不會在出現錯誤中斷的提示     */     dataURL = myCanvasEL.toDataURL();   };  | 
HTML5 靜態元素 img 取 CROS 資源,使用 crossorigin=’anonymous’,將 canvas 轉出成 base64 格式圖片
上面的功能以 HTML5 靜態元素方式載入圖片 <img> 元素中,使用 crossorigin='anonymous' 屬性,當然如果在透過遠端取得的來源圖片,要由 canvas 用轉出圖片的方法,沒有 crossorigin='anonymous' 屬性 是會回應 The operation is insecure.,中斷於 canvas 繪製出圖片於元素上,沒能將所繪製的部份轉出成 base64 的圖片格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  | <!-- <img id="cros_img" src="https://media.prod.mdn.mozit.cloud/attachments/2013/06/22/5397/7a3ec0cae64a95ad454ac3bc2c71c004/rhino.jpg"> --> <!-- 提示 The operation is insecure. --> <img id="cros_img" src="https://media.prod.mdn.mozit.cloud/attachments/2013/06/22/5397/7a3ec0cae64a95ad454ac3bc2c71c004/rhino.jpg" crossorigin='anonymous'> <canvas id="myCanvasEL_use_crossorigin"></canvas> <script>   var myCanvasEL_use_crossorigin = document.getElementById('myCanvasEL_use_crossorigin');   var imgEL = document.getElementById('cros_img')   var context = myCanvasEL_use_crossorigin.getContext('2d');   var dataURL;   imgEL.onload = function() {     myCanvasEL_use_crossorigin.width = imgEL.width;     myCanvasEL_use_crossorigin.height = imgEL.height;     context.drawImage(imgEL, 0, 0)     dataURL = myCanvasEL_use_crossorigin.toDataURL();     console.log('dataURL', dataURL);   } </script>  | 
參考資料
HTML5 script 標簽裡的 crossorigin 屬性到底有什麼用?
 HTML5 img 與 link 標簽裡的 crossorigin 屬性到底有什麼用
 解決canvas圖片getImageData,toDataURL跨域問題
