Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

現在とあるチームプロジェクトにおいてフロント(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のためにいま利用している参考書

fj_yohei
Vue, Nuxt, Rails, AWS, GCP, Docker, etc.... 複業でいろんな課題を解決中
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away