tanaka's Programming Memo

プログラミングについてのメモ。

パーフェクトJavaScript勉強メモ(22)

前へ

22章 実践Node.jsプログラミング

  • p502 ネットワークやファイルを非同期で処理する実例紹介

HTTPサーバ処理

  • http関連のAPIはhttpモジュール
  • httpモジュールでは基本的なHTTP機能を提供
HTTPサーバ処理の基本
  • http.ServerクラスがHTTPサーバ処理の中心
  • イベント一覧
  • p503 http.Serverインスタンスの生成には、http.createServer関数で生成するのが流儀
  • listenメソッドでHTTPサーバの動作が始まり、closeで停止
  • 接続があるとイベントが発火
  • 同時に接続があったら非同期にイベントが発生して処理する。ただし、シングルスレッド動作のため、実質は並列処理はしていない
  • HTTP通信プロトコルを操作したい場合はconnectionイベントに処理を書く
  • 通常はrequestイベントに処理を書く
リクエスト処理
  • http.ServerRequestクラスでリクエスト処理を行う
  • http.ServerRequestクラスは読み込みストリームを継承したクラス
  • p504 http.ServerRequestのイベントとプロパティ一覧
  • HTTPサーバ処理の入力は、リクエストURL、ヘッダ値、ボディ値
  • GETはリクエストURLのクエリパラメータ、POSTはボディでフォームデータを受け取る
  • リクエストヘッダはheadersプロパティ。ヘッダ名は全て小文字
  • URLパース処理
    • URLパスとクエリパラメータ値はhttp.ServerRequestオブジェクトのurlプロパティから得られる
    • URL文字列のパースはurlモジュール。クエリパラメータのパースはquerystringモジュールにある
    • p505 これらの処理はWebアプリフレームワークが隠蔽してくれることが多い
レスポンス処理
  • requestイベントハンドラ内で行う
  • http.ServerResponseは書き込みストリームを継承したクラスで、これで出力する
  • メソッド一覧
  • p506 writeメソッドとendメソッドの引数には文字列値かBuferオブジェクトを渡せる
  • 文字列では第2引数に文字エンコードを指定できる。デフォルトはutf-8
  • 返信はendで明示的に終える必要がある
POSTリクエスト処理
  • HTTPのリクエストボディのデータを、dataイベントを使って非同期に読み込む
  • デフォルトではBufferオブジェクトで受け取るが、事前にsetEncodingメソッド文字コードを指定すると文字列で得られる
  • 受け取ったデータをフィールド名とフィールド値に変換するのはquerystringモジュールの関数を利用
  • 個別のデータはformdata['fieldname']のようにアクセスできる
  • endイベントでデータの読み込みの終わりを検出できる

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は不要

HTTPS処理

  • p509 少し準備が必要
opensslコマンドを使う自己証明書の発行方法
  • 指定のコマンドで秘密鍵と公開鍵を生成しておく
  • Node.jsで作成した鍵の名前を指定する
HTTPSサーバ
  • HTTPSサーバ例。秘密鍵と公開鍵を読める場所に配置して実行
  • curl の-kオプションを指定すると、識別名等がいい加減でもエラーにしないオプション。通信の暗号化だけが目的であればこれで動作する
  • p510 HTTPSのクライアント側は、require('http')をrequire('https')に書き換えるだけ

Socket.IOとWebSocket

  • Part4ではwebsocket-serverパッケージを使ったが、ここではSocket.IOパッケージを利用
  • Socket.IOはWebSocketを含めたリアルタイム通信を提供するパッケージ
  • http://socket.io
  • パッケージをnpmでインストールすると、Node.jsを使うサーバサイドJavaScript向けライブラリと、Webブラウザ上で動くクライアントサイドJavaScript向けライブラリがセット
  • 一度接続が成立すれば、対照的に送受信可能
  • p511 プログラム例

低レイヤのネットワークプログラミング

低レイヤネットワーク処理
  • p512 TCP,UDPソケットや、名前解決ができる
ソケットとは
  • ソケットはストリームそのもの
  • 書き込んだデータを相手が読むかや、読もうとしたデータを相手が送っているかが保証されないのがファイルやメモリのストリームとは違う
  • ソケットの種別
    • ソケットを使うには通信相手と接続を確立する。相手先(相手機材)をIPアドレス、接続相手の識別(プロセス)にポート番号
    • ソケットにはサーバとクライアントという区分けはなく、接続を待ち受けるソケットと、接続にいくソケットがある
    • 受動的なソケットでは、相手から接続するターゲットとなるので、ポート番号を自分で指定する
    • 能動的ソケットのポート番号はなんでも良いので、空いているポート番号からシステムが自動的に選ぶように指定できる
  • ソケットの動作
    • p513 能動的なソケットから受動的なソケットへ接続を開始し、接続が成立すると受け入れソケットを自動で生成する
    • 接続が成立すると、能動的ソケットと受け入れソケットは対照的にデータの送受信ができるようになる
    • やりとりするのは、能動的ソケットと、受け入れソケット。受動的ソケットは待ち受けに使うのみ
    • 通信の終了は、いずれかがソケットを閉じれば良い
    • 受動的ソケットは残っている。別のクライアントから接続があれば、新しい受け入れソケットを作成して接続を行う。受動的ソケットを持つPCは、複数のクライアントと接続される
ソケットプログラミングの基本構造
  • net.createServer()を読んで、net.Serverオブジェクトを得る
  • listen()メソッドで接続待ち開始
  • connectionイベントハンドラで、クライアントとの接続を受け入れたソケットを得る
  • writeメソッドで書き込み、dataイベントで読み取り
  • closeやerrorイベントで接続終了
  • closeメソッドで接続を閉じる
  • クライアント側
    • p514 net.createConnection()メソッドを呼んで、net.Socketオブジェクトを得る。これが能動的ソケット
    • connectメソッドでサーバ接続
    • connectイベントで接続成功を扱う
    • writeメソッドで書き込み、dataイベントで読み取り
    • closeイベントやerrorイベントで接続が閉じたことを確認
    • closeメソッドで接続を閉じる
  • net.Socketクラスのプロパティとイベント一覧
p515 ソケットプログラミングの具体例

ファイル処理

  • p516 Node.jsのファイル処理にはfsモジュールを、ファイルパス関係の処理にはpathモジュールを使う
  • ファイル処理の関数には同期版と非同期版がある
  • Node.jsのネットワークは全てノンブロッキングで非同期関数
本節のサンプルコード
ファイルの非同期処理
  • ファイルのstat関数を非同期に呼び出すコード例
ファイルの同期処理
  • p518 戻り値で結果が得られる
ファイル操作系の関数
  • Unix系の前提。他OSへの移植性は書籍の段階では低い
ファイル読み込み
  • p519 ファイルの非同期読み込み例
  • 非同期処理はコードが読みづらい
  • パフォーマンスに問題がなければ、ファイル読み込みは同期的に読み込むのも手段
  • p520 簡易APIのreadFileとreadFileSyncがある
ファイル書き込み
  • 例示はしていないが、writeメソッドは例外を発生しうるので注意
  • p521 簡易APIはwriteFileとwriteFileSync
ディレクトリ操作
  • ディレクトリ操作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でいうとJSPPHPはそのものがテンプレート言語
  • 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の実例
  • p531 事前のテーブル設計(スキーマ定義)は不要だが、Mongooseはスキーマ定義を書くのが流儀
  • saveメソッドでオブジェクトを保存できる
  • p532 MongooseでMongoDBのドキュメント一覧を表示するコード例
  • findメソッドでフィールド値を検索できる
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メソッドを使う


前へ