ルーティング前にセッション変数を使う方法
結論から言うと無理です。
ルーティング前は初期処理、つまり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.use
やapp.get
、app.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/26 04:33