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

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

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

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

521閲覧

ルーティング前にセッション変数を使う方法

kazu2021

総合スコア48

Node.js

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2023/01/18 02:56

編集2023/01/18 05:44

前提

Node.jsでツイッター情報を取得、表示するアプリを作っています。

実現したいこと

トップページを表示したときにセッション情報の有無で条件を分岐したい
セッション無ならツイッターAPIから最新の情報を取得
セッション有ならツイッターAPIにはアクセスしない

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

ルーティング用のファイルで req.sessionを使おうとしたらundefinedのエラー

エラーメッセージ C:\node_twitter\twitter_get\routes\twitterRoutes.js:13 if (req.session.access === undefined) { ^ ReferenceError: req is not defined

該当のソースコード

route.js

1// Twitterアプリに初めてアクセスした時、セッションを更新します。 2if ((req.session.access === undefined)) { 3 req.session.access = true; 4 router.get('/', twittersController.saveDbTweets, twittersController.getDbTweets, twittersController.index); 5} else { 6 router.get('/', twittersController.getDbTweets, twittersController.index); 7}

試したこと

ルーティング後のtwittersController.saveDbTweetsの中ではreq.sessionが使えるので
その中で条件分岐を行いました。

route.js

1 router.get('/', twittersController.saveDbTweets, twittersController.getDbTweets,

node.jsサーバからrequest、responseの情報が渡されるのが
URLのパスにアクセスしてからのようなので
ルーティング前にreq.sessionを使うことは不可能なのでしょうか?

もしルーティング前にreq.sessionを使う方法がございましたら
ご教示の程宜しくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

ルーティング前にセッション変数を使う方法

結論から言うと無理です。
ルーティング前は初期処理、つまりWebサーバが立ち上がる前段階の話です。

Webサーバが立ち上がっていない
→HTTPリクエストがやってくる前
→そのユーザーがセッションを確立してるかわかるわけがない

アクセスを引き込んだ後の関数群でif文で分岐させるくらいしか対処法がありません。


これはPHPとNode.jsでサーバーの作りが違う事をコードにまで落とし込めていない事が原因です。

まず抑えて置かなければならない前提知識の話をします。
その後にコードとしてどう実装していかなければならないかに触れていきましょう。

PHPはApacheやPHP-fmt等の別アプリに
PHPの実行ファイルを起動させただけの状態でスタンバっていてもらい
Webアクセスが来たら対象のPHPファイルをロード→実行としています

なので超大型フレームワークLaravelやSymfonyといったWebフレームワークは
アクセスが来る度に全てのクラスファイルやらをロードしてってやってる超効率の悪いシステムです
その割には意外にもかなり高速に動作しているのでチューニングを相当頑張ってます

Node.jsのWebサーバはイベントループを使った1プロセスによる動作を実現します。
予めapp.get("/", fn)という風に関数を登録して、その場では実行せずにスルー
Webアクセスが来たらHTTPリクエストのパス部を確認して該当する関数を取り出して実行!

こういう作りなので、最初の起動には時間かかりますが、
実際に訪問者がWebアクセスする時点では仕組み上高速に動作します。
(RubyやPython、Goなんかも全てこういった仕組みで、PHPだけCGI風の動作をさせ続ける異端児みたいなポジションです)


次に駄目な理由について解説していきます。

router.get('/', twittersController.saveDbTweets, twittersController.getDbTweets, twittersController.index);

これは公式サイトの[ガイド > ルーティング > express.Router}(https://expressjs.com/ja/guide/routing.html)に詳細が載っています。

js

1const express = require('express') 2const app = express() 3 4const router = express.Router() 5router.use((req, res, next) => { 6 console.log('Time: ', Date.now()) 7 next() 8}) 9router.get('/', (req, res) => { 10 res.send('Birds home page') 11}) 12router.get('/about', (req, res) => { 13 res.send('About birds') 14}) 15 16// 最後にuseで組み込んでいるのでrouterはミドルウェア 17app.use('/birds', router) 18app.listen(3000)

こういう感じの実装になるかと思います。
このとき、router.get(path, fn)は全て「HTTPリクエストというイベントを待って関数実行する」ための登録申請でしかありません。
Webサーバが稼働する前に全ての登録申請は完了していなければなりません。

js

1// Twitterアプリに初めてアクセスした時、セッションを更新します。 2if ((req.session.access === undefined)) { 3 req.session.access = true; 4 router.get('/', twittersController.saveDbTweets, twittersController.getDbTweets, twittersController.index); 5} else { 6 router.get('/', twittersController.getDbTweets, twittersController.index); 7}

この行を通過している時点ではHTTPリクエストは来てますか?
Webサーバを稼働させる前処理の段階なのでHTTPリクエストが来るわけないんですよ。

そんな段階なのに、どうして訪問したユーザーがログイン済だなんて判別できるんですか?
できるわけがない。


最後にどのようにすれば良いかを解説します。

トップページを表示したときにセッション情報の有無で条件を分岐したい
セッション無ならツイッターAPIから最新の情報を取得
セッション有ならツイッターAPIにはアクセスしない

パスが同じなので、Webサーバの初期処理でやることは不可能です。
HTTPリクエストを受け取って実行した先の関数内で良い感じに処理するしかありません。

  • ミドルウェアを使いreqを拡張
  • reqの拡張に成功しているかを確認して、if文で分岐

ミドルウェアを作って使う!というと非常に敷居が高いように感じるかもしれませんが、
ルールさえ覚えておけば単純です。

Expressはapp.useapp.getapp.postなど、様々なメソッドが用意されていますが、
あれらは全てミドルウェアの適用です。
HTTPリクエストを確認して「今回のアクセスはメソッドの部分がGETだね。postは違うからapp.postはスルーしよう」とかやってるだけです。

HTTPアクセスが来たとき、
上から順番に確認していき、条件に合致(HTTPのメソッドやパス)があればミドルウェアの適用を行い
「基本的には」そこで処理が完了します。

継続してほしければ第三引数のnextを実行しましょう。
nextを実行すると、処理を行った後、ヒットしなかった場合と同じように下にミドルウェア適用の関数が無いか探しに行きます。

そしてミドルウェア適用は全ての関数は(req, res, next)の引数を受け取ります。
普段我々は(req, res)までしか定義しませんが、単純に「どうせ第三引数のnextなんて使わないから宣言しないよ」とスルーしているだけです。

この辺のルールはドキュメントのミドルウェアの作成に記載されています。
https://expressjs.com/ja/guide/writing-middleware.html

投稿2023/01/19 02:46

編集2023/01/19 03:28
miyabi-sun

総合スコア21158

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

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

kazu2021

2023/01/26 04:33

返信がおそくなり誠に申し訳ございませんm(__)m コロナに感染してしまい今になってしまいした。 セッションの有無を判定する処理とTwitterApiにアクセスする処理をミドルウエア切り出した方がすっきりしそうですね。 ミドルウェアについてよく分かっていなかった部分もあり理解が深まりました。 たいへん勉強になりました。ありがとうございますm(__)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問