読者です 読者をやめる 読者になる 読者になる

Corredor

ウェブ、プログラミングの勉強メモ。

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

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

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

  • 画像ファイルをアップする時は POST 送信する必要がある (GET 送信は不可)。
  • jQuery で Ajax 送信する際、FormData を使う場合は contentType 指定ができない (jQuery が勝手にやる)。
  • processData 指定による変換を行おうとしたが、これは GET 通信のときしか設定できない。

サーバ側は 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 側で送信する文字列を encodeURIComponent() を使って UTF8 ベースにエンコードしておき、
  • Java 側で受け取った文字列を URLDecoder.decode() を使ってデコードする

という方法を取った。

/* 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 処理を追加しないといけないページやフォーム要素が少なかったので、こうしたエンコード・デコードを手動で愚直にやることで逃げられた。

その他参考。