2010/07/29

[ASP] 設計 UTF-8 網頁的注意事項

過去很多人在撰寫中文網頁時, 常以 Big5 編碼做為顯示和資料儲存的編碼方式.
不過, Big5 能顯示的字集畢竟沒 UTF-8 多. 所以, 若要讓網頁可顯示更多的字(簡體中文, 日文等), UTF-8 編碼是不錯的選擇.
以下分別就資料庫, 前端網頁, 後端程式三個部分, 說明若要讓網頁顯示 UTF-8 編碼, 有哪些地方需要調整.

  1. 資料庫表格中的欄位資料型態:
    將可能存放中文字的資料欄位, 其資料類型從 char, varchar 和 text 改為使用 nchar, nvarchar 和 ntext.
    例如下圖的資料表結構: (UserName 和 UserTitle 會存 UTF-8 的資料, 所以設定為 nvarchar(50))
    存放使用者資訊的表格(tblUser)
    參考資料: http://technet.microsoft.com/zh-tw/library/ms191200(SQL.90).aspx
  2. 前端網頁的部分:
    1. 修改 <head> 中的 <meta>: 
      目的: 指示使用者端的瀏覽器使用 UTF-8 的編碼, 瀏覽此網頁.
      做法: 在網頁檔的 <head> 中加入 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      (如果原本就有此標籤,只要注意 charset 是 utf-8.)
    2. 修改網頁檔的編碼方式:
      目的: 由於上一步已經指示使用者端瀏覽器, 使用 UTF-8 編碼的方式顯示網頁, 相對地, 網頁本身的內容也要以 UTF-8 編碼的方式儲存. (避免網頁中寫死的文字亂碼.) 
      做法: 利用記事本的另存新檔, 進行網頁檔的編碼確認(如下圖).
      (如果發現是 ANSI 或其他非 UTF-8 編碼的選項, 就在編碼的清單中選 UTF-8, 然後覆蓋此檔案.)
      利用記事本確認網頁檔的編碼
  3. ASP 程式碼的部分: 分為輸出至網頁和寫入資料庫兩部分
    1. 輸出至網頁的部分:
      目的: 在輸出的部分, 設定 UTF-8 的輸出.
      做法: 在程式碼第一行 (或是輸出前), 加入以下兩行:
      Response.CodePage = 65001 
      Response.CharSet = "utf-8"
      (寫入資料庫前也要有上述這兩行.)
      參考資料: http://msdn.microsoft.com/en-us/library/ms524628.aspx
    2. 寫入資料庫的部分:
      目的: 寫入 UTF-8 編碼的資料進資料庫.
      做法: 利用 ADO 的 Command 進行寫入的作業, 不要用兜字串的方式組合 SQL 句, 進行資料庫的寫入.
      一來可避免 SQL Injection 的攻擊, 二來能寫入 UTF-8 的資料.
      以下的 Code 是用來寫入一筆資料到使用者表格 (tblUser):
      網頁檔 (addUser.htm):
      <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>新增使用者</title>
      </head>
      <body>
        <div style="text-align:center">
        <form action="addUser.asp" method="POST">
          帳號:<input name="txtUserAccount" /><br />
          姓名:<input name="txtUserName" /><br />
          職稱:<input name="txtUserTitle" /><br />
          <input type="submit" value="送出" />
        </form>
        </div>
      </body>
      </html>
      程式檔 (addUser.asp):
      <%
      dim conn,rs,cmd
      set conn=Server.CreateObject("ADODB.Connection")
      set rs=Server.CreateObject("ADODB.Recordset")
      set cmd=Server.CreateObject("ADODB.Command")
      conn.Open "driver={SQL Server};database=Test;server=.;uid=sa;pwd=12345678"
      '設定編碼
      Response.CodePage = 65001 
      Response.CharSet = "utf-8" 
      With cmd
        .ActiveConnection = conn
        .CommandType = 1
        .NamedParameters = true
        .CommandText = "INSERT INTO tblUser(UserAccount,UserName,UserTitle) VALUES (?,?,?);"
        .Parameters.item(0)= .CreateParameter("UserAccount",200,1,,Trim("" & request("txtUserAccount")))
        .Parameters.item(1)= .CreateParameter("UserName",200,1,,Trim("" & request("txtUserName")))
        .Parameters.item(2)= .CreateParameter("UserTitle",200,1,2,Trim("" & request("txtUserTitle")))
        .Execute
      End With
      conn.Close
      %>
      參考資料: http://www.w3schools.com/ado/ado_ref_command.asp
另外, 如果有透過 JavaScript 傳送中文的 QueryString 參數, 需使用 encodeURIComponent() 將中文字編碼.
例如以下的程式:
strURL ="queryUser.asp?name=" 
  + encodeURIComponent(document.form1.txtUserName.value);
參考資料: http://www.w3schools.com/jsref/jsref_encodeURIComponent.asp
補充兩種 ADO 的查詢方式: 2009/4/24
  1. 使用 ADODB.Command 的 Execute: http://www.w3schools.com/ado/met_comm_execute.asp
    注意: 用此方式所產生的 ADODB.Recordset, RecordCount 屬性值會是 –1.
    <%
    dim conn,rs,cmd
    set conn=Server.CreateObject("ADODB.Connection")
    set rs=Server.CreateObject("ADODB.Recordset")
    set cmd=Server.CreateObject("ADODB.Command")
    conn.Open "driver={SQL Server};database=Test;server=.;uid=sa;pwd=12345678"
    '設定編碼
    Response.CodePage = 65001 
    Response.CharSet = "utf-8" 
    With cmd
      .ActiveConnection = conn
      .CommandType = 1
      .NamedParameters = true
      .CommandText = "SELECT UserAccount,UserName,UserTitle FROM tblUser WHERE UserName Like ?;"
      .Parameters.item(0) = .CreateParameter("UserName",200,1,,"%" & Trim("" & request("txtUserName")) & "%")
      '查詢結果
      Set rs = .Execute
    End With
    %>
  2. 使用 ADODB.Recordset 的 Open: http://www.w3schools.com/ado/met_rs_open.asp
    注意: 可正確取得RecordCount屬性值, 若要做分頁或計算取到的資料數, 要用此方式.
    <%
    dim conn,rs,cmd
    set conn=Server.CreateObject("ADODB.Connection")
    set rs=Server.CreateObject("ADODB.Recordset")
    set cmd=Server.CreateObject("ADODB.Command")
    conn.Open "driver={SQL Server};database=Test;server=.;uid=sa;pwd=12345678"
    '設定編碼
    Response.CodePage = 65001 
    Response.CharSet = "utf-8" 
    With cmd
      .ActiveConnection = conn
      .CommandType = 1
      .NamedParameters = true
      .CommandText = "SELECT UserAccount,UserName,UserTitle FROM tblUser WHERE UserName Like ?;"
      .Parameters.item(0) = .CreateParameter("UserName",200,1,,"%" & Trim("" & request("txtUserName")) & "%")
      
    End With
    '查詢結果(注意第二個參數放空,不用給conn)
    rs.open cmd,,3,2
    %>

沒有留言: