今回は、掲示板を動かすコードを教えてもらい、実際に動かしてみます。
教えてもらったことを勉強して、「実は教えてもらったコードは間違っていました」では悲しすぎますので。
あくまで動かすだけですので、「fetch通信」みたいな用語は次回からやっていきます。
なお、最初に言っておきますと、今回は「私のミス特集」です。
「ああ、これは知らなかった」というのもあれば「こんなミス普通しないだろ…」というのもあるかと思います。
まずはそれをご承知おきください。
さて、前回の記事で、フォームに書き込んだ名前をAPIに送り、それを確認するところまでやりました。
今回はそのデータをウェブページで反映するところをやっていきます。
前回の「③APIに送ったデータを確認する」では名前だけを送信して確認しましたが、今回は実際に書き込みが反映されるところまでやりますので、名前とメッセージを送信しようと思います。
フロントエンドのみで書き込みを反映させる方法については、下記のページで解説しているので参照していただけたらと思います。
今回はサーバーもつかった掲示板ですが、HTMLは使いまわせるので、これを利用していきます。
CSSは今回は無視です。
あくまで、まずは「フォームに書いて送信」「書き込みを反映」、です。
で、本当はそこまで一気にやろうとしたんですけど、どうもここからはちょっとレベルが段違いになるみたいな感じでして。
三回くらいに分ける感じになると思います。
では進めていきます。
まず、完成形を先生に教えてもらいます。
HTML
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>掲示板</title> </head> <body> <h1>掲示板</h1> <form id="form"> <input type="text" id="name" placeholder="名前" /> <textarea id="comment" placeholder="コメント"></textarea> <button type="submit">送信</button> </form> <div id="posted"></div> <script src="script.js"></script> </body> </html>
フロントエンド用JavaScript(script.js)
document.getElementById('form').addEventListener('submit', async (e) => { e.preventDefault(); const name = document.getElementById('name').value.trim(); const comment = document.getElementById('comment').value.trim(); if (!name || !comment) { alert('名前とコメントを入力してください'); return; } try { const res = await fetch('/api/messages', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, comment }), }); if (!res.ok) throw new Error('送信に失敗しました'); const data = await res.json(); showPostedMessage(data); document.getElementById("comment").value = "";//コメント内容をクリア fetchMessages(); // 任意:投稿一覧を取得して再表示 } catch (error) { alert(error.message); } }); function showPostedMessage(message) { const postedDiv = document.getElementById('posted'); const newMessage = document.createElement('div'); newMessage.innerHTML = ` <p><strong>${escapeHTML(message.name)}</strong> さんのコメント:</p> <p>${escapeHTML(message.comment)}</p> <hr> `; postedDiv.prepend(newMessage); } async function fetchMessages() { try { const res = await fetch('api/messages'); if (!res.ok) throw new Error('投稿一覧の取得に失敗しました'); const messages = await res.json(); const postedDiv = document.getElementById('posted'); postedDiv.innerHTML = ''; messages.forEach(showPostedMessage); } catch (error) { console.error(error); } } function escapeHTML(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } fetchMessages(); // ページ読み込み時に一覧を取得
バックエンド用のJavaScript(server.js)
const express = require('express'); const cors = require('cors'); const app = express(); const PORT = 3000; app.use(cors()); app.use(express.json()); let messages = []; app.get('/api/messages', (req, res) => { res.json(messages); }); app.post('/api/messages', (req, res) => { console.log('POST受信:', req.body); const { name, comment } = req.body; if (!name || !comment) { return res.status(400).json({ error: '名前とコメントは必須です' }); } const newMessage = { name, comment }; messages.push(newMessage); res.status(201).json(newMessage); }); app.listen(PORT, () => { console.log(`サーバーがポート${PORT}で稼働中`); });
なんか見るからに、前回までやってきたものとはレベル違う感じがします。
HTMLだけはほぼ同じですが。
<form>にIDをつけて取得しているところが違うくらいですが、これはどっかで間違えて<form>を取得してしまうというミスを防ぐためです。
あと、前回までは名前だけど送信していましたが、ここまでいろいろ変わってしまうのであれば、コメントも同じように送信してしまうことにします。
まあHTMLに関しては特に問題はないかと思います。
問題はJavaScriptのほうですが、とりあえずこれが動かないことには話になりませんので、動かしてみます。
これまで、script.jsとserver.jsを作りましたが、それぞれフロントエンド、バックエンドのコードを貼り付けることになります。
名前とコメントを書いて送信してみます。
成功しました。
ただこれ、フロントエンドのJavaScriptのおかげで<div>が作成されてうまくいってるように見えてるだけなんですね。
ちゃんとサーバーにデータが行って、それを反映しているのを確認する必要があります。
で、見てきました。
[nodemon] app crashed - waiting for file changes before starting...
なんだこれは。
なんかクラッシュとかでてるんですが。
しかもnode.jsも強制終了されたようです。
ええ・・・?
仕方ないのでエラーの内容を見ていきます。
原因っぽいもの①cors
上から順番に見ていったら、エラーの中にこんなのがありました。
Error: Cannot find module 'cors'
corsが見つからない?
corsって何?
ということで先生に聞いてみました。
どうやらこれは別のポートからアクセスしてきたfetch通信を許可するためのものだそうです。
fetch通信ってのが何なのかは今は置いとくとして、まずは問題解決にあたります。
解決方法は簡単。
インストールすればいいだけです。
というわけでインストールします。
npm install cors
と記入するだけですね。
npm install cors added 2 packages, and audited 69 packages in 1s 14 packages are looking for funding run `npm fund` for details found 0 vulnerabilities
という結果になりました。
vulnerabilities(問題点)もゼロなので問題ないようです。
さて。
じゃあ今度こそ!
nodemon server.js
でサーバーを立ち上げて試してみます。
相変わらずページのほうに反映はされましたが、ターミナルのほうには全く変化がありません。
さて、次の問題点探しです。
原因っぽいもの②const res = await fetch('api/messages'
これ、'api/messages'この部分って宛先を示すんですけど、立ち上げてるサーバーのポートは3000なんです。
おそらく普通に立ち上げたら3000になると思います。
ですけどフロントエンドのみで使ってた、簡易用のライブサーバーのポートは5500でした。
VS Codeの一番右下を見ればわかるかと思います。
おもいきり5500と出ています。
もし見つからなければ、ウインドウを最大にしてみてください。
それで見つかることも多いですので。
せっかく上でcorsで違うポートからのアクセスを許可したと言ってたのに、そもそも送り先が違ってたんじゃ意味ないですね。
なのでここはポート3000に送ると指定します。
await fetch('http://localhost:3000/api/messages'
変更する場所は二か所あるので気を付けてください。
さて、これで問題はなくなったはず!!
いざ実行!!
・・・・失敗。
なんでやねん・・・。
F12キーでエラーを見てみますがエラーはdetector.js:1ばかりなのですが、これは拡張機能によるものなので無視してかまいません。
そうするとエラーは全くなくなってしまいます。
とりあえずVS Codeやターミナルを再起動してみます。
・・・・ダメでした。
いったい何がダメなのか・・・。
原因っぽいもの③というか完全に原因
で、気づいたのが、index.htmlのファイル。
これが全然違うものを操作してたのではないか、ということに思い至りました。
ごめんなさい。
嘘つきました。
ChatGPT先生に「本当に正しいファイルを操作してる?」と聞かれて確かめました。
私が作業用フォルダとして使っていたのは「NODE_INTRO_CODE」だったのですが、実はその中にさらにテスト用の作業用フォルダを作っていました。
その中で使っていたindex.htmlが関与してきて、私は一生懸命それをいじくっていたというわけです。
すべてのテスト用フォルダを放り出したらすべてうまくいきました。
script.jsに仕込んだ「スクリプトを読み込みました」と表示させるconsole.logは作動しましたし、ターミナルのほうにもPOST受信という文字とともに、入力した内容も届いていました。
なんというミス・・・!
凡ミスじゃありません。
私にとっては本格的なミスです。
いずれにしても、作業用フォルダの中に別のフォルダを入れてはいけないということはわかりました。
二度とこのようなことがないよう気を付けていきたいと思います。
最後に
まさかChatGPT先生が書いてくれたコードをそのままコピペしたにもかかわらず、動かすだけでここまで時間をかけてしまうとは思いませんでした。
記事を独立させて本当に良かったと思います。
これでやっと進めていけます。
次回はフロントエンド側のJavaScriptのコードを見ていきます。