Shift-JIS のページから Ajax 送信しようとして文字化けしたときに… クライアントサイド (JavaScript) とサーバサイド (Java) でエンコード・デコード

古いシステムを改修していて、Shift-JIS でエンコーディングされているページから Ajax 送信する必要があり、日本語が文字化けしたので色々やったメモ。

FormData を使って、文字列だけでなく画像ファイルも一緒に送信する必要があったので、色々と制限があった。

サーバ側は Java だったので、SetEncodingFilter を突っ込めばいいか?と思ったのだが、現行の別ページのエンコーディングに影響しては困るので導入できなかった。

ちなみに FormData というのは、送信する <form> 要素を JavaScript 内で独自に構築できるようなオブジェクト。ページ内に存在する form 要素を流用して Ajax 送信するとか、ページ中に form 要素がなくとも、ゼロからフォームを作ってそれを送信したりもできる。

// こんな風に既存の form 要素を流用できる
var fd = new FormData(document.getElementById('my-form'));

// 追加したいデータがあればこうやる
// これでファイルを選択した input[type='file'] からファイルを取得して追加している
fd.append('file', $('#fileUp').prop('files')[0]);

// jQuery を使って Ajax 送信したり…。
$.ajax({
  type     : 'POST',
  url      : 'updateFile.do',
  dataType : 'text',
  data     : fd,
  processData : false,
  contentType : false
}).done(function(data) {
  // 受け取ったデータを処理…
});

そんなワケでどうしたかというと、

という方法を取った。

/* JavaScript にて */

// 送信したい日本語を含む文字列は…
var rawFileName = $('#fileName').val();
// エンコードしておき…
var sendFileName = encodeURIComponent(rawFileName);
// FormData に追加して Ajax 送信する
fd.append('fileName', sendFileName');
/* 送信データを受け取った Java 側では */

// そのままでエンコードされた状態なので…
String fileName = form.getFileName();
// デコードして元に戻す
String decodedFileName = URLDecoder.decode(fileName, "UTF-8");
// decodedFileName が文字化けせずに文字列を受け取れている

幸い、Ajax 処理を追加しないといけないページやフォーム要素が少なかったので、こうしたエンコード・デコードを手動で愚直にやることで逃げられた。

その他参考。