22章 実践Node.jsプログラミング
- p502 ネットワークやファイルを非同期で処理する実例紹介
HTTPサーバ処理
- http関連のAPIはhttpモジュール
- httpモジュールでは基本的なHTTP機能を提供
HTTPサーバ処理の基本
リクエスト処理
- http.ServerRequestクラスでリクエスト処理を行う
- http.ServerRequestクラスは読み込みストリームを継承したクラス
- p504 http.ServerRequestのイベントとプロパティ一覧
- HTTPサーバ処理の入力は、リクエストURL、ヘッダ値、ボディ値
- GETはリクエストURLのクエリパラメータ、POSTはボディでフォームデータを受け取る
- リクエストヘッダはheadersプロパティ。ヘッダ名は全て小文字
- URLパース処理
- URLパスとクエリパラメータ値はhttp.ServerRequestオブジェクトのurlプロパティから得られる
- URL文字列のパースはurlモジュール。クエリパラメータのパースはquerystringモジュールにある
- p505 これらの処理はWebアプリフレームワークが隠蔽してくれることが多い
レスポンス処理
HTTPクライアント処理
- p507 http.ClientRequestクラスとhttp.ClientResponseクラスで行う
- HTTPクライアント処理は、リクエストを投げてレスポンスを待つだけ
- リクエストボディはwriteメソッドとendメソッドで書き込む
- リクエストボディがなくてもendは必要
- レスポンスはresponseイベントで待つ
- http.ClientRequestオブジェクトの生成は、http.request関数で生成する
- 第1引数は接続先サーバ情報を渡し、第2引数にコールバック関数を渡す。第2引数のかわりにon関数で設定することも可能
- p508 responseイベントハンドラの引数にhttp.ClientResponseオブジェクトが渡される
- responseイベントでdataイベントを仕込み、レスポンスのボディデータを取得する
- 事前にsetEncodingメソッドで文字エンコードを指定すると文字列、なにもしないとBufferオブジェクトで得られる
- GET専用のhttp.getメソッドもある。endは不要
Socket.IOとWebSocket
- Part4ではwebsocket-serverパッケージを使ったが、ここではSocket.IOパッケージを利用
- Socket.IOはWebSocketを含めたリアルタイム通信を提供するパッケージ
- http://socket.io
- パッケージをnpmでインストールすると、Node.jsを使うサーバサイドJavaScript向けライブラリと、Webブラウザ上で動くクライアントサイドJavaScript向けライブラリがセット
- 一度接続が成立すれば、対照的に送受信可能
- p511 プログラム例
低レイヤのネットワークプログラミング
ソケットとは
- ソケットはストリームそのもの
- 書き込んだデータを相手が読むかや、読もうとしたデータを相手が送っているかが保証されないのがファイルやメモリのストリームとは違う
- ソケットの種別
- ソケットを使うには通信相手と接続を確立する。相手先(相手機材)をIPアドレス、接続相手の識別(プロセス)にポート番号
- ソケットにはサーバとクライアントという区分けはなく、接続を待ち受けるソケットと、接続にいくソケットがある
- 受動的なソケットでは、相手から接続するターゲットとなるので、ポート番号を自分で指定する
- 能動的ソケットのポート番号はなんでも良いので、空いているポート番号からシステムが自動的に選ぶように指定できる
- ソケットの動作
- p513 能動的なソケットから受動的なソケットへ接続を開始し、接続が成立すると受け入れソケットを自動で生成する
- 接続が成立すると、能動的ソケットと受け入れソケットは対照的にデータの送受信ができるようになる
- やりとりするのは、能動的ソケットと、受け入れソケット。受動的ソケットは待ち受けに使うのみ
- 通信の終了は、いずれかがソケットを閉じれば良い
- 受動的ソケットは残っている。別のクライアントから接続があれば、新しい受け入れソケットを作成して接続を行う。受動的ソケットを持つPCは、複数のクライアントと接続される
ソケットプログラミングの基本構造
p515 ソケットプログラミングの具体例
ファイル処理
- p516 Node.jsのファイル処理にはfsモジュールを、ファイルパス関係の処理にはpathモジュールを使う
- ファイル処理の関数には同期版と非同期版がある
- Node.jsのネットワークは全てノンブロッキングで非同期関数
本節のサンプルコード
- p517 コマンドライン引数で対象のファイルパスを渡す前提
ファイルの非同期処理
- ファイルのstat関数を非同期に呼び出すコード例
ファイルの同期処理
- p518 戻り値で結果が得られる
ファイル操作系の関数
- Unix系の前提。他OSへの移植性は書籍の段階では低い
ファイル読み込み
- p519 ファイルの非同期読み込み例
- 非同期処理はコードが読みづらい
- パフォーマンスに問題がなければ、ファイル読み込みは同期的に読み込むのも手段
- p520 簡易APIのreadFileとreadFileSyncがある
ディレクトリ操作
- ディレクトリ操作API一覧
ファイルの変更監視
- p522 監視の開始と停止の例
ファイルパス
- pathモジュール。代表的なAPI一覧
タイマー
- p523 DOMと同様のsetTimeoutやsetIntervalがある
- timersモジュールの関数だが、暗黙で読み込まれているのですぐに使える
Node.jsのデバッグ
- node debug my.js でデバッガを起動
Express
- p524 Webアプリ作成のためのMVCフレームワーク
- http://expressjs.com
- npmでインストール
- get関数でpathを指定すると、GETメソッドで該当パスにアクセスがあった際にイベントが呼び出されるようになる
- expressは、リクエストURLと内部のコールバック関数の対応付けを定義すること
- このような対応をURLルーティング処理や、URLディスパッチ処理と呼ぶ
URLルーティング
- get,post,put,delなどがある。削除をdelと省略することに注意。これはdeleteがJavaScriptの予約語のため
- 全てにマッチさせるのがall
- p525 app.get('/user/:id'…)とすると、/user/suzukiとアクセスした際に、req.params.idでsuzukiを取り出せる
- よって、RESTfulなURL設計に役立つ
- URLパスの場所には複数の要素が書けたり、正規表現なども利用可能
リクエスト処理
- リクエスト処理の主な対象は、URLパスに加えて、GETはクエリパラメータ、POSTはフォームデータ
- クエリパラメータは、req.query['foo']のように値を取得できる
- 同じパラメータ名があると配列になる
- POSTのフォームデータを受け取るには、app.use(express.bodyParse())などと前処理を行う
- フォームのフィールド値はreq.body['foo']のように得る
- name="user[name]" name="user[email]"などのようにすると、req.body['user']は、{name:値,email:値}のようなオブジェクトで得られる
- req.paramメソッドを使うと、パスの要素、クエリパラメータ、フォームデータ全てを同じスタイルでアクセスできる
- p526 第2引数で初期値を指定できる
レスポンス処理
- レスポンス処理の代表的なメソッド一覧
- renderが一番重要
scaffold作成機能
- expressコマンドが付属
- アプリケーションの骨格となるファイルをコマンド1つで作成するscaffold機能を提供
- express アプリ名 で、アプリ名のフォルダが生成されて、必要なファイルが自動生成される
- フォルダ内にapp.jsというファイルが出来上がるので、 node app.js で実行
MVCアーキテクチャ
- scaffoldで作成すると、MVCアーキテクチャが利用できる
- p527 res.renderメソッドの第1引数がビュー名で、第2引数がビューに渡るコンテキストオブジェクト
- MVCの流儀では、ビューに渡すコンテキストオブジェクトをモデルと呼ぶ
- ビューは、コントローラから渡されたコンテキストオブジェクトを参照して最終的な出力結果を生成する
- ビューにはテンプレート言語を使うのが定石
- MVCの役割分担
- コントローラの役割の一つは、コンテキストオブジェクトを生成してビューに渡すこと
- モデルの役割をバックエンドの処理と定義すると(いくつか定義がある)、コントローラの役割はモデルとビューの対応付け
- MVCアーキテクチャに従うWebアプリのコントローラの他の役割は、URLルーティングや、フォームデータなどの受信データを内部データに変換するバインディングなど
- res.renderの第1引数は、実ファイルに対応付け。対応付けはapp.jsに依存
- レスポンス処理を指定先に委譲。Javaサーブレットではこのような動作をフォワード処理と呼ぶ
- コントローラがリクエストを受け取る
- URLパスなどに応じて内部処理のモデルを呼ぶ
- モデル呼び出しの結果をコンテキストオブジェクトとしてビューに渡す
- ビューはコンテキストオブジェクトをもとにレスポンスを出力する
テンプレート通信Jade
- p527 レスポンスをHTMLなどでハードコーディングすると保守性が悪い
- ビュー層にテンプレート言語を使う
- テンプレート言語は、HTMLの不変部分をベースに、実行時の可変部分を埋め込むように記述する
- JavaでいうとJSP、PHPはそのものがテンプレート言語
- p528 ExpressではJadeがデフォルト http://jade-lang.com/
- Jadeの主要な規則一覧
MongoDB
- p529 Node.jsからは様々なRDBMSに接続できるが、まだスタンダードになりそうなものが不明なのでnodejs-dbを紹介 http://nodejsdb.org/
- p530 MongoDB http://www.mongodb.org/
- 書籍ではMongoose http://mongoosejs.com/ を利用
- npmでインストールして、起動
- mongodがMongoDBのサーバプロセス
- mongoコマンドが付属。対話型JavaScriptシェル機能をもつ
- MongoDBの概念
- JavaScriptのオブジェクトを永続化できるものと考えても差し支えない
- 永続化したオブジェクトをドキュメント。オブジェクトのプロパティをフィールド
- ドキュメントはIDで識別され、IDをキーにして取得(検索)、更新、削除ができる
- ドキュメント指向データベース
- SQLに比べると表現力は劣るが、分散処理に向いている
Mongooseの実例
ExpressとMongooseを使うWebアプリ
- 文章管理アプリ
- p533 scaffoldでアプリの雛形を作成
- モデル作成
- app.jsの相対パスのmodels/article.jsファイルを作成。モデルに該当し、Mongooseが提供する機能そのもの
- 独自操作が必要な場合はArticleクラスのprototypeに独自関数を追加
- app.jsにarticle.jsを読み込ませる
- 文書一覧のコントローラ
- p534 app.jsの/へのリクエストを受けた時の処理をapp.getで設定
- 文書一覧のビュー
- views/index.jadeファイルを改変して、HTMLテーブルで文書一覧を表示
- 文書表示機能
- /文書ID形式のパスのリクエストを受けた時のコントローラとしての振る舞いをapp.jsにapp.getで追加する
- 文書作成機能
- p535 app.get('/create'…で、パスに割り当てる。/:idとかぶるのでこちらを先に書く
- ビューとなるviews/create.jadeファイルを作成
- フォームのアクションを、文書一覧表示の/にする。コンテナに対して文書をPOSTすると新規文書になるのはRESTfulなURL設計のイディオム
- POST先のコントローラは、app.post('/'…)で設定
- 文書保存時のレスポンスにはリダイレクトを使うのがWebアプリの定石
- CRUD(Create,Read,Update,Delete)は揃っていないが、最低限のもの
- MongoDBでは指定した_idプロパティがなければ新規保存、あれば更新処理
- 削除はremoveメソッドを使う