質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

解決済

1回答

2351閲覧

Node.jsで画像表示とページ遷移を両立させたい

mariko68311

総合スコア10

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2021/12/27 04:17

前提・実現したいこと

プログラム初心者です。
あるゲームのタイトル画面の作成中で、htmlに設定した画像を表示しながら、画像を押した際に他のページへ遷移できるように頑張っていたのですが、ネットで調べたプログラムを参考につくっていたところ、ページ遷移はできるのですが、画像の表示が上手くいかずにalt属性に付与した言葉が表示されるだけで画像が一切表示されません。
どなたかご教授をお願いできませんでしょうか?

発生している問題・エラーメッセージ

エラーが表示されているわけではないので読み込めてはいて、なにかしらの指定が足りないだけなのだとは思いますがそれがわかりません。また、cssも適用できていません。

該当のソースコード

const http = require('http'); const fs = require('fs'); const url = require('url'); const gestpage = fs.readFileSync('./index/index_gest.html', 'UTF-8'); const userpage = fs.readFileSync('./index/index_user.html', 'UTF-8'); const loginpage = fs.readFileSync('./index/login/login.html', 'UTF-8'); const stylecss = fs.readFileSync('./index/css/style_gest.css', 'UTF-8'); const port = 3000; const server = http.createServer(RouteSetting); server.listen(port, () => { console.log(`Server listening on ${port}`); }); function getType(_url) { var types = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.png': 'image/png', ".jpg": "image/jpeg" } for (var key in types) { if (_url.parse(key)) { return types[key]; } } return 'text/plain'; } function RouteSetting(req, res) { const url_parts = url.parse(req.url); switch (url_parts.pathname) { case '/': case '/index_gest.html': res.writeHead(200, {'Content-Type': getType(url)}); res.write(gestpage); res.end(); break; case '/index_user.html': res.writeHead(200, {'Content-Type': getType(url)}); res.write(userpage); res.end(); break; case '/login/login.html': res.writeHead(200, {'Content-Type': getType(url)}); res.write(loginpage); res.end(data); break; case '/css/style.css': res.writeHead(200, {'Content-Type': 'text/css'}); res.write(stylecss); res.end(); break; default: res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('お探しのページは見つかりません。'); break; } }

試したこと

if文での処理に変えようとしたりしました。また下にのせているサイトに載っているプログラムの一部一部を組み合わせてみたりしましたが、うまく動きませんでした。

補足情報(FW/ツールのバージョンなど)

参考にさせていただいたサイトです。
https://www.kipure.com/article/225/

https://k-koh.hatenablog.com/entry/2019/11/08/095732

https://www.i-ryo.com/entry/2020/04/03/061324

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

結論だけでいえば生httpモジュール使うのやめろ案件

httpモジュールはWebフレームワークの作者が実装するときに
変にあれこれ高度な機能を抱き合わせにして遅くなるより
最初からこういうショボくて高速に動作するパーツパーツだけよこしてくれた方がありがたいという話であって

我々Webの開発者が使うモジュールじゃありません。
せめてExpressあたりを使いましょう。
ページ上部にある「解説」や「ガイド」が便利すぎるし、
やりたいことはちゃんと実現できます。

bash

1# package.jsonファイルがあるかを確認 2$ ls 3 4# package.jsonファイルがなければ作る 5$ npm init --yes 6 7$ npm install express

静的ファイルの配信
publicというフォルダを作って、そこにhtmlファイルやcssファイルを投げ込む想定ならこんな感じ

js

1const express = require("express"); 2const app = express(); 3 4app.use(express.static(`${__dirname}/public`)); 5 6app.listen(3000);

4行で終わってしまった。


何故httpモジュールを生で触るのがクソなのかも見ていくために
問題に関して愚直に攻めていきましょう。

まずは問題を切り分けるところからです。

  1. 使用しているブラウザでデベロッパーツールを立ち上げる

Windown: F12キー
Mac: command + option + I
2. Networkタブを開く
3. F5やcommand + Rなどでページを再読み込み

すると基点となるHTMLファイルのダウンロードが正常にされて、
続くCSSファイルや画像ファイルは一つも読み込まれない事が確認できるはずです。
Wikipediaで調べたところ、ステータスコードとして404番を返せとRFCで(インターネットの仕様書で)定義されています。

js

1 default: 2 res.writeHead(200, {'Content-Type': 'text/plain'}); 3 res.end('お探しのページは見つかりません。'); 4 break;

ページがないのに200の正常終了?うせやろ?
404に修正しておいてください。
そうすれば404番のそんなファイルは無いという結果が帰ってきます。

こういうとこフレームワークなら組み込まれて当然
でhttpモジュールには無いから手作業で書かされるわけで、
知ってなきゃ地雷踏むよってことですね。


次に質問文のコードの何がいけなかったのか、
どのように修正していけば良いのかを見ていきましょう。

参考記事の下記記事を読む限り、使うべき本体を使えていません。
https://www.kipure.com/article/225/

js

1 if (fs.existsSync(url)) { 2 //ファイルがあれば 3 fs.readFile(url, (err, data) => { 4 if (!err) { 5 //res.writeHead(200, {"Content-Type": "text/html"}); //本当はこのように書きたいが 6 res.writeHead(200, {"Content-Type": getType(url)}); //拡張子をみないと書けないので 7 res.end(data); 8 } 9 }); 10 }

一番移植しなければならないのはこの部分です。
ざっと何やってるかを解説

Node.jsにはfs(file system)モジュールがあります。
https://nodejs.org/api/fs.html

これはNode.jsのマシン内に存在しているファイルを読み書きする機能です。
しかし、これの元になっているJavaScriptにはファイルを読み書きするような機能はついていません。

Node.jsの開発者はC++でファイルの読み書きできるモジュールを作って
JavaScriptエンジンと自作のモジュールを合体させることで、
Node.jsとして動かしたときにファイルの読み書きができるということを実現しています。

そのfsモジュールを使って、
fs.existsSyncでファイルが存在するか否かを確認、
fs.readFileで実際にファイルをバイナリ形式で読み込んでres.end(data);で流し込む
こういう事をやっています。

switch文で1個1個足していくより遥かに高度な事やってますね。
フォルダの中にファイルを投げ込むだけで検知してくれますからね。

これがまるっと不足しているので
画像ファイルを検知できていないのが原因です。
更に質問者さんがエラーを検知できなかったのは、ファイルがなくても上記で200番の正常終了を返していたためです。


質問文のコードに組み込んで、
少々手直しするとこんな感じになるでしょう。

js

1function RouteSetting(req, res) { 2 const url_parts = url.parse(req.url); 3 const path = url_parts.pathname === '/' 4 ? `${__dirname}/index_gest.html` 5 : `${__dirname}/${url_parts.pathname}`; 6 7 if (fs.existsSync(path)) { 8 fs.readFile(path, (err, file) => { 9 if (err) { 10 // errになるということはパーミッション等の問題で読み取れない重篤なエラーになっている 11 console.error(err); 12 res.writeHead(500, {'Content-Type': getType(url)}); 13 res.end('ファイルを読み込む事ができませんでした'); 14 return; 15 } 16 res.writeHead(200, {'Content-Type': getType(url)}); 17 res.end(file); 18 }); 19 return; 20 } 21 22 // 最後まで適したページがなければ404を返して終わる 23 res.writeHead(404, {'Content-Type': 'text/plain'}); 24 res.end('お探しのページは見つかりません。'); 25}

確認してはいませんが、
こんな感じで動作するかと思います。

使ったテクニックとしては下記

  • __dirname: これでNode.jsの実行ファイルからの相対パスでファイルのありかを探せるようになる

ドット.始まりのパスにした場合、nodeコマンドを実行したカレントディレクトリが.になりブレるので極力__dirnameを使うべき

  • 三項演算子: これで/に来たときに/index_gest.htmlに流すようにした
  • 早期リターン: これでif文だらけで延々とネストしていく事を抑止

ここまで頑張って書きましたが、
expressみたいなちゃんとしたWebフレームワークにやってもらった方が良いです。

投稿2021/12/27 07:00

miyabi-sun

総合スコア21203

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mariko68311

2021/12/27 13:40

おわわわ、、、!長々とありがとうございます、とりあえずexpressを中心に組み替えてみますね!ゆっくりと読ませてもらいます、、、!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問