-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
index-jp.html
3455 lines (3054 loc) · 252 KB
/
index-jp.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
<head>
<?php require_once('_defaultheaders.php'); ?>
<title>Nodeビギナーズブック » Node.jsチュートリアル » Node.js 教程</title>
<meta name="description" content="本書は、Node.jsでのアプリケーション開発を始めようとする皆さんに、”高度な”JavaScriptについて知るべきあらゆることを解説します。よくある”Hello World”チュートリアルの、はるか上をいくものです。" />
<link rel="stylesheet" type="text/css" href="olddefault.css" />
<link rel="canonical" href="https://www.nodebeginner.org/index-jp.html" />
<?php require_once('_hreflang.php'); ?>
<style type="text/css">
body {
font-family: "MS P明朝", "ヒラギノ明朝 ProN W3","Hiragino Mincho ProN", Georgia, serif;
}
</style>
<script type="text/javascript">
// Disqus
var disqus_shortname = 'nodebeginner';
var disqus_identifier = 'nodebeginner-book-japanese';
var disqus_url = 'https://www.nodebeginner.org/index-jp.html';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'https://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
// CSS browser select
function css_browser_selector(u){var ua=u.toLowerCase(),is=function(t){return ua.indexOf(t)>-1},g='gecko',w='webkit',s='safari',o='opera',m='mobile',h=document.documentElement,b=[(!(/opera|webtv/i.test(ua))&&/msie\s(\d)/.test(ua))?('ie ie'+RegExp.$1):is('firefox/2')?g+' ff2':is('firefox/3.5')?g+' ff3 ff3_5':is('firefox/3.6')?g+' ff3 ff3_6':is('firefox/3')?g+' ff3':is('gecko/')?g:is('opera')?o+(/version\/(\d+)/.test(ua)?' '+o+RegExp.$1:(/opera(\s|\/)(\d+)/.test(ua)?' '+o+RegExp.$2:'')):is('konqueror')?'konqueror':is('blackberry')?m+' blackberry':is('android')?m+' android':is('chrome')?w+' chrome':is('iron')?w+' iron':is('applewebkit/')?w+' '+s+(/version\/(\d+)/.test(ua)?' '+s+RegExp.$1:''):is('mozilla/')?g:'',is('j2me')?m+' j2me':is('iphone')?m+' iphone':is('ipod')?m+' ipod':is('ipad')?m+' ipad':is('mac')?'mac':is('darwin')?'mac':is('webtv')?'webtv':is('win')?'win'+(is('windows nt 6.0')?' vista':''):is('freebsd')?'freebsd':(is('x11')||is('linux'))?'linux':'','js'];c=b.join(' ');h.className+=' '+c;return c;};css_browser_selector(navigator.userAgent);
</script>
</head>
<body>
<img style="display: none;" src="the_node_beginner_book_cover_medium.png" height="256" width="171" />
<div id="forkmeongithub">
<a href="https://github.com/ManuelKiessling/NodeBeginnerBook"><img src="fork_me_on_github.png" width="149" height="149" alt="Fork me on GitHub" /></a>
</div>
<div id="translations">
<table>
<tr>
<td>
<a href="./">
<div class="flag"><img src="us-flag.png" width="24" height="24" alt="usa flag" /></div>
<div class="text">Read this tutorial in english</div>
</a>
</td>
<td>
<a href="index-es.html">
<div class="flag"><img src="es-flag.png" width="24" height="24" alt="spanish flag" /></div>
<div class="text">Lee este tutorial en Español</div>
</a>
</td>
<td>
<a href="index-kr.html">
<div class="flag"><img src="kr-flag.png" width="24" height="24" alt="korean flag" /></div>
<div class="text">이 튜토리얼을 한글로 보세요</div>
</a>
</td>
</tr>
<tr>
<td>
<a href="index-zh-cn.html">
<div class="flag"><img src="cn-flag.png" width="24" height="24" alt="chinese flag" /></div>
<div class="text">阅读本书中文版</div>
</a>
</td>
<td>
<a href="index-zh-tw.html">
<div class="flag"><img src="tw-flag.png" width="24" height="24" alt="traditional chinese flag" /></div>
<div class="text">閱讀本書繁體中文版</div>
</a>
</td>
<td>
<a href="http://www.nodebeginner.ru">
<div class="flag"><img src="ru-flag.png" width="24" height="24" alt="russian flag" /></div>
<div class="text">Читать этот учебник на русском</div>
</a>
</td>
</tr>
<tr>
<td>
<a href="index-vi.html">
<div class="flag"><img src="vi-flag.png" width="24" height="24" alt="vietnamese flag" /></div>
<div class="text">Đọc bằng tiếng Việt</div>
</a>
</td>
<td>
</td>
<td>
</td>
</tr>
</table>
</div>
<div class="buybox">
<div class="buy-the-bundle">
<div class="cover">
<p>
The perfect introduction plus the perfect reference in one bundle!
</p>
<a href="https://leanpub.com/b/node-beginner-and-craftsman-bundle"><img src="the_node_beginner_book_cover_small.png" height="86" width="57" /></a>
<a href="https://leanpub.com/b/node-beginner-and-craftsman-bundle"><img src="hands-on_node.js_cover.png" height="86" width="57" /></a>
</div>
<div class="description">
<p>
LeanBundle currently offers<br />
the final version of
<br />
<strong>The Node Beginner Book</strong>
<br />
plus Pedro Teixeira's excellent
<br />
<strong>Hands-on Node.js</strong> for only
<br />
<br />
<strong class="price dollarsign">$</strong><strong class="price">9.99</strong>
<br />
(regular price <del>$21.98</del>)
</p>
</div>
<div class="buy">
<p>
226 pages in total
<br />
PDF, ePub & MOBI
<br />
Direct download
<br />
Free updates
</p>
<a class="buttonlink" href="https://leanpub.com/b/node-beginner-and-craftsman-bundle">
<div class="button">Buy this<br />bundle now</div>
</a>
</div>
</div>
</div>
<div id="book">
<h1>Nodeビギナーズブック</h1>
<div id="author">
A Node.js tutorial by <a href="https://twitter.com/manuelkiessling">Manuel Kiessling</a>
<br>
Translated by <a href="http://il-all.blogspot.com/">Yuki Kawashima</a>
</div>
<a name="about"></a>
<h2>本書について</h2>
<p>
本書は、Node.jsでのアプリケーション開発を始めようとする皆さんに、
”高度な”JavaScriptについて知るべきあらゆることを解説します。
よくある”Hello World”チュートリアルの、はるか上をいくものです。
</p>
<a name="status"></a>
<h3>ステータス</h3>
<p>
貴方が読んでいるのは、本書のいわゆる最終版となります。
つまり本書は、間違いが見つかった場合や、
Node.jsの新バージョンにおえる変更点を反映する時のみ、改訂されます。
最終更新日は2012年2月12日です。
</p>
<p>
本書内のコードのサンプルは、Node.jsのバージョン0.6.10でテストしています。
</p>
<a name="intended-audience"></a>
<h3>ターゲット読者</h3>
<p>
本書は、Ruby、Python、PHP、Javaのような、少なくともひとつのオブジェクト指向言語を理解しており、
JavaScriptについてはあまり経験がなく、Node.jsについては全く経験がないという、
著者と同じようなバックグラウンドをもつ読者にとって最もフィットする内容となっています。
</p>
<p>
何かしらのプログラミング言語を経験しているデベロッパー向けですので、
本書はデータ型や変数、制御構造などの本当に基本的な事柄はカバーしないということになります。
本書を理解するためには、そのような基本的な事柄は読み進める時点で理解している必要があります。
</p>
<p>
ただし、JavaScriptの関数やオブジェクトは他の言語のものと異なるので、より詳細に解説していきます。
</p>
<a name="structure"></a>
<h3>本書の構造</h3>
<p>
本書を読み終わる頃には、貴方はひとつのWebアプリケーションを完成させることになります。
そのWebアプリケーションでは、ユーザがWebページを閲覧し、ファイルをアップロードすることができます。
</p>
<p>
もちろん、世界を変えるようなものができるわけではないですが、
これらの機能を実現するために”必要最低限”のコードを書くだけではありません。
さらに一歩先へ進み、アプリケーションの持ついくつかの相違点をきれいに分離した、
シンプルだけれども完全なフレームワークを作りあげることができます。
私が言わんとしていることは、すぐにわかることでしょう。
</p>
<p>
まずはNode.jsを使ったJavaScriptでの開発は、
ブラウザ内のJavaScriptの開発と何が違うのかを見てみるところから始めます。
</p>
<p>
次に、古き良き伝統として”Hello World”アプリケーションを作ります。
これは確かに”何かをする”、最も基本的なNode.jsのアプリケーションです。
</p>
<p>
そして、私たちが構築したいと考えている”現実の”アプリケーションの種類について議論します。
このアプリケーションを組み立てるために実装が必要となるパーツを分解し、
それぞれのパーツをステップバイステップで作っていきます。
</p>
<p>
約束通り、これらを通してJavaScriptのより先進的なコンセプトを知り、どう活用し、
そしてなぜ他のプログラミング言語とは異なるコンセプトが意味をなすのかを学ぶことになります。
</p>
<p>
完成したアプリケーションのソースコードは
<a href="https://github.com/ManuelKiessling/NodeBeginnerBook/tree/master/code/application">NodeBeginnerBook Githubリポジトリ</a>
からダウンロードできます。
</p>
<div id="table-of-contents-headline">目次</div>
<div id="table-of-contents">
<ul>
<li><a href="#about">本書について</a>
<ul>
<li><a href="#status">ステータス</a></li>
<li><a href="#intended-audience">ターゲット読者</a></li>
<li><a href="#structure">本書の構造</a></li>
</ul>
</li>
<li><a href="#javascript-and-nodejs">JavaScriptとNode.js</a>
<ul>
<li><a href="#javascript-and-you">JavaScriptと貴方</a></li>
<li><a href="#a-word-of-warning">注意事項</a></li>
<li><a href="#server-side-javascript">サーバサイドJavaScript</a></li>
<li><a href="#hello-world">"Hello World"</a></li>
</ul>
</li>
<li><a href="#a-full-blown-web-application-with-nodejs">Node.jsでの本格的なWebアプリケーション</a>
<ul>
<li><a href="#the-use-cases">ユースケース</a></li>
<li><a href="#the-application-stack">アプリケーションスタック</a></li>
</ul>
</li>
<li><a href="#building-the-application-stack">アプリケーションスタックの構築</a>
<ul>
<li><a href="#a-basic-http-server">基本的なHTTPサーバ</a></li>
<li><a href="#analyzing-our-http-server">HTTPサーバの分析</a></li>
<li><a href="#passing-functions-around">関数をあちこちに渡す</a></li>
<li><a href="#how-function-passing-makes-our-http-server-work">関数渡しでHTTPサーバを動かす方法</a></li>
<li><a href="#event-driven-callbacks">イベント駆動コールバック</a></li>
<li><a href="#how-our-server-handles-requests">サーバによるリクエストの取り扱い方</a></li>
<li><a href="#finding-a-place-for-our-server-module">サーバモジュールの場所の確保</a>
</li>
<li><a href="#whats-needed-to-route-requests">リクエストを”ルーティング”するために必要なものは?</a></li>
<li><a href="#execution-in-the-kongdom-of-verbs">動詞王国での実行</a></li>
<li><a href="#routing-to-real-request-handlers">本当のリクエストハンドラへのルーティング</a></li>
<li><a href="#making-the-request-handlers-respond">リクエストハンドラによる応答</a>
<ul>
<li><a href="#how-to-not-do-it">うまくいかない方法</a></li>
<li><a href="#blocking-and-non-blocking">ブロッキングとノンブロッキング</a></li>
<li><a href="#responding-request-handlers-with-non-blocking-operations">ノンブロッキング操作で応答するリクエストハンドラ</a>
</li>
</ul>
</li>
<li><a href="#serving-something-useful">有益なものを提供する</a>
<ul>
<li><a href="#handling-post-requests">POSTリクエストの扱い</a></li>
<li><a href="#handling-file-uploads">ファイルアップロードの扱い</a></li>
</ul>
</li>
<li><a href="#conclusion-and-outlook">まとめと展望</a></li>
</ul>
</li>
</ul>
</div>
<a name="javascript-and-nodejs"></a>
<h2>JavaScriptとNode.js</h2>
<a name="javascript-and-you"></a>
<h3>JavaScriptと貴方</h3>
<p>
技術的な話に入る前に、貴方とJavaScriptの関係について話をしておきましょう。
本章は、この文書をさらに読み進めることが貴方にとって意味があるのか、判断してもらいたいのです。
</p>
<p>
もし貴方が私と同じであれば、はるか昔HTMLの文書を書いてHTMLでの”開発”を始めたはずです。
JavaScriptと呼ばれるなんだか面白そうなものに出会い、
つまり貴方のWebページに相互作用を加えるような、とても基本的な使い方だけで利用していたことでしょう。
</p>
<p>
貴方はもっと”本物”が欲しくなり、複雑なWebサイトを構築する方法を学びたくてPHP、
Ruby、Javaなどのプログラミング言語を勉強し、
”バックエンド”となるコードを書き始めたのではないでしょうか。
</p>
<p>
それにも関わらず、JavaScriptに注目してみるとjQueryやPrototypeなどが目に入ってきました。
JavaScriptの世界では物事が進化し、もはやこの言語は、<em>window.open()</em>では済まないのだ、
ということがわかってきたのです。
</p>
<p>
しかしそれは序章に過ぎません。jQueryを自由に扱えればWebページにスパイスを加えることができますが、
結局のところ貴方はまだ、JavaScriptの<em>ユーザ</em>でしかなく、
<em>デベロッパー</em>ではなかったのです。
</p>
<p>
そしていま、Node.jsにたどり着きました。サーバ側でのJavaScriptって、凄いの?
</p>
<p>
そろそろ、古くて新しいJavaScriptをチェックする時期がきたことを確信しました。
でもちょっと待って、Node.jsアプリケーションを書くというのはとても厄介。
なぜそうやって書く必要があるのか、理解しないといけない、
つまりJavaScriptを理解しなければいけないのです。今度こそ、真剣に。
</p>
<p>
ここで問題があります。JavaScriptには2つ、
もしかすると3つの時代があるため(90年代半ばの小さくて可愛らしいDHTMLの助っ人、
jQueryなどのもう少し真剣なフロントエンド、そして現在のサーバサイド)、
JavaScriptを利用するのではなくてJavaScriptで開発しているのだと感じさせてくれるような、
”正しい”使い方を示す情報を探すのは容易ではありません。
</p>
<p>
貴方は経験豊富なデベロッパーなのですから、
なんとなく時間を無駄に過ごしたり間違った使い方をしたりして新しいテクニックを身につけたい、
なんていうことはないでしょう。しっかりと正しい角度でアプローチしていきたいはずです。
</p>
<p>
もちろん素晴らしい文書はそこら中にあります。しかし一つの文書では十分でないこともあります。
必要なのはガイダンスなのです。
</p>
<p>
私の目的は、貴方にガイドを提供することなのです。
</p>
<a name="a-word-of-warning"></a>
<h3>注意事項</h3>
<p>
世の中には本当に素晴らしいJavaScriptエンジニアがいます。でも私は違います。
</p>
<p>
本当に、私は前段で述べたような男に過ぎません。
バックエンドのWebアプリケーションを1つや2つ知っているだけで、
まだまだ”本当の”JavaScriptは学び始めたばかりですし、Node.jsについても同じです。
JavaScriptのより先進的な側面を学んだのは最近で、経験も豊富ではありません。
</p>
<p>
ですので、本書は”初心者から上級者へ”なるためのではなくて、
どちらかというと”初心者から初級者へ”というものです。
</p>
<p>
私がNode.jsを学び始めた時にあったらよかった、そんな文書になっているはずです。
</p>
<a name="server-side-javascript"></a>
<h3>サーバサイドJavaScript</h3>
<p>
最初にJavaScriptが日の目を見たのは、ブラウザ上でした。
しかしこれは単なるコンテキストに過ぎません。
コンテキストによってその言語でできることは決まってきますが、
それはその言語自体ができることとイコールというわけではありません。
JavaScriptは”完全な”言語であり、様々なコンテキストで使えます。
他の言語でやっていることは、すべてJavaScriptでもできます。
</p>
<p>
Node.jsもまた、ひとつのコンテキストに過ぎません。
Node.jsによって、JavaScriptはバックエンド、ブラウザの外で動作できるのです。
</p>
<p>
バックエンドでJavaScriptが動作するには、インタープリターで変換され、
そして実行されなければなりません。これをNode.jsが行います。
内部ではGoogleのV8 VMが利用されています。
V8 VMはGoogle Chromeが使用しているJavaScriptの実行環境そのものと同じです。
</p>
<p>
それに加えて、Node.jsにはたくさんの便利なモジュールが同梱されています。
全てを1から作る必要はないのです。例えばコンソールに文字列を出力するモジュールなどがあります。
</p>
<p>
つまりNode.jsは、実行環境とライブラリの2つから成っているのです。
</p>
<p>
さて、これを使うためには、Node.jsをインストールする必要があります。
<a href="https://github.com/joyent/node/wiki/Installation" title="Building and Installing Node.js">公式サイトのインストール手順</a>を訪れて、またここに戻ってきて下さい。
</p>
<a name="hello-world"></a>
<h3>"Hello World"</h3>
<p>
OK、では冷水に飛び込んで、
はじめてのNode.jsアプリケーション”Hello World”を書いてみるとしましょう。
</p>
<p>
好きなエディタを選んだら、<em>helloworld.js</em>というファイル名で保存して下さい。
このアプリケーションでは”Hello World”を標準出力に書き出します。コードはこの通りです:
</p>
<pre class="prettyprint lang-js"><span class="pln">console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span></pre>
<p>
ファイルを保存して、Node.jsから動かしてみます:
</p>
<pre>node helloworld.js</pre>
<p>
これで貴方の端末で、<em>Hello World</em>と出力されたはずです。
</p>
<p>
いやあ、退屈ですね。次はもっと本物っぽいものを書いてみましょう。
</p>
<a name="a-full-blown-web-application-with-nodejs"></a>
<h2>Node.jsでの本格的なWebアプリケーション</h2>
<a name="the-use-cases"></a>
<h3>ユースケース</h3>
<p>
シンプルに、しかし現実的に考えてみましょう:
</p>
<ul>
<li>
ユーザは、我々のアプリケーションをWebブラウザから使えるべき
</li>
<li>
ユーザは、http://<em>domain</em>/startにアクセスしたらウェルカムページを見ることができ、
そこではファイルアップロードフォームが表示される
</li>
<li>
アップロードする画像ファイルを選択して送信すると、
画像がhttp://<em>domain</em>/uploadにアップロードされ、
アップロードが一旦完了したらそこに表示される
</li>
</ul>
<p>
結構です。Googleで検索して、<em>何か</em>組み合わせていけばできてしまうでしょう。
でもここでやりたいのはそういうことではないのです。
</p>
<p>
目的を達成するためだけの最も基本的なコードだけを書く、それをやりたいだけではないのです。
綺麗で正確なコードを書きたいのです。
ここからは、もっと複雑なNode.jsアプリケーションを構築していく時の感覚を得るために、
わざと必要以上に抽象的にしていきます。
</p>
<a name="the-application-stack"></a>
<h3>アプリケーションスタック</h3>
<p>
それではアプリケーションを分解していきましょう。
やりたいことを満たすためには、一体どんなものを実装したら良いのでしょうか。
</p>
<ul>
<li>
Webページを提供したい。よって<strong>HTTPサーバ</strong>が必要
</li>
<li>
我々のサーバでは、リクエストが要求しているURLによってそれぞれ別に応答する必要がある。
よってリクエストをリクエストハンドラに結びつけるための<strong>ルータ</strong>のようなものが必要
</li>
<li>
サーバに届き、ルータによって渡されたリクエストの内容に応えるために、
<strong>リクエストハンドラ</strong>が必要
</li>
<li>
ルータはどんなPOSTデータでも取り扱えるべきで、
そのデータをリクエストハンドラに使い易い形式で渡す必要がある。
よって<strong>リクエストデータハンドリング</strong>が必要
</li>
<li>
URLへのリクエストだけを扱いたいのではなく、
それらのURLが要求された時に内容を表示したい。
つまり、コンテンツをユーザのブラウザへ送り返すための、
リクエストハンドラから利用できる<strong>ビューロジック</strong>が必要
</li>
<li>
ユーザは画像をアップロードできるようになるため、何らかの形で、
細かい部分の面倒を見る<strong>アップロードハンドリング</strong>が必要
</li>
</ul>
<p>
ちょっと考えてみて下さい。PHPでこのスタックを作り上げるとしたら、
どうやって実現するでしょうか。何も隠すことはないので言ってしまうと、
だいたいApache HTTPサーバとmod_php5をインストールするのでしょう。
<br>
そう考えると、”Webページを提供して、HTTPリクエストに応答する必要がある”
という部分については、PHPの中で起きているわけではないことに気づきます。
</p>
<p>
さて、nodeの場合、状況が少し異なります。Node.jsでは、
アプリケーションのみを実装するのではなく、HTTPサーバ全体を実装することになります。
我々がこれから作ろうとしているWebアプリケーションとWebサーバは基本的に同一のものなのです。
</p>
<p>
もしかすると大変そうな印象を持たれてしまったかもしれませんが、
Node.jsでは、そうでもないことがすぐにわかるはずです。
</p>
<p>
それではスタックの最初の部分である、HTTPサーバから始めてみましょう。
</p>
<a name="building-the-application-stack"></a>
<h2>アプリケーションスタックの構築</h2>
<a name="a-basic-http-server"></a>
<h3>基本的なHTTPサーバ</h3>
<p>
はじめて私が”本当の”Node.js”アプリケーションを作り始めようとした時は、
どうやってコードを書くのかわかりませんでしたし、コードをどう構成したら良いかもわかりませんでした。
<br>
1つのファイルに全てを書くので良いのでしょうか。Webで見つかるチュートリアルではほとんどの場合で、
Node.jsの基本的なHTTPサーバが、全てのロジックを1カ所で持っているようなものでした。
次の機能を実装しようとした時、コードの可読性を維持することは果たしてできるのでしょうか。
</p>
<p>
モジュールを使えば、やりたいこと別にコードを分離することは、
比較的簡単だということがわかりました。
</p>
<p>
そうすることで、Node.jsで実行するメイン部分のファイルを綺麗な状態に保つことができます。
また、メインファイルから使ったりモジュール同士で相互利用したりするモジュールも、
すっきりさせることができます。
</p>
<p>
アプリケーションを起動するためのメインファイルと、
HTTPサーバのコードから利用されるモジュールファイルを作りましょう。
</p>
<p>
私の印象では、メインファイルには<em>index.js</em>という名前にするのが標準的です。
そしてサーバモジュールには<em>server.js</em>というファイル名を付けます。
</p>
<p>
では、サーバモジュールから始めます。このプロジェクトのルートディレクトリに<em>server.js</em>
という名前のファイルを作成します。ファイルの内容は以下の通りにします:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br>http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">(</span><span class="kwd">function</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br> response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br> response</span><span class="pun">.</span><span class="pln">write</span><span
class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span><span
class="pln"><br> response</span><span class="pun">.</span><span class="pln">end</span><span
class="pun">();</span><span class="pln"><br></span><span class="pun">}).</span><span
class="pln">listen</span><span class="pun">(</span><span class="lit">8888</span><span
class="pun">);</span></pre>
<p>
これだけです!これで実際に動くHTTPサーバが書けました。
実行して、ちゃんと動くかテストしてみましょう。
まず、このスクリプトをNode.jsから実行します:
</p>
<pre>node server.js</pre>
<p>
それでは、ブラウザを開いて
<a href="http://localhost:8888/" rel="nofollow">http://localhost:8888/</a>
にアクセスしてみましょう。
”Hello World”と表示しているWebページが表示されるはずです。
</p>
<p>
これは、とても気になるのではないでしょうか。我々のプロジェクトをどう構成していくのか、
というテーマを少し離れて、この部分について深堀してみませんか。すぐに本題に戻ることを約束します。
</p>
<a name="analyzing-our-http-server"></a>
<h3>HTTPサーバの分析</h3>
<p>
ではでは、何が起こっていたのか、分析していきます。
</p>
<p>
最初の行で、<em>http</em>モジュールを<em>require</em>(要求)しています。
これにより、Node.jsに同梱されているhttpモジュールへのアクセスが、
変数<em>http</em>を通して可能になります。
</p>
<p>
次に、httpモジュールが提供する関数のひとつである<em>createServer</em>を呼出しています。
この関数はオブジェクトを返しますが、このオブジェクトが<em>listen</em>というメソッドを持っています。
listenメソッドはポート番号を数値の引数として受け取り、HTTPサーバがそのポート番号で待ち受けします。
</p>
<p>
今のところは<em>http.createServer</em>の括弧内にある関数定義の箇所は無視しておいて下さい。
</p>
<p>
もし8888番ポートで待ち受けするサーバを開始したければ、こんなコードでも良かったはずです:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">var</span><span
class="pln"> server </span><span class="pun">=</span><span class="pln"> http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">();</span><span
class="pln"><br>server</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span></pre>
<p>
これでHTTPサーバが8888番ポートで待ち受けをして、その他、何もすることはありません。
(たとえリクエストがきても応答さえしません)
</p>
<p>
(もしPHPのような、より保守的な言語の経験者であれば特に)面白いのは、
<em>createServer()</em>の呼出しの第1引数に関数定義があることではないでしょうか。
</p>
<p>
この関数の定義は、<em>createServer()</em>を呼び出す際に渡す最初の (そして最後の)引数なのです。
JavaScriptでは、関数をその他の値と同様、あちこちに渡すことができるのです。
</p>
<a name="passing-functions-around"></a>
<h3>関数をあちこちに渡す</h3>
<p>
例えばこんなことができてしまいます:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> say</span><span
class="pun">(</span><span class="pln">word</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br> console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span
class="pln">word</span><span class="pun">);</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> execute</span><span
class="pun">(</span><span class="pln">someFunction</span><span class="pun">,</span><span class="pln"> value</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br> someFunction</span><span
class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>execute</span><span
class="pun">(</span><span class="pln">say</span><span class="pun">,</span><span
class="pln"> </span><span class="str">"Hello"</span><span class="pun">);</span></pre>
<p>
よく読んでみて下さい!ここでは、関数<em>say</em>を<em>execute</em>関数の第1引数として渡しています。
<em>say</em>の戻り値ではなく、<em>say</em>自体を渡しているのです!
</p>
<p>
ここでは<em>say</em>が、関数<em>execute</em>の中にあるローカル変数
<em>someFunction</em>になっています。
そしてexecuteの中では(この変数に括弧をつけて)<em>someFunction()</em>
と書くことができるのです。
</p>
<p>
もちろん<em>say</em>は引数を1つとるので、
<em>execute</em>から<em>someFunction</em>を呼び出す時には、
さらに引数を渡すことができます。
</p>
<p>
このように、関数は、他の関数への引数として名前で渡すことができますが、
何も関数の定義を先にしたうえで、それを渡す、といった手順を踏まなくても良いのです。
関数は、関数を引数として渡す際、その場で定義しても良いのです:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> execute</span><span
class="pun">(</span><span class="pln">someFunction</span><span class="pun">,</span><span class="pln"> value</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br> someFunction</span><span
class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>execute</span><span
class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span
class="pln">word</span><span class="pun">){</span><span class="pln"> console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span
class="pln">word</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">},</span><span class="pln"> </span><span class="str">"Hello"</span><span
class="pun">);</span></pre>
<p>
まさに<em>execute</em>が第1引数を期待している場所で、<em>execute</em>
に渡したい関数を定義しています。
</p>
<p>
ここで見たやり方をすると、関数に名前をつけてやる必要がありません。
このような関数を<em>匿名関数(anonymous function)</em>と呼びます。
</p>
<p>
これは”上級の”JavaScriptと呼んでいるものの最たる例ですが、
ステップバイステップでやっていきましょう。
今のところ、JavaScriptでは関数を呼び出す時の引数として関数を渡すことができる、
ということを受け入れて下さい。
あらかじめ定義した関数を変数として割り当ててから渡すこともできますし、
その場で関数を定義して渡すこともできるのです。
</p>
<a name="how-function-passing-makes-our-http-server-work"></a>
<h3>関数渡しでHTTPサーバを動かす方法</h3>
<p>
今知った事を活用すれば、最低限のHTTPサーバをこんな風に書く事ができます:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br>http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">(</span><span class="kwd">function</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br> response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br> response</span><span class="pun">.</span><span class="pln">write</span><span
class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span><span
class="pln"><br> response</span><span class="pun">.</span><span class="pln">end</span><span
class="pun">();</span><span class="pln"><br></span><span class="pun">}).</span><span
class="pln">listen</span><span class="pun">(</span><span class="lit">8888</span><span
class="pun">);</span></pre>
<p>
もうここで何をしているのかは明確なはずです:
<em>createServer</em>関数に匿名関数として渡しているのです。
</p>
<p>
先のコードをリファクタリングすると、こうすることができます:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br> response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br> response</span><span class="pun">.</span><span class="pln">write</span><span
class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span><span
class="pln"><br> response</span><span class="pun">.</span><span class="pln">end</span><span
class="pun">();</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span></pre>
<p>
さて、次はこんな疑問が湧いてくるのではないでしょうか: なぜこんなことをしているの?
</p>
<a name="event-driven-callbacks"></a>
<h3>イベント駆動コールバック</h3>
<p>
先ほどの質問に対する答えは、a) (少なくとも私にとっては)それほど簡単な話ではなく、
b) Node.jsがどのように動作するかの原理に従っているものだから、ということになります。
それはつまり、イベント駆動型のことであり、高速に動作する理由でもあります。
</p>
<p>
もしこの背景について知りたければ、
Felix Geisendörferの素晴らしいエントリ
<a href="http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb">”Understanding node.js”</a>
は一読の価値があります。
</p>
<p>
つまるところ、Node.jsはイベント駆動で動作するということです。
えー、はい、私もです。何を言っているのかさっぱりわかんない。
しかし頑張って説明してみようと思います。
なぜWebベースのアプリケーションをNode.jsで書くことに意味があるのかを。
</p>
<p>
<em>http.createServer</em>メソッドを呼び出す時、
当然ながらサーバの待ち受けは同じポートでしないようにしたいですし、
サーバにHTTPリクエストが届いた時は、他にも何かしたいわけです。
</p>
<p>
問題は、これが非同期で起こるということです: いかなる時でも起こりますし、
サーバ内では動かせるのは単一のプロセスしかないのです。
</p>
<p>
PHPのアプリケーションを書く時は、このようなことに困る事はありません:
HTTPリクエストがあった時はいつでも、
(だいたいはApacheなどの)Webサーバがこのリクエストのために新しいプロセスをフォークし、
PHPスクリプトが最初から最後まで実行されることになります。
</p>
<p>
ですので、制御フローについていうとポート8888番に新しいリクエストが届いた時には、
Node.jsプログラムの中に入ってきており、
おかしなことにならないようそれをうまく取り扱わないといけません。
</p>
<p>
これに精通するためにはいくつか新しい概念を学ぶ必要がありますが、
まさにここが、Node.js/JavaScriptのイベント駆動設計が役に立つ部分なのです。
新しい概念をどのようにサーバのコードに適用するのかを見ていきましょう。
</p>
<p>
サーバは先ほど作りました。サーバを作る時には関数をメソッドに渡しました。
リクエストを受け付けた時は必ず、渡した関数が呼ばれます。
</p>
<p>
実際起こるかどうかはわかりませんが、入ってくるリクエストを取り扱うための場所を作りました。
そう、その渡した関数のことです。最初に定義したとか、匿名で渡したとかは置いておきましょう。
</p>
<p>
この概念を<em>コールバック</em>と呼びます。メソッドに関数を渡した時、
メソッドに紐づいたイベントが発生していた場合に、この関数を<em>コールバック</em>するのです。
</p>
<p>
少なくとも私にとっては、これを理解するのは大変でした。まだ理解が足りないと感じるのであれば、
是非Felixのブログエントリを読んでみて下さい。
</p>
<p>
それではこの新しい概念を使って遊んでみましょう。サーバを作成してから、
HTTPリクエストが発生せず、渡したコールバック関数が呼ばれていなくても、
我々のコードが実行を続けることを証明できるでしょうか。やってみましょう:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br> console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request received."</span><span
class="pun">);</span><span class="pln"><br> response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br> response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello World"</span><span
class="pun">);</span><span class="pln"><br> response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br>http</span><span class="pun">.</span><span class="pln">createServer</span><span
class="pun">(</span><span class="pln">onRequest</span><span class="pun">).</span><span class="pln">listen</span><span
class="pun">(</span><span class="lit">8888</span><span class="pun">);</span><span class="pln"><br><br>console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span></pre>
<p>
<em>onRequest</em>関数(コールバック関数)が呼ばれた時、
テキストを<em>console.log</em>で出力していることに注目して下さい。
その他のテキストはHTTPサーバ開始<em>直後に</em>出力しています。
</p>
<p>
これを起動した時(先ほどと同様、<em>node server.js</em>)、
すぐに”Server has started.”とコマンドライン上で出力されると思います。
(<a href="http://localhost:8888/" rel="nofollow">http://localhost:8888</a>を開いて)
サーバにリクエストを送った時、
”Request received.”というメッセージがコマンドライン上に出力されます。
</p>
<p>
イベント駆動の非同期サーバサイドJavaScriptでのコールバックはうまく動くことがわかりましたね :-)
</p>
<p>
(おそらくサーバは標準出力に、”Request received.”を2回出力したのではないでしょうか。
これはあなたがhttp://localhost:8888/ を開いた時、
ブラウザがfaviconをロードしようとしているためです。)
</p>
<a name="how-our-server-handles-requests"></a>
<h3>サーバによるリクエストの取り扱い方</h3>
<p>
OK、サーバのコードの残り部分をサクッと解析してしまいましょう。
残りはコールバック関数<em>onRequest()</em>の本体です。
</p>
<p>
コールバックによって<em>onRequest()</em>が呼ばれた時、2つの引数、
<em>request</em>と<em>response</em>が渡されます。
</p>
<p>
これらはオブジェクトです。このオブジェクトの持つメソッドを使うと、
発生したHTTPリクエストや、そのリクエストへの応答の詳細を取り扱うことができます
(例えば、サーバにリクエストを行ったブラウザに対して実際に何かを送り返す、というようなこと)。
</p>
<p>
我々のコードがやっているのはこれだけです:
リクエストを受信し、<em>response.writeHead()</em>関数を使って、
HTTPステータスコード200とcontent-typeをHTTPレスポンスヘッダとして、
さらに<em>response.write()</em>関数を使って、
テキスト”Hello World”をHTTPレスポンスのボディーとして送ります。
</p>
<p>
さいごに<em>response.end()</em>を呼び出してレスポンスを完了しています。 </p>
<p>
この時点では<em>request</em>オブジェクトは全く使っていないので、
リクエストの詳細についてはまだ触れません。
</p>
<a name="finding-a-place-for-our-server-module"></a>
<h3>サーバモジュールの場所の確保</h3>
<p>
OK、それでは約束通り、アプリケーションの構成の話に戻りましょう。