2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

js初心者のnode.js自習メモ(2)アップローダを作ろう②~ルータ構成とURLのパース+おまけ~

Posted at

#これまでのあらすじ
js初心者のnode.js自習メモ(1)
js初心者のnode.js自習メモ(2)アップローダを作ろう①~全体の見通し~

前回、全体の構成は4ファイルでアップローダつくるぜ!
ということでで今回はちゃっちゃか行きます。

  1. exportsとrequireを使ってファイルの分け方を確認します
  2. 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()
// 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
//index.js
var server = require("./server"); //server.jsの呼び出し

server.start();

#パース結果の確認
ローカルホストの/startにリクエストしたキャプチャです。
ブラウザでもコンソールログでも正しく動作しています。
キャプチャに入れ忘れましたがnodeのバージョンはv0.10.26です。
cap1.JPG

もう少し長いパスにリクエストしてみます。
cap2.JPG

次はクエリを混ぜてみます。
パス部分だけ抽出できてますね。
cap3.JPG

#ルータ構造をつくる
URLをパースできるようになったので、それをルータに渡す構造を作ります。
ルータはパスをみて、リクエストに合った動作をする関数を呼ぶのがお仕事。
うーん、手配師かな?

とりあえず、今回はそこまで作らず、ちゃんとパスが渡せることを確認します。
index.js, server.js, router.jsの3つを動作させます。

router.js
//router.js
function route( pathname ){
	console.log( "About to route a request for " + pathname );
}

exports.route = route;
server_ver2.js
// 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_ver2.js
//index.js
var server = require("./server"); //server.jsの呼び出し
var router = require("./router"); //router.jsの呼び出し

server.start(router.route); //route関数を引数にする

たいしたことやってないし説明カット。

##確認
cap4.JPG

リクエストパス /aiueo が関数routeまで伝達できています。
次回はこいつを使って、URLに合った動作をさせます。

#querystring.parseでつまづいた話
URLを取り扱うurlモジュールと同様に、
queryを取り扱うquerystringモジュールがあるんですが、
これのparseでちょっとつまづいた。
くだらないけどアウトプットしておきます。

##問1:次の(アホな)間違いを指摘せよ
次の間違い、パッとわかります?

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(request.url).foo;
var fuck     = querystring.parse(request.url).suck;

##デバッグしてみる
何処の記述がおかしいかわかりましたか?
結果としてどうなるかわかりますか?
それでは動作させてみたキャプチャを確認してみましょう。

cap5.JPG

コンソール出力を見ると、1番目のパラメータfooの値だけ
undefinedになってますね。まれによくあるやつだ。

nodeをインタプリタ実行環境として使って確認してみましょう。
端末から $ node でnode単体で起動して
> var query = require("querystring");
querystringを呼び出して動作を確認します。

a=1&b=2&c=3を引数にしたときと、
abc?a=1&b=2&c=3を引数にしたときの違いは以下のとおり。
cap0.JPG

うーん、さっきと同じ現象が再現してますね・・・?
URLやパスとつながったまま渡すとおかしくなるようです。

(゜-゜)…

…( ゚д゚)ハッ!

cap6.JPG

1個目のパラメータ名が?でスライスされてない…じゃん…
そりゃあ1個目のパラメータだと思ってたものが、
「ない」んだからundefined返ってきますよね。
URLでも動いてくれるとか勘違い良くない。
プログラマが優しいわけがない。(優しくないのも優しさか?)

ということで、
querystringはURLが引数として渡されるのを想定していない
ということがわかりました。そりゃそうだ。

#答え合わせ
と、いうことで、parse_ng.jsを正しく動かすには、
次の記述にしないといけません。

parse_ok.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にパースしてから使う

cap8.JPG

#ドキュメントをちゃんと読もう。
Node.js v5.7.1 Documentationquerystring.js をパラっと見ると
?より前を捨てたりしてくれません。
デフォルトセパレータは=と&だよってちゃんと書いてます。

クエリにしてから渡しましょう。
ちゃんちゃん。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?