Edited at

素のJavaScriptで書くPOSTメソッドにおける二重送信対策


はじめに

現在とあるチームプロジェクトにおいてフロント(Vue.js)を担当しております。しかしバックエンドをNode.jsで組んでおり、ちょくちょくそちら側も勉強しております。

今は「Node.js超入門」を使って勉強を進めています。

image.png

とても親切に優しく書かれているので、初学者の方にはお勧めですねー。

チャプター3で「超簡単掲示板を作ろう」とあるのですが、個人的に追加で機能を実装しながら遊んでいましたところ、とある問題に気づきました。

それが、「フォームの二重送信問題

特に「ページリロード時に発生する」ものについてです。

対策としては、PRGパターンの活用や、トークンの発行など色々あるのですが、

調べても調べても出てくるのはPHPにおける対策例ばかり。

確かに以前私もPHPを使ったことがあるので、そちらについては分かるのですが、今回はNode使ってるし、しかも送信後の表示ページは元のホーム画面と同じこともあり、ずっとどうしていいかわからず悩んでおりました。(私の知識不足が大きな要因ではありますが。。)


問題の症状

こんな感じの簡易掲示板を作りました。

登録処理前の状態.png

<フォーム部分のコード>

修正前のformタグ.png

actionで"/"記述することで、送信後のリクエストページを同じページに戻らせており、POSTメソッドを使用しています。

そして、「こんにちは!」と送信してみます。

formdataにデータが存在する-2.png

すると、無事に一番上にきちんと表示されました。

(今は私の名前でログインしているので、自動でID名は藤井となります)

検証ツールから「ネットワーク」を見て、さらに「ヘッダー」部分をみると、きちんと「Form Data」のところにidとmsgが表示されています。

しかし、これが問題でした。

送信完了後にここの「Form Data」が残ることにより、ページを再読み込みした時に何度も送信されてしまうのです。

ページの更新ボタンを押して見ます。

すると。。。

post送信での二重送信問題-2.png

ほら、このように結果として二重送信されてしまっています。。。。


解決策

Ajaxによる非同期通信が一番簡単でいいのではないかと、メンターからアドバイスを頂き、素直にそうすることに。まあ、それが一番簡単だよね。

しかし、気づきました。jQueryが必要やーーん。

素のJSでいじっていたので、どうしようか悩んで調べていたところ、行き着いたのがこちらの記事。脱jQuery $.ajax()

Screen Shot 2018-09-29 at 9.06.17.png

とても丁寧に解説されており、早速取り入れて見ることに。

ここで登場するのが、XMLHttpRequest

「クライアントとサーバー間でデータをやり取りするためのAPI」だそうです。

まあ、詳しくはググってみてくださいww

そんなことより早速実装してみました。

formタグにおける二重送信防止用の追加コード.png

ひとまず、先ほどのフォーム部分に、自動でフォーム送信が起こらないように追加①を入れました。onsubmit = "return false"と入れるだけです。

その次に、送信ボタンに対してonclick="関数名"追加②を入れて、送信処理を関数内で実行するようにします。ここではsubmitForm()としました。

次にscriptタグの中で処理を書きます。。

先ほどの送信ボタンを押した時に発火するsubmitForm()をここで定義します。

submitformの記述内容.png

上の画像に各役割の説明を入れました。

通信成功時の処理は特に必要ないので、空にしておき、完了時にページの再読み込みを行うようにしました。非同期通信ですので、ページのリロードを行わないと、追加処理が画面に反映されません。

そして、最後にmyXml.open()と書くことで、フォーム送信処理をここで初めて定義しています。ここでは、POSTメソッドで、同じ画面に戻りたいのでURLは/と書いています。

最後のif分はフォームの中身が空でない場合にのみ、送信処理がされるようにしました。


再度検証

一通り再設定は終わったので、再度試してみます。

登録処理前の状態.png

今回は「お寿司がいいです!」と送ってみます。

ポチッとな。

すると。。。

formdataは存在しないのでリロードしても問題ない-2.png

おーー!ちゃんと送信されました。

ネットワークのHeadersを見ても、Formdataは見当たりません。よし!

そして、リロードしてみます。

ポチッとな。

リロードしても重複しない.png

おおーーー!二重送信されていない!

無事にXMLHttpRequestが働いているぞ。感動。


最後に

二重送信の対策の一つとして、素のJavaScriptで書く場合はこのやり方が簡単な方法だと思いました。同じような問題に詰まっている方がいらっしゃいましたら、この記事が何かしらの助けになれば幸いです。


参照

XMLHttpRequest.readyState: ReadyStateに当てる番号の役割について理解

XMLHttpRequest についてのメモ:メソッドやプロパティについて詳しく表になっています!

Node.js超入門:Node.jsのためにいま利用している参考書