はじめに
こんにちは、Gakken Leap のフロントエンドエンジニアの日下です。
今回は過去に経験した興味深い技術的問題について書きます。
クーポンコード 72E875 が Infinity に変換されてしまうというものです。この記事では、この問題の原因と、JavaScript の数値解釈の特性について共有します。
問題の概要
私が当時担当していた通販サイトでは、Cookie に保存されたランダムな文字列から生成されたクーポンコードに基づいて割引を適用する機能がありました。
その機能は問題なく動作していたのですが、ある日決済時クーポンが適用されないという事象が発生しました。
Sentry のログを確認すると coupon=Infinity と記載されていました。
当初悪意のあるユーザーが Infinity という文字列を試しに入れたのかと思っていたのですが、発生件数が日毎に増えていくため本格的に調査を行いました。
調査を進めていく中でクーポンコード 72E875 の場合、決済時クーポンが適用されていないことが判明しました。
原因の解明
この問題の根本的な原因は、JavaScript の数値解釈にあります。
JavaScript では、E または e を含む数値文字列は、科学的記数法(指数表記)として解釈されます。
具体的には:
72E875 は JavaScript によって 72 * 10^875 と解釈されます。
この数値は、JavaScript が扱える Number 型の範囲(約 ±1.8 * 10^308)を遥かに超えています。
結果として、この値は Infinity(無限大)に変換されてしまいます。
Infinity というクーポンはないため、クーポンが適用されていなかったというわけです。
以下のように
setCookie("coupon_code", "72E875");
const coupon = useCookie("coupon_code").value.toString();
と書いても String に変換する前にすでに暗黙的型変換により数値として解釈され、結果として Infinity に変換されているため、coupon は "Infinity" です。
対策と教訓
対策として暗黙的型変換時に文字列として解釈されるように Cookie 保存時クーポンに文字列のプレフィクスをつける対応を行いました。
Cookie から取り出すさいにプレフィクスを取り除き文字列を置換します。
setCookie("coupon_code", "MyCoupon72E875");
const coupon = useCookie("coupon_code").value.replace("myCoupon", "");
このようにすることで上記の問題を防ぐことができます。
まとめ
JavaScript の動的な型変換は便利な特性である一方で、予期せぬ挙動を引き起こす可能性もあります。
今回のケースでは、クーポンコードが科学的記数法として解釈され、結果として Infinity に変換されるという問題が発生しました。
この問題を解決するために、クーポンコードに文字列のプレフィクスを追加するという対策を採用しました。
これにより、クーポンコードが数値として解釈されることを防ぎ、期待通りの動作を保証しました。
この経験から、JavaScript の型変換の特性を理解し、それがコードの挙動にどのように影響するかを常に意識することの重要性を学びました。
エンジニア募集中
Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています!!
ぜひお気軽にカジュアル面談へお越しください!!