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跨域問題