【javascript】文字列変数に改行をいれるとイカれる
javascriptの文字列変数にソースコード上でそれとわかるような形で改行いれるとページ全体がなんかおかしなことになる。
少なくとも、その変数使ってるjavascriptは動かなくなるようだ。
まあ普通に考えるとそういうもんだろう。
個人的な感覚でいうと、変数に固定の文字列埋め込むケースではコーディングミス(誤記、というか)以外に考えられらない。
だから普通発生しないはずである。
ただ実際に発生して困ったので備忘録として残す。
HTMLの具体的な実例で見てみると。
(1)固定値埋め込み:改行なし
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Script-Type" content="text/javascript"><script type="text/javascript"> <span style="color: green;"><!-- <span style="color: red; font-weight: bold;">var strVal = "あいうえお";</span> function alertOn() { alert(strVal); } // --></span> </script> <title>Test Js Alert(No Line)</title> </head> <body> <h1>■改行なしの文字列を表示します。</h1><br/> <br/> <input type="button" value="ここをクリックするとjs変数を表示します。" onClick="alertOn()"> </body>
</html>
(2)固定値埋め込み:改行あり
<!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"> <meta http-equiv="Content-Script-Type" content="text/javascript"><script type="text/javascript"> <span style="color: green;"><!-- <span style="color: red; font-weight: bold;">var strVal = "
あいうえお";
function alertOn() { alert(strVal); } // --></span> </script> <title>Test Js Alert(No Line)</title> </head> <body> <h1>■改行ありの文字列を表示します。</h1><br/> <br/> <input type="button" value="ここをクリックするとjs変数を表示します。" onClick="alertOn()"> </body>
</html>
(3)自ページ内のテキストエリアから設定
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Script-Type" content="text/javascript"><script type="text/javascript"> <span style="color: green;"><!-- function alertOn() { var strVal = document.getElementById("TEXTAREA_FREE").value; alert(strVal); } // --></span> </script> <title>Test Js Alert(Free Input)</title> </head> <body> <h1>■自由入力の値を表示します。</h1><br/> <br/> ここ↓に入力した値を表示します。<br/> <textarea width="300" height="200" id="TEXTAREA_FREE"></textarea> <br/> <input type="button" value="ここをクリックするとjs変数を表示します。" onClick="alertOn()"> </body>
</html>
それぞれボタンをクリックすると変数値をalertで表示するだけのシンプルなHTMLである。
(1)は言わずもがな、全然問題ない。(普通に"あいうえお"が表示される)
(3)は表示する値をTEXTAREAから取得するため、TEXTAREAへの入力内容次第では当然改行が入ることもあるが、
仮に改行をいれて入力していても問題なくalertで表示できる。(改行もちゃんと表現された状態でalertされる、いわゆる"あいうえお\nかきくけこ"とかと同じ扱いになる)
ただし、(2)はボタンを押しても反応がない。
Internet Explorerの開発ツールによれば、ボタンクリック時に起動しているjavascriptの関数「alertOn()」が未定義で呼び出せない。
関数定義のブロックと変数に値を埋め込んでいる箇所はコード上で異なるが、
意図的に改行をいれてしまったことでjavascript全体がイカれてしまっている。
冒頭で言った”変数に固定の文字列埋め込むケースではコーディングミス(誤記、というか)以外に考えられらない。”というのは
上に挙げた例でいうところの(2)にあたるケースで、
要するにこういう書き方↓は普通は(=意図的には)しないよねという意味である
<script type="text/javascript">
<--
var STR_VAL = "あいうえお ←わざわざここで改行なんかしないだろjk…という意味
かきくけこ";
// -->
</script>
↑までの話ならただのコーディングミスで話が付くのだが、
実際に遭遇した時はjspで変数設定している箇所に原因があった。
簡単な実例として、
「HTMLのTEXTAREAに入力された値をPOSTして、JSPにFORWARDした後、受け取った値をjavascriptでalert表示させる」
ようなものを考える。
(4)入力元HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Test Textarea</title><meta HTTP-EQUIV='Cache-Control' CONTENT='no-cache'> <meta HTTP-EQUIV='Pragma' CONTENT='no-cache'> <meta HTTP-EQUIV='Expires' CONTENT='-1'>
</head>
<body>
<h1>■最初の画面です。</h1><br/>
<br/>
<form action="/linecodetest/TestServlet" method=“post”>
ここになんか入力↓<br/>
<textarea width=“300” height=“30” name=“textarea_test” id=“textarea_test”>
</textarea>
<br/>
<input type=“submit” value=“GO! Submit!!">
</form>
</body>
(5)間にいるServlet
import javax.servlet.*; import javax.servlet.http.*; import java.util.*; import java.io.*; import java.text.*; import java.net.*; import javax.mail.internet.*;public class TestServlet extends HttpServlet {
private static final DateFormat LOG_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); private static final String ENCODING_UTF8 = "UTF-8"; private static final String STR_PARAM_TEXTAREA_TEST = "textarea_test"; private static final String STR_URL = "/jsp/forward.jsp"; public void doGet(HttpServletRequest req , HttpServletResponse res) throws ServletException,IOException { this.doProcess(req,res); } public void doPost(HttpServletRequest req , HttpServletResponse res) throws ServletException,IOException { this.doProcess(req,res); } private void doProcess(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { try { String strVal = request.getParameter(STR_PARAM_TEXTAREA_TEST); if (strVal == null) { throw new ServletException(STR_PARAM_TEXTAREA_TEST + " is null"); } printLog("**** Debug Print -START- ****"); printLog(STR_PARAM_TEXTAREA_TEST + " = " + strVal); printLog("**** Debug Print -E N D- ****"); HttpSession hs = request.getSession(); hs.setAttribute(STR_PARAM_TEXTAREA_TEST,strVal); RequestDispatcher rd = request.getRequestDispatcher(STR_URL); rd.forward(request,response); } catch(ServletException e) { throw e; }
}
private static void printLog(Object msg) { StringBuilder sb = new StringBuilder(); sb.append(LOG_FORMAT.format(new Date())); sb.append(" "); if (msg != null) { sb.append(msg.toString()); } System.out.println(sb.toString()); }
}
(6)forward先JSP
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Test forward</title><meta HTTP-EQUIV='Cache-Control' CONTENT='no-cache'> <meta HTTP-EQUIV='Pragma' CONTENT='no-cache'> <meta HTTP-EQUIV='Expires' CONTENT='-1'> <script type="text/javascript"> <!-- var REQ_VAL = '<%= session.getAttribute("textarea_test") %>'; function alertOn() { alert("前画面からもらった値は\n" + REQ_VAL); } // --> </script>
</head>
<body>
<h1>■forward先画面です。</h1><br/>
<br/>
<input type=“button” value=“ここを押すと前画面でもらった値を表示します。” onClick=“alertOn();">
</body>
(6)はボタンクリックでjavascriptの変数「REQ_VAL」をalertに表示させるが、
この値はHttpSession#getAttributeで受け取った後にHTMLのソースコードとして展開されるため、
HttpSession#getAttributeの値次第ではここで改行が起き、変数の設定箇所が2行に渡るコードになり、(2)と同じ状態になる。
結果的にjavascriptが動作しない…という現象が起きる。
ことこのケースでいえば、
HttpSession#getAttributeで取得できる値を”入力する(設定する)側”は(4)で、それを表示するのが(6)という構成なので、
つまり自分で入力して自分でコードをブッ壊しているという間抜けな状況だが
この項目の取得元が「外部システムに依存していてデータの仕様がよくわからない」というようなケースでは結構こういうことも起き得るだろう。
(そもそもデータの仕様を確認せぬまま実装してはいけないけど…)
まあこういう危険性をはらんでる時点で、改行含むかどうかに関わらずこういうコーディングをしてはいけないのだろう。