この記事では、実際にRails + Webpayのトークン決済を導入する方法を説明しながら、
裏側で使われている技術とかを紹介しますよ.
トークン決済!?(;゜0゜)
そもそもトークン決済て何。みたいな話はやりはwebpayのドキュメントを見るのが一番分かりやすそう
早速、動くコード(最小の構成)
動くコードを見るのが一番早いと思います.
説明はその後します.
例は短いに超した事がないと思ってるので最小構成で作ってみた.
最小の構成とは
フォームにカード情報を入力してもらい、ItemsController
の buy
アクションを叩く事を想定しましょうか.
このItemsController#buy
の中でフォームから受け取ったカード情報で決済をゴニョゴニョしたい感じです.
- view1つ(test.html.erb)
- controllerのaction1つ(items_controller.rb#buy)
この2つがあればおk
<script type="text/javascript" src="https://js.webpay.jp/v1/"></script>
<script type="text/javascript">
// token生成のAPIを叩いた結果(statusとresponse)を引数として受け取る(コールバック)関数を定義する
var webpayResponseHandler = function(status, response) {
var form = $("#payment-form");
if (response.error) {
// token生成失敗後の処理を書く
} else {
// token生成成功後の処理を書く
// この例では取得したtokenを<input type="hidden">にのせてappendしてる
var token = response.id;
var input = document.createElement("input");
input.type = "hidden";
input.name = "token";
input.value = token;
$(input).appendTo(form);
form.get(0).submit();
}
};
$(document).ready(function() {
// フォームの送信がボタンが押されると..
$("#payment-form").submit(function(event) {
// Webpayで発行した公開鍵を入れましょう(商用、テスト環境はよしなに)
WebPay.setPublishableKey("test_public_19DdUs78k2lV8PO8ZCaYX3JT");
// こいつがAPIを叩きにいってる、上で定義したコールバック関数もご一緒に
WebPay.createToken({
number: $("#card-number input").val(),
name: $("#card-name input").val(),
cvc: $("#card-cvc input").val(),
exp_month: $("#card-expiry-month input").val(),
exp_year: $("#card-expiry-year input").val()
}, webpayResponseHandler);
return false;
});
});
</script>
<%= form_tag buy_items_path, id: "payment-form" do %>
<div id="card-number">カード番号: <%= text_field_tag "card[number]", "4242-4242-4242-4242"%></div>
<div id="card-name"> 名義: <%= text_field_tag "card[name]", "KENGO HAMASAKI" %></div>
<div id="card-cvc">セキュリティコード: <%= text_field_tag "card[cvc]", "123" %></div>
<div id="card-expiry-month">
有効期限(月): <%= text_field_tag "card[exp_month]", "12" %>
</div>
<div id="card-expiry-year">
有効期限(年): <%= text_field_tag "card[exp_year]", "2015" %>
</div>
<%= submit_tag '送信' %>
<% end %>
class ItemsController < ApplicationController
def buy
binding.pry
params[:token]
# [大事]!!!↑ここにトークンが入ってる!!!
end
end
実際に動かしてみた
Gyazo使ってみたかったので使ってみた
(controller名とかはちょっと違うけどあんまり気にしないで)
ファッ!?(;゜0゜)
formにあるはずのない、params[:tokens]が!?
このトークンがカード情報(番号、CSV、有効期限、氏名)と等価に扱えるので、
僕たちはカード番号やCVCなどの取り扱いの面倒な情報を持たなくておk
トークン決済スゲー
以下説明
1.カード情報が入力されたformのsubmitボタンが押される
2.$("#payment-form").submit()が発火
このイベント発火後の処理の中で、
WebPayオブジェクト(https://js.webpay.jp/v1/ 内で定義されてる)に必要な情報を渡しAPIを叩く
3.webpayResponseHandlerがAPIの結果を受け取り処理
これは同一生成元ポリシーの元で許されていないクロスドメインリクエストですが、以下に説明するとJSONPというハックを使って実現している.
クライアントとクロスドメイン先のサーバーであらかじめ取り決めたコールバック関数を叩くというものだ.
今回はwebpayResponseHandlerが引数にHTTP(S)のステータスコードとレスポンスを取る。
今回の例では受け取ったtokenをhiddenタグとしてform内に仕込みsubmitし直している。
=====ここまで読めば動くものは作れる======
JSONP
JSONPを知らない方は、まあググって適当に調べてもらうと良い.
今回は、https://js.webpay.jp/v1/ 内で上記の機構をどう実現してるか書きますよ.
以下疲れたのでちょっと手抜き
Webpay.createTokenで必要な情報を受け取った後、
callbackId = "jsonp_" + new Date * 1;
の様にユニークなcallbackIdを作ります。
window[callbackId] = function (data, status) {
window.clearTimeout(timeoutId);
return webpayResponseHandler(status, data)
};
windowオブジェクトに対してこれをキーにコールバック関数をセットします。
script = document.createElement("script");
script.src = this.endpoint + option.path + "?" + toParam(option.data) + "&callback=" + callbackId;
document.getElementsByTagName("body")[0].appendChild(script)
srcの部分に叩きたいAPIのendpointとParamsをつめhtml内にappendします.
appendされたscriptタグが評価されるとAPIを叩きにいきます.
jsonp_1398067755529({"id":"tok_5Cb4bo3LidO6dDn","object":"token","livemode":false,"created":1398067774,"used":false,"card":{"object":"card","exp_year":2015,"exp_month":12,"fingerprint":"215b5b2fe460809b8bb90bae6eeac0e0e0987bd7","name":"KENGO HAMASAKI","country":"JP","type":"Visa","cvc_check":"pass","last4":"4242"}}, 201)
callbackId
という関数の呼び出し文が返されます.
callbackId(data,status)という形式になってます.
先ほどのwindowオブジェクトに埋め込んだ関数の引数としてこの(data,status)が入ってきます.