nikkie-ftnextの日記

イベントレポートや読書メモを発信

好きな映画の鑑賞ログをGitHubのContributionのような形式で表示する(後編:CORSエラーに対処)

はじめに

いま、幸せ? nikkieです。

GitHubのContributionのように、アイの歌声を聴かせての鑑賞ログを表示してみるの後編です。
前回はCal-heatmapというライブラリを選び、JavaScriptのオブジェクトとしてデータを渡し、それが表示されることを確認しました。

オブジェクトの代わりに、JSONファイル名(相対パス)を渡したところ、開発者ツールのコンソールに「Reason: CORS request not HTTP」と表示され、カレンダーは色づかなくなってしまいました。
こちらを解決する中で知ったことを記事にまとめます。

目次

結論:Pythonでローカルサーバを立てる

MDNのドキュメントで案内されている方法です(後述します)。

カレントディレクトリの状態

.
├── commits_ainouta.json  # 鑑賞回数データ(キー:タイムスタンプ、値:鑑賞回数)
└── show_commits.html  # 鑑賞回数を表示するように実装
$ python3 -m http.server 8000

ブラウザで http://localhost:8000/show_commits.html を開きます。

「Reason: CORS request not HTTP」とは?

開発者ツールのコンソールから、MDNの以下のドキュメントに案内されました(このドキュメントは日本語訳が古いようでした)。

file:///スキームを使って、URLでローカルファイルを指定したときに発生する1と書かれています。
たしかに、HTMLをブラウザで開いているので、URLはfile:///で始まっています。

このエラーが起こるようになった経緯についても書かれていました2

  • 同じディレクトリやサブディレクトリのローカルファイルは、歴史的にはsame originとして扱われて(☆)、CORSエラーにはならなかった
  • 2019年 CVE-2019-11730 にて、(☆)の挙動に脆弱性があることが判明
  • ブラウザは今ではすべてのローカルファイルをデフォルトでopaque originとして扱い、結果としてCORSエラーが起こる

Cal-heatmapが2019年時点でメンテされていたかは不明ですが、ブラウザの脆弱性が修正されたために、Cal-heatmapのドキュメントの通りに実装しても動かなかったと理解しました。

案内された解決法:ローカルサーバ

上記のドキュメントの中で解決方法も案内されています。

その方法はPythonをインストールして、http.serverモジュールを使ってローカルサーバを動かすというものです3

警告 http.server is not recommended for production. It only implements basic security checks.

インタプリタの -m スイッチで http.server モジュールと ポート番号 を指定して直接実行することもできます。(略)ここで立ち上がったサーバは現在のディレクトリ以下のファイルへのアクセスを提供します。(太字は引用者による)

http://localhost:8000/commits_ainouta.json をブラウザで表示すると、データが返されることが確認できます。
file:///に代えてhttp://を使い、ローカルサーバによってファイルのデータが返るので、解決するわけですね!

以降は「結論」と合流します。

f:id:nikkie-ftnext:20220110235423p:plain

ソースコード

HTMLのJavaScriptの最終形を示しておきます。

    <script type="text/javascript">
      const cal = new CalHeatMap();
      const config = {
        domain: "month",
        subDomain: "day",
        range: 4,
        tooltip: true,
        start: new Date(2021, 9), // start October, 1st 2021
        data: "commits_ainouta.json",
        legend: [0.0, 0.5, 1.0, 1.5],
        cellSize: 15,
        subDomainTextFormat: "%d",
      };
      cal.init(config);
    </script>

GitHubのContributionのように、アイの歌声を聴かせての鑑賞ログを表示するソースコードの全容は以下にあります:

動かし方はREADMEをどうぞ!
質問あれば @ftnext まで

終わりに

『アイの歌声を聴かせて』を何回も観ていることから思い付いて、GitHubのContributionのように表示してみました。
手を動かす中で、「CORSエラー」の対処など、いくつも学びがありました。

作品自体が「本当にいいぞ」ですし、素振りの材料にもなり、技術的な学びにもつながるという、これはもう、最高の作品ですね!
エンジニア的にも幸せになっちゃいます。

また、次回の「アイの歌声を聴かせて × エンジニアリング」ネタでお会いしましょう。


  1. This often occurs if the URL specifies a local file, using the file:/// scheme.

  2. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp#loading_a_local_file

  3. MDNのドキュメントではPythonでしたが、PHPやNode.jsなど他の言語でもローカルでサーバが立てられると思うので、Pythonが必須というわけではないという理解です。