Expressでフォーム送信/受信

Node.js+Expressを使ってフォーム送信/受信するページを作りたいと思います。
https://qiita.com/watsuyo_2/items/327b74d68f921dbdd524を参考にしました。
まずは http://localhost:3000/hello でページが表示されるように routes の設定をします。
app.js の設定
App.js に2行のコードを追記します。
var helloRouter = require('./routes/hello');
app.use('/hello', helloRouter);
routes の設定
routes ディレクトリに hello.js を作ります。
ここは参考ページから丸々コピペしました。
const express = require('express')
const router = express.Router()
// define the home page route
router.get('/', function (req, res, next) {
const data = {
title: '会員登録情報の確認',
content: '会員確認のため、お名前をご記入ください'
}
res.render('hello', data);
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
router.post('/confirm', (req, res, next) => {
const name = req.body['userName'];
const data = {
title: '登録情報の確認完了!',
content: name + 'さんの会員登録情報が確認できました。'
}
res.render('hello', data);
})
module.exports = router;
しかし、このままブラウザで表示すると「Error: Cannot find module ‘html’」と出てエラーになってしまいます。
モジュールHTMLが見つからないよと怒られてしまいました。
そこで、https://www.code-adviser.com/detail_26779846 を参考にして app.js に以下のコードを追加しました。
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/public/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
今度はCannot find module ‘ejs’と怒られたので ejs モジュールをインストールします。
$ npm install --save ejs
ここでブラウザを表示します。
$node app.js
1度ブラウザに正しく表示されるようになりましたが、すぐにターミナルにエラーが吐き出されて中断されました。
$ node app.js
Example app listening on port 3000!
_http_outgoing.js:467
throw new ERR_HTTP_HEADERS_SENT('set');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:467:11)
なんだなんだ?
送信した後にヘッダー設定しているぞ!ということですかね。
res.send() が res.render() より先に読み込むように順番を変更して再度実行してみました。
正常に動きました!!!
HTMLファイルを作成
続いて hello.html を作ります。
参考ページではpugを使っていますが、ここでは普通にHTMLとして使いたいです。
Ejsは既にインストールして app.js にいろいろ設定しているのでHTMLが使えるはずです。
受け取った data を表示するにはどうしたら良いのでしょうか?
良い参考ページを見つけました。
https://qiita.com/kamihork/items/1b13d2157979d1837849 を参考に作りました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%- title %></title>
</head>
<body>
<h1><%- title %></h1>
<p><%- content %></p>
</body>
</html>
このHTMLファイルを /public/views に置いて app.js を実行します。
$ node app.js

このように hello.js のデータが渡されてブラウザ上で表示することができました!
あとはここにフォームを追加するだけです。
フォームを追加する
フォームを追加して送信してみました。
URLがちゃんと「http://localhost:3000/hello/confirm」に変わったけれどエラー…。
TypeError: Cannot read property ‘userName’ of undefined
こんなときはGoogle先生!
検索して良いものを見つけました。
https://blog.ryo4004.net/web/306/
//app.js に下記を追記。
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
ちゃんと動きました!
npm でbody-parserをインストールする必要があると書いてありますが、既にインストールされているので特にしませんでした。


コードの最終形態
//app.js
const express = require('express')
const app = express()
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/public/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
const helloRouter = require('./routes/hello')
app.use('/hello', helloRouter);
app.get('/', (req, res) => res.send('HelloWorld'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
// hello.js
const express = require('express')
const router = express.Router()
// define the home page route
router.get('/', function (req, res, next) {
const data = {
title: '会員登録情報の確認',
content: '会員確認のため、お名前をご記入ください'
}
res.render('hello', data);
})
router.post('/confirm', (req, res, next) => {
const name = req.body['userName'];
const data = {
title: '登録情報の確認完了!',
content: name + 'さんの会員登録情報が確認できました。'
}
res.render('hello', data);
})
module.exports = router;
//hello.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%- title %></title>
</head>
<body>
<h1><%- title %></h1>
<p><%- content %></p>
<form action="hello/confirm" method="post">
<input type="text" name="userName" value="">
<input type="submit" name="送信">
</form>
</body>
</html>

フォローお願いします