你寫了一個JSP網頁,使用Big5編碼:
其中${name}會是資料庫中撈取出來的名稱,放在請求範圍屬性中再轉發至這個JSP頁面,如果實際上資料庫中的名稱是「王大犇」,在伺服端的JVM中撈取出來的名稱也確認是正確的顯示,但再經由這個JSP網頁,卻會是亂碼:
這是自然地,因為你的網頁採Big5編碼,對瀏覽器而言,看到的HTML是:
在 Big 5 網頁難字 中介紹過,你可以將特殊字元用實體編號表示,所以你可以在伺服端JVM中使用StringEscapeUtils.escapeHtml()之類的程式庫,將「王大犇」處理為「王大犇」:
如此看到的就會是正確的字元:
這是因為瀏覽器看到:
再將「王大犇」轉為實際的「王大犇」。然而,如果你這麼撰寫:
如果${name}是將「王大犇」處理為「王大犇」的結果,那你會看到:
這個問題在 JavaScript 編碼基礎 中略談過,瀏覽器對於收到的HTML會進行剖析,這是實體編號被剖析為對應字元的時間點,這也是為什麼:
最後會看到「王大犇」,瀏覽器完成HTML剖析後,會 建立JavaScript環境中對應的DOM物件,如果你直接將字串指定給DOM的特性,那就會以實際的字串值設定給DOM特性,而不會再經由剖析,不過 JavaScript 編碼基礎 提過,innerHTML特性是個例外,指定給innerHTML的字串,會嘗試再進行HTML剖析,所以如果你這麼撰寫:
那你就會看到正確的「王大犇」。
你會想,誰會那麼無聊,使用JSP將字串產生為JavaScript,再用JavaScript指定給輸入欄位呢?有的時候,尤其是維護舊系統為主的公司,有些部份是你可以修改的,但有些剖份是你不能修改的(例如也許是另一個部份負責的子系統),就會遇到類似的情況。
例如,也許另一個子系統傳回的字串一徑作實體編號, 你的JSP中,使用Ajax進行查詢, 像是某個查詢人名,另一個子系統直接將查得的人名作實體編號傳回以下結果:
如果你這麼撰寫:
request.onreadystatechange = function() {
if(request.readyState === 4) {
if(request.status === 200) {
document.getElementById('name').value = request.responseText;
}
}
};
那文字欄位就會出現「王大犇」,但如果你這麼撰寫:
那就可以得到正確的顯示結果。事實上,這些作法,只不過是 Servlet 中文處理(Tomcat) 、 Big 5 網頁難字 、 JSP 的轉譯 、 JavaScript 編碼基礎 等基礎觀念的綜合應用,許多程式設計人員在這些基礎不足下,自然就無法變化應用。
再看一個學員來信的例子:
如果有個輸入欄位:
如果資料庫中的資料有雙引號,例如123"456結果就會是:
這個HTML當然有問題,也許你會想,那就這樣:
如果資料庫中的資料有雙引號,例如123"456結果就會是:
但現在的情況中,資料庫中的資料是雙引號或單引號都有,如果資料實際上是123'456,你怎麼辦?
簡單的解決方式之一可以用JSTL,例如:
<c:out>預設escapeXML是true,所以可解決問題,但這位學員又有問題了:
我不太知道他要用<c:out>產生值給 JavaScript 的原因,但要同時滿足兩個需求也非不行:
使用hidden欄位也可以,或者你也可以像先前用動態產生DOM元素的方式,這都是先前例子的再變化應用。
<%@ page contentType="text/html; charset=Big5" pageEncoding="Big5"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Big5"> <title>JSP 網頁</title> </head> <body> 名稱:<input type="text" name="name" value="${name}"> </body> </html>
其中${name}會是資料庫中撈取出來的名稱,放在請求範圍屬性中再轉發至這個JSP頁面,如果實際上資料庫中的名稱是「王大犇」,在伺服端的JVM中撈取出來的名稱也確認是正確的顯示,但再經由這個JSP網頁,卻會是亂碼:
這是自然地,因為你的網頁採Big5編碼,對瀏覽器而言,看到的HTML是:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Big5">
<title>JSP 網頁</title>
</head>
<body>
名稱:<input type="text" name="name" value="王大?">
</body>
</html>
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Big5">
<title>JSP 網頁</title>
</head>
<body>
名稱:<input type="text" name="name" value="王大?">
</body>
</html>
在 Big 5 網頁難字 中介紹過,你可以將特殊字元用實體編號表示,所以你可以在伺服端JVM中使用StringEscapeUtils.escapeHtml()之類的程式庫,將「王大犇」處理為「王大犇」:
request.setAttribute("name", StringEscapeUtils.escapeHtml("王大犇"));
如此看到的就會是正確的字元:
這是因為瀏覽器看到:
名稱:<input type="text" name="name" value="王大犇">
再將「王大犇」轉為實際的「王大犇」。然而,如果你這麼撰寫:
<%@ page contentType="text/html; charset=Big5" pageEncoding="Big5"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <script type="text/javascript"> window.onload = function() { document.getElementById('name').value = '${name}'; }; </script> <meta http-equiv="Content-Type" content="text/html; charset=Big5"> <title>JSP 網頁</title> </head> <body> 名稱:<input id="name" type="text" name="name"> </body> </html>
如果${name}是將「王大犇」處理為「王大犇」的結果,那你會看到:
這個問題在 JavaScript 編碼基礎 中略談過,瀏覽器對於收到的HTML會進行剖析,這是實體編號被剖析為對應字元的時間點,這也是為什麼:
名稱:<input type="text" name="name" value="王大犇">
最後會看到「王大犇」,瀏覽器完成HTML剖析後,會 建立JavaScript環境中對應的DOM物件,如果你直接將字串指定給DOM的特性,那就會以實際的字串值設定給DOM特性,而不會再經由剖析,不過 JavaScript 編碼基礎 提過,innerHTML特性是個例外,指定給innerHTML的字串,會嘗試再進行HTML剖析,所以如果你這麼撰寫:
<%@ page contentType="text/html; charset=Big5" pageEncoding="Big5"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <script type="text/javascript"> window.onload = function() { var span = document.createElement('span'); span.innerHTML = '${name}'; document.getElementById('name').value = span.innerHTML; }; </script> <meta http-equiv="Content-Type" content="text/html; charset=Big5"> <title>JSP 網頁</title> </head> <body> 名稱:<input id="name" type="text" name="name"> </body> </html>
那你就會看到正確的「王大犇」。
你會想,誰會那麼無聊,使用JSP將字串產生為JavaScript,再用JavaScript指定給輸入欄位呢?有的時候,尤其是維護舊系統為主的公司,有些部份是你可以修改的,但有些剖份是你不能修改的(例如也許是另一個部份負責的子系統),就會遇到類似的情況。
例如,也許另一個子系統傳回的字串一徑作實體編號, 你的JSP中,使用Ajax進行查詢, 像是某個查詢人名,另一個子系統直接將查得的人名作實體編號傳回以下結果:
王大犇
如果你這麼撰寫:
request.onreadystatechange = function() {
if(request.readyState === 4) {
if(request.status === 200) {
document.getElementById('name').value = request.responseText;
}
}
};
那文字欄位就會出現「王大犇」,但如果你這麼撰寫:
<%@ page contentType="text/html; charset=Big5" pageEncoding="Big5"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <script type="text/javascript"> window.onload = function() { var xhr = window.XMLHttpRequest && (window.location.protocol !== 'file:' || !window.ActiveXObject) ? function() { return new XMLHttpRequest(); } : function() { try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) { throw new Error('XMLHttpRequest not supported'); } }; var request = xhr(); request.onreadystatechange = function() { if(request.readyState === 4) { if(request.status === 200) { var span = document.createElement('span');
span.innerHTML = request.responseText;
document.getElementById('name').value = span.innerHTML; } } }; request.open('GET', 'response'); request.send(null); }; </script> <meta http-equiv="Content-Type" content="text/html; charset=Big5"> <title>JSP 網頁</title> </head> <body> 名稱:<input id="name" type="text" name="name"><br> </body> </html>
那就可以得到正確的顯示結果。事實上,這些作法,只不過是 Servlet 中文處理(Tomcat) 、 Big 5 網頁難字 、 JSP 的轉譯 、 JavaScript 編碼基礎 等基礎觀念的綜合應用,許多程式設計人員在這些基礎不足下,自然就無法變化應用。
再看一個學員來信的例子:
問:若db的資料內容若有單引號或雙引號, 撈出來會造成html顯示不正常,怎麼解決呢?
如果有個輸入欄位:
<input type="text" value="${data}">
如果資料庫中的資料有雙引號,例如123"456結果就會是:
<input type="text" value="123"456">
這個HTML當然有問題,也許你會想,那就這樣:
<input type="text" value='${data}'>
如果資料庫中的資料有雙引號,例如123"456結果就會是:
<input type="text" value='123"456'>
但現在的情況中,資料庫中的資料是雙引號或單引號都有,如果資料實際上是123'456,你怎麼辦?
簡單的解決方式之一可以用JSTL,例如:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Hello World!</h1>
<%
String text1 = "test'test";
String text2 = "test\"test";
%>
<input type="text" value="<c:out value="<%= text1 %>"/>"><br>
<input type="text" value="<c:out value="<%= text2 %>"/>">
</body>
</html>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Hello World!</h1>
<%
String text1 = "test'test";
String text2 = "test\"test";
%>
<input type="text" value="<c:out value="<%= text1 %>"/>"><br>
<input type="text" value="<c:out value="<%= text2 %>"/>">
</body>
</html>
<c:out>預設escapeXML是true,所以可解決問題,但這位學員又有問題了:
問:不過還真的有一好沒兩好,當我們想要 document.getElementById('xxx').value 給值的時候,卻會老老實實的顯示html內碼
ex.會顯示 123'456 或 123"456
ex.會顯示 123'456 或 123"456
我不太知道他要用<c:out>產生值給 JavaScript 的原因,但要同時滿足兩個需求也非不行:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%
String text1 = "test'test";
String text2 = "test\"test";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
<script type="text/javascript">
window.onload = function() {
document.getElementById('i3').value =
document.getElementById('i1').value;
document.getElementById('i4').value =
document.getElementById('i2').value;
};
</script>
</head>
<body>
<h1>Hello World!</h1>
<input id="i1" type="hidden" value="<c:out value="<%= text1 %>"/>"><br>
<input id="i2" type="hidden" value="<c:out value="<%= text2 %>"/>"><br>
<input id="i3" type="text"><br>
<input id="i4" type="text">
</body>
</html>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%
String text1 = "test'test";
String text2 = "test\"test";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
<script type="text/javascript">
window.onload = function() {
document.getElementById('i3').value =
document.getElementById('i1').value;
document.getElementById('i4').value =
document.getElementById('i2').value;
};
</script>
</head>
<body>
<h1>Hello World!</h1>
<input id="i1" type="hidden" value="<c:out value="<%= text1 %>"/>"><br>
<input id="i2" type="hidden" value="<c:out value="<%= text2 %>"/>"><br>
<input id="i3" type="text"><br>
<input id="i4" type="text">
</body>
</html>
使用hidden欄位也可以,或者你也可以像先前用動態產生DOM元素的方式,這都是先前例子的再變化應用。