この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
webpackの仕様を理解しないとたまにトラブルが起きるという話
GMOペイメントゲートウェイのトークン決済とは
ECサイトで決済処理を実装するときにGMOペイメントゲートウェイを活用する事になりました。
多様な決済方式に対応していて便利ですね。
GMOペイメントゲートウェイにはトークン決済という方式があります。
クレジットカード情報をJavaScript上でAPIに送信し、トークン化する事でセキュリティ的な観点で安心して決済処理を行う事ができる、というものですね。
実装
トークン化はコントローラを介さずJavaScriptで行います。
必要なライブラリはCDNで配布されています。
本番用と開発用があるのでお間違えの無いように
<!-- トークン決済開発用javascriptを読み込み -->
<%= javascript_include_tag 'https://stg.static.mul-pay.jp/ext/js/token.js' %>
※URLが変更されている場合があるので必ず最新のドキュメントを参照してください
Multipayment
が定義されるのでカード情報をsubmitする際に利用します。
Multipayment.getToken({
パラメータ
}, 任意のコールバック関数);
の形式です
公式ドキュメントのコードサンプルは以下の通り
最低限の機能なので、カード情報の入力に不足がある場合はアラートを表示して送信しない等の処理を挟むのをオススメします。
<script type="text/javascript">
function execPurchase(response) {
if (response.resultCode != "000") {
window.alert("購入処理中にエラーが発生しました");
} else {
// カード情報は念のため値を除去
document.getElementById("cardno").value = "";
document.getElementById("expire_year").value = "";
document.getElementById("expire_month").value = "";
document.getElementById("securitycode").value = "";
document.getElementById("tokennumber").value = "";
// 予め購入フォームに用意した token フィールドに、値を設定
//発行されたトークンは、有効期限が経過するか、一度 API で利用されると、無効となります。
//複数のAPIでトークンを利用される場合は、tokenNumberにてトークンを複数発行してください。
document.getElementById("token").value = response.tokenObject.token;
// スクリプトからフォームを submit
document.getElementById("purchaseForm").submit();
}
}
function doPurchase() {
var cardno, expire, securitycode, holdername;
var cardno = document.getElementById("cardno").value;
var expire =
document.getElementById("expire_year").value + document.getElementById("expire_month").value;
var securitycode = document.getElementById("securitycode").value;
var holdername = document.getElementById("holdername").value;
var tokennumber = document.getElementById("tokennumber").value;
Multipayment.init("tshop00000001");
Multipayment.getToken({
cardno : cardno,
expire : expire,
securitycode : securitycode,
holdername : holdername,
tokennumber : tokennumber
}, execPurchase);
}
</script>
問題点
このサンプルでいうexecPurchase
にあたるコールバック処理は、
グローバルスコープに無いとCDNから取得したライブラリ側で認識されないのですが、
webpackがスコープを管理する都合でサンプルをこのまま記述してもexecPurchase
はundefinedになってしまいました。
解決策
window.execPurchase = execPurchase;
上記をスクリプトに追記し作成したコールバック関数をwindowオブジェクトに持たせることで解決しました。
package.jsonに設定を記載する等の手段がありそうでしたが上手くいかなかったのでこの手法に落ち着きました。
更なるトラブル
Uncaught ReferenceError: r is not defined
おっ解決したと思いきやデプロイしたら動かん…
何故ならwebpackはproduction環境では変数名等を変換して難読化させた状態でビルドするからです。
window.execPurchase = r;
Multipayment.getToken({
cardno : cardno,
expire : expire,
securitycode : securitycode,
holdername : holdername,
tokennumber : tokennumber
}, r);
上記のようにコールバック関数がr一文字に変換されていましたwindow.execPurchase = execPurchase;
で宣言してもこれでは動かない…
今回の場合、幸いなことにコールバック関数は文字列を渡しても問題なく処理してくれるので
Multipayment.getToken({
cardno : cardno,
expire : expire,
securitycode : securitycode,
holdername : holdername,
tokennumber : tokennumber
}, "execPurchase");
のようにコールバック処理を指定する引数を文字列にすることで解決できました。
変数名は勝手に変換されますが文字列はそのまま残ります。
普段意識しないですがwebpackはこういう変換処理をしてくれているんですね。
トラブルが起きない分には素晴らしいですがたまにこういう事が起きるという話でした。