有看過這種HTML嗎?

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Data URI</title>
    <link href="data:text/css;base64,77u/aW1nICANCnsNCiAgICBib3JkZXI6IDFweCBzb2xpZCByZWQ7DQp9DQo=" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <img src="data:image/gif;base64,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" />
    </form>
</body>
</html>

在HTML裡link的href及img的src,並沒有指向某個URL,而是直接嵌入一段Base64編碼,而IE8+, Firefox, Safari, Opera, Chrome都能正確顯示其中的圖檔與CSS設定。

這種表示方法叫做data URI schema,是新一代瀏覽器支援的檔案資料表現格式,允許在網頁裡以字串形式直接內嵌圖檔、CSS檔案,進而達到以下好處:

  1. 瀏覽器不用為了下載圖檔、CSS另外發動HTTP Request。每次HTTP傳輸產生的額外資料量(HTTP Header、TCP/IP Header...等),累積下來多半會大於使用Base64編碼二進位資料所增加的資料量(每3個Byte增加一個Byte),事實上內嵌成Base64字串反而較節省頻寬。
  2. 基於TCP傳輸特性,傳送一個大檔案會比連續傳送多個拆解的小檔更快速有效率。(HTTP Keep-Alive可以改善傳送多個小檔案效率不佳的問題,但並不能徹底解決)
  3. 使用HTTPS(SSL)傳輸時,因為HTTPS Request的額外程序更多,內嵌資料做法的改善更明顯。
  4. 瀏覽器通常會有同時使用HTTP連線數的上限(例如: 兩條),將所有需要資料一次下載回來,可以避免持續佔用寶貴的連線資源。
  5. 以往在網頁式的Rich Text編輯器裡處理貼上圖檔,得將圖檔上傳至伺服器端某處,再將URL丟回編輯器中。使用內嵌資料寫法,可讓網頁編輯文字要內嵌圖檔容易多了。

當然,凡事不會有利無害,網頁內嵌資料的做法也有其缺點:

  1. 因圖檔內容被綁在網頁中,若為動態網頁每次內容都會變化,就無法透過快取加速及節省頻寬,網頁內容含圖檔資料,每次都得重新下載。
  2. 當檔案資料有變化時,所有內嵌它的網頁都要重新產生編碼。
  3. IE8以上的版本才有支援,且限制大小不可超過32KB
  4. Base64會讓內容變大33%,但若Web Server端啟用GZIP壓縮,增加的大小可以縮小到2-3%。
  5. 對資安軟體來說,Data URI增加了網頁內容檢驗的難度。

IE從IE8開始才支援這種Data URI的做法,且基於安全、效率的考量,加入了一些限制:

  • 不支援Javascript檔內嵌,避免惡意程式藏匿其中,逃避Script過濾機制。
  • 內嵌檔案大小不可超過32KB。
  • 支援格式包含: object (images only) , img, input type=image, link
    以及CSS宣告,例如:
    background-image, background, list-style-type, list-style等。

我寫了一小段ASP.NET程式用來產生Data URI字串,最前面的HTML就是透過這個工具做出來的,大家也可以玩看看。

using System;
using System.IO;
 
public partial class DataURI_Default : System.Web.UI.Page
{
    private string GenDataURI(string contentType, string filePath)
    {
        byte[] buff = File.ReadAllBytes(filePath);
        return string.Format("data:{0};base64,{1}",
            contentType, Convert.ToBase64String(buff));
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        string path = Request["path"] ?? "";
        if (!string.IsNullOrEmpty(path) &&
            File.Exists(Server.MapPath(path)))
        {
            string contentType = "";
            switch (path.ToLower().Substring(path.Length-4, 4))
            {
                case ".jpg":
                    contentType="image/jpeg";
                    break;
                case ".gif":
                    contentType="image/gif";
                    break;
                case ".png":
                    contentType="image/png";
                    break;
                case ".htm":
                    contentType="text/html";
                    break;
                case ".css":
                    contentType="text/css";
                    break;
                default:
                    Response.Write("Not supperted file type!");
                    Response.End();
                    break;
            }
            Response.Write(GenDataURI(contentType, Server.MapPath(path)));
            Response.End();
        }
    }
}

Comments

# by Mesak

男丁大有寫個應用程式可以直接轉.... 這東西我也滿長拿來放進 greasemonkey http://userscripts.org/scripts/show/63761

# by player

php版的實驗版 http://www.player.idv.tw/prog/toolkits/web/data_uri.php 如果要看code的話,放在 http://www.player.idv.tw/prog/index.php/Data_URI_scheme#PHP

# by drem

發現 google搜尋結果多了圖片預覽… 再仔細一看,大神的預覽圖片是用 data URI的方式做的

Post a comment