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

#はじめに

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

今は「Node.js超入門」を使って勉強を進めています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/252687/61b5e961-f8f6-e522-746a-df338eb91800.png)

とても親切に優しく書かれているので、初学者の方にはお勧めですねー。
チャプター３で「超簡単掲示板を作ろう」とあるのですが、個人的に追加で機能を実装しながら遊んでいましたところ、とある問題に気づきました。

それが、「**<font color="red">フォームの二重送信問題</font>**」

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

対策としては、PRGパターンの活用や、トークンの発行など色々あるのですが、
調べても調べても出てくるのはPHPにおける対策例ばかり。

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

#問題の症状
こんな感じの簡易掲示板を作りました。
![登録処理前の状態.png](https://qiita-image-store.s3.amazonaws.com/0/252687/c290ce83-0f0b-8b57-c36b-3a656099f3e7.png)

<フォーム部分のコード>
![修正前のformタグ.png](https://qiita-image-store.s3.amazonaws.com/0/252687/4502145c-b9f1-fcef-2ca0-1af153584f1d.png)
actionで"/"記述することで、送信後のリクエストページを同じページに戻らせており、POSTメソッドを使用しています。

そして、**「こんにちは！」**と送信してみます。
![formdataにデータが存在する-2.png](https://qiita-image-store.s3.amazonaws.com/0/252687/6ab65f53-a1db-8cdd-f690-44aeb4562b10.png)
すると、無事に一番上にきちんと表示されました。
(今は私の名前でログインしているので、自動でID名は藤井となります)

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

**<font color="red">しかし、これが問題でした。</font>**

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

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

すると。。。
![post送信での二重送信問題-2.png](https://qiita-image-store.s3.amazonaws.com/0/252687/8e43e635-69f6-47bf-fc50-61200e539918.png)

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

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

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

素のJSでいじっていたので、どうしようか悩んで調べていたところ、行き着いたのがこちらの記事。[脱jQuery $.ajax()](https://q-az.net/without-jquery-ajax/)

![Screen Shot 2018-09-29 at 9.06.17.png](https://qiita-image-store.s3.amazonaws.com/0/252687/11e7c979-0e32-135d-f0fe-27ad598c0497.png)


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

ここで登場するのが、**<font color="red">XMLHttpRequest</font>**
「クライアントとサーバー間でデータをやり取りするためのAPI」だそうです。

まあ、詳しくはググってみてくださいww 
そんなことより早速実装してみました。
![formタグにおける二重送信防止用の追加コード.png](https://qiita-image-store.s3.amazonaws.com/0/252687/c8049618-c748-b655-0b72-6bff24c14d39.png)

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

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

次に`script`タグの中で処理を書きます。。
先ほどの送信ボタンを押した時に発火する`submitForm()`をここで定義します。
![submitformの記述内容.png](https://qiita-image-store.s3.amazonaws.com/0/252687/77adff69-b8ed-bed7-ec22-a8b93535d1b9.png)
上の画像に各役割の説明を入れました。
通信成功時の処理は特に必要ないので、空にしておき、完了時にページの再読み込みを行うようにしました。非同期通信ですので、ページのリロードを行わないと、追加処理が画面に反映されません。

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

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

# 再度検証
一通り再設定は終わったので、再度試してみます。
![登録処理前の状態.png](https://qiita-image-store.s3.amazonaws.com/0/252687/15dc8848-d226-32cb-5621-167e88ca6df6.png)
今回は**「お寿司がいいです！」**と送ってみます。

ポチッとな。
すると。。。
![formdataは存在しないのでリロードしても問題ない-2.png](https://qiita-image-store.s3.amazonaws.com/0/252687/9d19322c-4629-e1b8-3c1f-9f9b58a8fea5.png)

おーー！ちゃんと送信されました。
ネットワークのHeadersを見ても、Formdataは見当たりません。よし！

そして、リロードしてみます。
ポチッとな。
![リロードしても重複しない.png](https://qiita-image-store.s3.amazonaws.com/0/252687/1f469d8d-92eb-5999-c357-2356a7e5ff37.png)
おおーーー！二重送信されていない！
無事にXMLHttpRequestが働いているぞ。感動。

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


#参照
[XMLHttpRequest.readyState](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState): ReadyStateに当てる番号の役割について理解
[XMLHttpRequest についてのメモ](https://qiita.com/sirone/items/412b2a171dccb11e1bb6):メソッドやプロパティについて詳しく表になっています！
[Node.js超入門](https://www.amazon.co.jp/Node-js%E8%B6%85%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/479805092X):Node.jsのためにいま利用している参考書