ローカルやデモ環境ではちゃんと動いていたJavaScriptが、本番サーバーにアップした途端に無反応になる。私も一度これで半日ハマったことがあります。エラーらしいエラーも出ないのに動かないので、原因の切り分けにやたら時間がかかるんですよね。
このパターン、SSL(HTTPS)を入れたサイトで起きているなら、かなりの確率で「混在コンテンツ(Mixed Content)」が犯人です。今回はその仕組みと、いまのブラウザの挙動を踏まえた直し方をまとめておきます。
原因はほぼ「混在コンテンツ(Mixed Content)」
HTTPSで表示しているページの中で、http://から始まるJavaScriptやCSS、画像を読み込むと、それは混在コンテンツと呼ばれます。ページ本体は暗号化されているのに、一部のリソースだけ暗号化されていない通信で取りに行っている状態ですね。この非暗号の部分は途中で盗み見・改ざんされるおそれがあるため、ブラウザは安全のために手を打ちます。(MDN Web Docs: Mixed content)
ここで大事なのが、リソースの種類によって扱いが違うという点です。
- スクリプト・スタイルシート・iframe・fetch/XHR・Webフォントなど、ページの動きに深く関わるもの(かつてのアクティブ混在コンテンツ)は既定でブロックされます。JavaScriptが「エラーもなく動かない」のはこれが理由です。
- 画像・音声・動画など影響の小さいもの(かつてのパッシブ混在コンテンツ)は、いまのChromeやFirefoxでは自動的にhttpsへアップグレードして読み込もうと試みます。アップグレードに失敗した場合は読み込まれません。
つまり、動かなくなっているスクリプトのURLがこうなっていないか、まず疑ってみてください。
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
http://でjQueryを取りに行っているので、HTTPSページではブロックされ、jQueryに依存したコードが軒並み動かなくなる、というわけです。
まずはコンソールで犯人を特定する
手を動かす前に、ブラウザの開発者ツール(F12)を開いてConsoleタブを見てください。混在コンテンツがあると、Mixed Content: The page at ... was loaded over HTTPS, but requested an insecure ... といった警告が出ています。ここに「どのURLがブロックされたか」がそのまま書いてあるので、直す対象を漏れなく洗い出せます。ブロックされた分は「blocked」、httpsへ自動アップグレードされた分は「upgraded」といった形で区別して表示されるので、いちいち推測しなくて済みます。
解決方法
1. リソースのURLをhttpsに書き換える(基本)
一番素直な直し方です。読み込んでいる外部リソースのURLのhttp://をhttps://にするだけ。いまどきの主要なCDNはHTTPSに対応しているので、これで解決するケースがほとんどです。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
CSSや画像も同じで、外部から読むものは最初からhttpsで書いておくのが安全です。
2. プロトコル相対URLは、いまはもう使わない
昔は//example.com/...のようにプロトコルを省いた「プロトコル相対URL」を使い、閲覧中のプロトコルに自動で合わせる書き方が定番でした。ただ、サイト全体をHTTPSに寄せるのが当たり前になったいまでは、この書き方は非推奨とされています。素直にhttps://と明記したほうが、ローカルでfile://から開いたときの事故も防げますし、意図もはっきりします。
<!-- 昔の書き方(今は避ける) -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
3. 数が多いなら CSP の upgrade-insecure-requests
古いサイトを移行したときなど、http://のURLがページ中に大量に残っていて手作業では追いきれない場合があります。そんなときはCSP(Content Security Policy)のupgrade-insecure-requestsディレクティブが便利です。これを付けると、ページ内のリソース読み込みリクエストをブラウザが自動でhttpsに読み替えてくれます。(MDN Web Docs: upgrade-insecure-requests)
HTTPレスポンスヘッダーで指定するか、
Content-Security-Policy: upgrade-insecure-requests;
ヘッダーをいじれない環境なら、HTMLの<head>内にmetaタグで書く手もあります。
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
ただし、これはあくまで応急処置的な保険です。恒久対応としてはやはり、ソース側のURLをhttpsに直しておくのが本筋になります。
4. 外部に頼らずサーバーに置く手も
外部ライブラリをそれほど使っていないなら、jQueryなどのファイルを自分のサーバーに置いて、そこから読み込む方法もあります。読み込み元が自サイト(HTTPS)に統一されるので、混在コンテンツの心配自体がなくなります。外部CDNの障害に左右されないという副次的なメリットもあります。
確認しておきたいポイント
最後に、SSL対応後にJavaScriptが動かなくなったときの見直しポイントをまとめておきます。
- JavaScript・CSS・画像などの外部リソースはhttpsで読み込む
- プロトコル相対URL(
//始まり)は使わず、https://と明記する - コンソール(F12 → Console)で、どのURLがブロックされているかを確認する
- httpのURLが大量に残っているなら
upgrade-insecure-requestsで一括対応しつつ、順次ソースを直す - 外部ライブラリが少なければ、自サーバーにホストしてしまうのも手
動かない原因が見えないと焦りますが、混在コンテンツはコンソールを見ればほぼ一発で特定できます。まずはF12でConsoleを開いて、httpで読み込んでいるものがないかを確認する。そこから直していくのが結局いちばんの近道です。