#これまでのあらすじ
js初心者のnode.js自習メモ(1)
js初心者のnode.js自習メモ(2)アップローダを作ろう①~全体の見通し~
前回、全体の構成は4ファイルでアップローダつくるぜ!
ということでで今回はちゃっちゃか行きます。
- exportsとrequireを使ってファイルの分け方を確認します
- URLをパースするところを作ります
#require("module")
httpサーバをつくるときにすでにモジュールの呼び出しはやってますね。
var http = require("http");
でhttpモジュールを呼び出します。
ユーザモジュールを使う場合は次のようにファイルパスを記述します。
var foo = require("./bar");
拡張子.js
は省略していいみたいです。
省略すべきかどうかは一考の余地ありですが。
ところでnodeではモジュールって呼ぶんですかね。
個人的にはライブラリと何が違うのかなって思いますが。
#exports.function
今度は、呼び出される側に以下の記述をします。
exports.foo = bar;
これで
「function bar()
を外部モジュールでfunction foo()
として使っていいよ」
という意味合いになります。
#urlモジュール
便利なことにURLにいろんなことできるurlモジュールがあるので使います。
これでpathnameとqueryを分けてルータに投げれば大まかな仕組みはできそうです。
urlモジュールを呼び出して、pathnameを抽出するためにparseを使い
リクエストされたpathnameをプレーンテキストで返すhttpサーバにしてみます。
// server.js
var http=require("http");
var url =require("url"); //url文字列の抽出をする
function start(){
function onRequest( request, response ){
//urlのリクエストパス抽出
var pathname = url.parse(request.url).pathname;
console.log("Request for "+ pathname +" recieved.");
response.writeHead(200,{"Content-Type": "text/plain"});
response.write("your request is \""+ pathname +"\"");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;
ついでにstart()を外部から使えるようにしているので、
index.jsから呼び出して使いましょう。
//index.js
var server = require("./server"); //server.jsの呼び出し
server.start();
#パース結果の確認
ローカルホストの/startにリクエストしたキャプチャです。
ブラウザでもコンソールログでも正しく動作しています。
キャプチャに入れ忘れましたがnodeのバージョンはv0.10.26です。
#ルータ構造をつくる
URLをパースできるようになったので、それをルータに渡す構造を作ります。
ルータはパスをみて、リクエストに合った動作をする関数を呼ぶのがお仕事。
うーん、手配師かな?
とりあえず、今回はそこまで作らず、ちゃんとパスが渡せることを確認します。
index.js, server.js, router.jsの3つを動作させます。
//router.js
function route( pathname ){
console.log( "About to route a request for " + pathname );
}
exports.route = route;
// server.js
var http=require("http");
var url =require("url");
function start(route){
function onRequest( request, response ){
//urlのリクエストパス抽出
var pathname = url.parse(request.url).pathname;
console.log("Request for "+ pathname +" recieved.");
route( pathname ); //パスをルータに渡す
response.writeHead(200,{"Content-Type": "text/plain"});
response.write("your request is \""+ pathname +"\"");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;
//index.js
var server = require("./server"); //server.jsの呼び出し
var router = require("./router"); //router.jsの呼び出し
server.start(router.route); //route関数を引数にする
たいしたことやってないし説明カット。
リクエストパス /aiueo が関数routeまで伝達できています。
次回はこいつを使って、URLに合った動作をさせます。
#querystring.parseでつまづいた話
URLを取り扱うurlモジュールと同様に、
queryを取り扱うquerystringモジュールがあるんですが、
これのparseでちょっとつまづいた。
くだらないけどアウトプットしておきます。
##問1:次の(アホな)間違いを指摘せよ
次の間違い、パッとわかります?
var url =require("url"); //url文字列の抽出をする
var querystring =require("querystring"); //query文字列の抽出をする
var pathname = url.parse(request.url).pathname;
var query = url.parse(request.url).query;
var foo = querystring.parse(request.url).foo;
var fuck = querystring.parse(request.url).suck;
##デバッグしてみる
何処の記述がおかしいかわかりましたか?
結果としてどうなるかわかりますか?
それでは動作させてみたキャプチャを確認してみましょう。
コンソール出力を見ると、1番目のパラメータfooの値だけ
undefinedになってますね。まれによくあるやつだ。
nodeをインタプリタ実行環境として使って確認してみましょう。
端末から $ node
でnode単体で起動して
> var query = require("querystring");
で
querystringを呼び出して動作を確認します。
a=1&b=2&c=3
を引数にしたときと、
abc?a=1&b=2&c=3
を引数にしたときの違いは以下のとおり。
うーん、さっきと同じ現象が再現してますね・・・?
URLやパスとつながったまま渡すとおかしくなるようです。
(゜-゜)…
…( ゚д゚)ハッ!
1個目のパラメータ名が?でスライスされてない…じゃん…
そりゃあ1個目のパラメータだと思ってたものが、
「ない」んだからundefined返ってきますよね。
URLでも動いてくれるとか勘違い良くない。
プログラマが優しいわけがない。(優しくないのも優しさか?)
ということで、
querystringはURLが引数として渡されるのを想定していない
ということがわかりました。そりゃそうだ。
#答え合わせ
と、いうことで、parse_ng.jsを正しく動かすには、
次の記述にしないといけません。
var url =require("url"); //url文字列の抽出をする
var querystring =require("querystring"); //query文字列の抽出をする
var pathname = url.parse(request.url).pathname;
var query = url.parse(request.url).query;
var foo = querystring.parse(query).foo; //queryにパースしてから使う
var fuck = querystring.parse(query).suck; //queryにパースしてから使う
#ドキュメントをちゃんと読もう。
Node.js v5.7.1 Documentationやquerystring.js をパラっと見ると
?より前を捨てたりしてくれません。
デフォルトセパレータは=と&だよってちゃんと書いてます。
クエリにしてから渡しましょう。
ちゃんちゃん。