2017年8月21日月曜日

Firebaseで公開したウェブサイトが文字化けしたときの対処

googleのFirebaseはMBaasと呼ばれるクラウドサービスの1つですが、静的なウェブサイトのホスティングサービスとしても使えます。 昨日、そのFirebaseでウェブサイトを公開しました。 内容は以前プロバイダのホームページサービスで公開していたものの一部です。 昨年の引越しでプロバイダを使わなくなったからホームページサービスも使えなくなったんですよね。 一度移転しかけて、作業中で放置して……それを今になってあらためてFirebaseで公開。

ファイルのアップロードまでは簡単にできました。 でも古いShift_JISで書いたページが文字化けしてます。 htmlファイルの文字コード宣言を確認したら問題はありませんでした。 「何コレ?」って事で少し調べて対処法が分かったのでここにメモを残しておきます。

原因はhttpのレスポンスヘッダを見て分かりました。 Google Chromeで「Ctrl+Shift+I」を押してデベロッパーツールを表示。 Networkタブを選んでから公開したサイトを表示すると、htmlファイルのResponse Headerに「content-type: text/html; charset=utf-8」の文字があります。 どうやらFirebaseで公開したhtmlファイルは、そのままだと無条件でUTF-8として扱われるようです。 そして、少なくともWindows10で使える主要なブラウザ(Chrome、Firefox、Edge)は最優先でレスポンスヘッダに書かれた文字コードで表示しようとするようです。 htmlファイルの文字コードや宣言は関係なし。 文字コードの自動判別なんて無かった……。

というわけで対処法はFirebaseの設定を書いて、レスポンスヘッダのcontent-typeでShift_JISが返るようにすること。 古いページをutf-8に変換するってのも正しい対処法ではあるんでしょうけど、ファイルが数十個あるのでやりたくはありません。 新しいページを書くときはいろんなソフトウェアとの相性を考えてutf-8を使う方がいいと言われていますが、今回はFirebaseの方でなんとかしましょう。

やり方は簡単。 firebase.jsonに7行ほど書き加えるだけです。

{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "headers": [ {
      "source" : "/@(saga3|bbb_memo|pe_memo|smbmap)/**/*.html",
      "headers" : [ {
        "key" : "Content-Type",
        "value" : "text/html; charset=Shift_JIS"
      } ]
    } ]
  }
}

太字で書いたheadersのところがソレ。 headersの前の「,」もお忘れなく。

sourceの部分でレスポンスヘッダを設定する対象を指定します。 Globパターンマッチングで複数のファイルを対象にすることができます。

  • ルート(/)はpublicディレクトリを指すようです。
  • *は複数文字(1文字以上)のワイルドカードです。 *.htmlのように使うと*の部分が色々変化した全てのファイルとマッチします。 *単体で使うとそのディレクトリ内のファイルまたサブディレクトリ全てとマッチします。
  • **はそのディレクトリ自体とそれに含まれるディレクトリ、サブディレクトリ、それらに入っているファイルすべてとマッチします。
  • @(src|img|code)のように@()で囲って単語を並べ|で区切った場合、その単語のどれかとマッチすればokです。
  • ?[]などの他の記号も使えるはずですが、試してません。

今回は特定のディレクトリ内のhtmlファイルのみShift_JISなので複雑になっていますが、全ファイルをShift_JISに指定したい場合は"**/*.html"でokです。

sourceの下にもう1つheadersを書いて、そこで設定したいレスポンスヘッダの項目を書きます。 今回はhtmlファイルの文字コードの指定なので前述のように

  • "key" : "Content-Type"
  • "value" : "text/html; charset=Shift_JIS"

の組を書きました。 もちろんEUC-JPならば「charset=EUC-JP」です。

これで無事Shift_JISのページの文字化けが解消できました。 やれやれ、色々調べてたら2時間かかったぞ。

このやり方が分かればレスポンスヘッダの他の項目も色々設定できますね。 (というか検索しても海外のサイトばかりヒットしたので他の例しか見つかりませんでした。)