-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathday1_express.html
More file actions
982 lines (760 loc) · 70.8 KB
/
day1_express.html
File metadata and controls
982 lines (760 loc) · 70.8 KB
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
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>day1_express</title>
<link href="toc/style/github-bf51422f4bb36427d391e4b75a1daa083c2d840e.css" media="all" rel="stylesheet" type="text/css"/>
<link href="toc/style/github2-d731afd4f624c99a4b19ad69f3083cd6d02b81d5.css" media="all" rel="stylesheet" type="text/css"/>
<link href="toc/css/zTreeStyle/zTreeStyle.css" media="all" rel="stylesheet" type="text/css"/>
<style>
pre {
counter-reset: line-numbering;
border: solid 1px #d9d9d9;
border-radius: 0;
background: #fff;
padding: 0;
line-height: 23px;
margin-bottom: 30px;
white-space: pre;
overflow-x: auto;
word-break: inherit;
word-wrap: inherit;
}
pre a::before {
content: counter(line-numbering);
counter-increment: line-numbering;
padding-right: 1em; /* space after numbers */
width: 25px;
text-align: right;
opacity: 0.7;
display: inline-block;
color: #aaa;
background: #eee;
margin-right: 16px;
padding: 2px 10px;
font-size: 13px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
pre a:first-of-type::before {
padding-top: 10px;
}
pre a:last-of-type::before {
padding-bottom: 10px;
}
pre a:only-of-type::before {
padding: 10px;
}
.highlight { background-color: #ffffcc } /* RIGHT */
</style>
</head>
<body>
<div>
<div style='width:25%;'>
<ul id="tree" class="ztree" style='width:100%'>
</ul>
</div>
<div id='readme' style='width:70%;margin-left:20%;'>
<article class='markdown-body'>
<style>.highlight .hll { background-color: #ffffcc }
.highlight { background: #f0f0f0; }
.highlight .c { color: #60a0b0; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #40a070 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #40a070 } /* Literal.Number.Bin */
.highlight .mf { color: #40a070 } /* Literal.Number.Float */
.highlight .mh { color: #40a070 } /* Literal.Number.Hex */
.highlight .mi { color: #40a070 } /* Literal.Number.Integer */
.highlight .mo { color: #40a070 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */</style>
<h1>Express</h1>
<p>http://expressjs.com/</p>
<p>Express是一个简洁、灵活的基于nodejs的web应用开发框架,它是基于<a href="https://github.com/senchalabs/connect">connect</a>中间件的。</p>
<p>它提供一系列强大的特性,勇于创建各种Web和移动设备应用。</p>
<h2>为什么使用Express</h2>
<ul>
<li>基于node的异步,性能比较好</li>
<li>Express本身比较成熟,目前已经是v4了</li>
<li>有很多大规模应用实例,集群等都非常容易</li>
</ul>
<h2>无状态的http协议</h2>
<p>HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。</p>
<p>大家都明白,Web应用抽象起来就是客户端发出请求,请求到达服务器后,服务器经过一番捣鼓,给客户端发回一个应答。“请求”我们一般抽象成 request,“应答”是 response。服务器和客户端(一般也就是浏览器啦,但是绝不局限于浏览器哦。)之间交流的语言就是 HTTP 协议了。至于服务器怎么折腾出一个应答来的,就八仙过海,各显神通了。</p>
<p>总之,Web 应用中两个重量级的东东就是: Request , Response 。</p>
<p>前面我们说到,每次有访问进来,我们的代码都会跑一遍。现在的问题是,在我们的代码里,怎么抓到客户端发来的 request , 然后,到哪里去找这个 response ,好把我们捣鼓出来的东西放进去,发给客户端呢?答案是,只要我们把他们作为参数交给 tellme 函数(你可以给这个函数取任何名字甚至不给他名字),然后,当请求到达时,node.js 就会把客户的请求封装成 request ,预备发给客户的应答封装成 response 。我们拿到 request ,看看他请求些什么,再折腾些东西(读出个文件也好,去查数据库也好,随便你了。)丢进 response ,发给客户端。</p>
<p>TODO: 此处该补出一张express在node中得位置图片</p>
<p><img src="./images/expressimg9.jpg" alt="Mou icon"></p>
<h2>Node 基础</h2>
<p>see <a href="https://github.com/nodeonly/nodejs-tutorial/blob/master/doc/day3_node.md">node 基础</a></p>
<h2>Write a http server</h2>
<h3>use Nodejs</h3>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">http</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'http');</span>
<span class="vg">http</span><span class="o">.</span><span class="vg">createServer</span><span class="p">(</span><span class="vg">function</span><span class="p">(</span><span class="vg">request</span><span class="p">,</span><span class="vg">response</span><span class="p">){</span>
<span class="w"> </span><span class="vg">console</span><span class="o">.</span><span class="vg">log</span><span class="p">(</span><span class="vg">request</span><span class="p">);</span>
<span class="w"> </span><span class="vg">response</span><span class="o">.</span><span class="vg">end</span><span class="p">(</span><span class="c1">'Hello world!');</span>
<span class="p">})</span><span class="o">.</span><span class="vg">listen</span><span class="p">(</span><span class="il">8888</span><span class="p">);</span>
</pre></div>
<p>这就是最简单的实现</p>
<h3>use Node connect</h3>
<p>Connect is an extensible HTTP server framework for node using "plugins" known as middleware.</p>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">connect</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'connect')</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">http</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'http')</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">connect</span><span class="p">()</span>
<span class="o">//</span><span class="w"> </span><span class="vg">gzip</span><span class="o">/</span><span class="vg">deflate</span><span class="w"> </span><span class="vg">outgoing</span><span class="w"> </span><span class="vg">responses</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">compression</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'compression')</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">compression</span><span class="p">())</span>
<span class="o">//</span><span class="w"> </span><span class="vg">store</span><span class="w"> </span><span class="vg">session</span><span class="w"> </span><span class="vg">state</span><span class="w"> </span><span class="vg">in</span><span class="w"> </span><span class="vg">browser</span><span class="w"> </span><span class="vg">cookie</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">cookieSession</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'cookie-session')</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">cookieSession</span><span class="p">({</span>
<span class="w"> </span><span class="nl">keys:</span><span class="w"> </span><span class="p">[</span><span class="c1">'secret1', 'secret2']</span>
<span class="p">}))</span>
<span class="o">//</span><span class="w"> </span><span class="vg">parse</span><span class="w"> </span><span class="vg">urlencoded</span><span class="w"> </span><span class="vg">request</span><span class="w"> </span><span class="vg">bodies</span><span class="w"> </span><span class="vg">into</span><span class="w"> </span><span class="vg">req</span><span class="o">.</span><span class="vg">body</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">bodyParser</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'body-parser')</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">bodyParser</span><span class="o">.</span><span class="vg">urlencoded</span><span class="p">())</span>
<span class="o">//</span><span class="w"> </span><span class="vg">respond</span><span class="w"> </span><span class="vg">to</span><span class="w"> </span><span class="vg">all</span><span class="w"> </span><span class="vg">requests</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">function</span><span class="p">(</span><span class="vg">req</span><span class="p">,</span><span class="w"> </span><span class="vg">res</span><span class="p">){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">end</span><span class="p">(</span><span class="c1">'Hello from Connect!\n');</span>
<span class="p">})</span>
<span class="o">//</span><span class="vg">create</span><span class="w"> </span><span class="vg">node</span><span class="o">.</span><span class="vg">js</span><span class="w"> </span><span class="vg">http</span><span class="w"> </span><span class="vg">server</span><span class="w"> </span><span class="vg">and</span><span class="w"> </span><span class="vg">listen</span><span class="w"> </span><span class="vg">on</span><span class="w"> </span><span class="vg">port</span>
<span class="vg">http</span><span class="o">.</span><span class="vg">createServer</span><span class="p">(</span><span class="vg">app</span><span class="p">)</span><span class="o">.</span><span class="vg">listen</span><span class="p">(</span><span class="il">3000</span><span class="p">)</span>
</pre></div>
<p>这是官方给出的例子</p>
<h2>安装Express</h2>
<ul>
<li>如何手动安装</li>
<li>如何使用generator</li>
</ul>
<h3>如何手动安装</h3>
<p>新建文件夹:</p>
<div class="highlight"><pre><span class="nv">$ </span>mkdir /getting start/app
<span class="nv">$ </span>npm init
</pre></div>
<p><img src="./images/expressimg7.jpg" alt="Mou icon"></p>
<p>cd到app下,运行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">sudo</span><span class="w"> </span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">--</span><span class="vg">save</span><span class="w"> </span><span class="vg">express</span>
</pre></div>
<p>将express安装在此目录下,新建app.js文件:</p>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">express</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'express');</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">express</span><span class="p">();</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="p">});</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">listen</span><span class="p">(</span><span class="il">5000</span><span class="p">);</span>
</pre></div>
<p>终端运行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">node</span><span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">js</span>
</pre></div>
<p>开启端口,浏览器访问localhost:5000,输出:</p>
<p><img src="./images/expressimg8.jpg" alt="Mou icon"></p>
<h3>如何使用generator</h3>
<h4>安装</h4>
<p>generator是express命令工具集,首先确保已经安装node和npm,先在全局安装这个工具集:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">-</span><span class="vg">g</span><span class="w"> </span><span class="vg">express</span><span class="o">-</span><span class="vg">generator</span>
</pre></div>
<p>如果安装失败,尝试加sudo权限:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">sudo</span><span class="w"> </span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">-</span><span class="vg">g</span><span class="w"> </span><span class="vg">express</span><span class="o">-</span><span class="vg">generator</span>
</pre></div>
<p>现在新建一个我们的express应用,执行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">express</span><span class="w"> </span><span class="vg">expressApp</span>
</pre></div>
<p>项目创建完毕,文件结构如下:</p>
<p><img src="./images/expressimg1.jpg" alt="Mou icon"></p>
<h4>express命令以及参数说明</h4>
<p>TODO:by kezhi</p>
<h4>安装依赖</h4>
<p>打开package.json,可以看到依赖的模块,执行命令来下载依赖的模块:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span>
</pre></div>
<p>如果下载依赖失败,尝试加sudo权限:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">sudo</span><span class="w"> </span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span>
</pre></div>
<p>下载依赖模块成功后,可以看到在node_modules文件夹下多出了这些模块:</p>
<p><img src="./images/expressimg2.jpg" alt="Mou icon"></p>
<h4>启动服务器</h4>
<p>回到app.js层级,执行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">start</span>
</pre></div>
<p>开始运行express打开端口,用浏览器打开http://localhost:3000/,在此估计会出现缺少模块的情况,如果有模块缺少,cd到node_modules文件夹下去安装缺失的模块:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">sudo</span><span class="w"> </span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="vg">xxx</span><span class="p">(</span><span class="err">模块名称</span><span class="p">)</span>
</pre></div>
<p>大概会缺失5个模块左右,模块全部安装完成,浏览器则会输出:</p>
<p><img src="./images/expressimg3.jpg" alt="Mou icon"></p>
<p>完毕,说明express安装成功.</p>
<h2>核心概念</h2>
<h3>请求request</h3>
<p>Request对象是有关于客户端所发出的请求的对象,只要是有关于客户端请求的信息,都可以藉由它来取得,例如请求标头、请求方法、请求参数、客户端IP,客户端浏览器等等信息。</p>
<p>客户端发来的请求,node.js 帮我们封装成 request 对象</p>
<p>在request里面我们可以获得</p>
<ul>
<li>body</li>
<li>header</li>
<li>params</li>
<li>query</li>
<li>....</li>
</ul>
<h3>响应response</h3>
<p>Response对象是有关于对客户端请求之响应,可以利用它来设定一些要响应的讯息,例如标题信息、响应状态码等.</p>
<p>我们利用response,向客户端发送回答,说白了是向浏览器写内容。</p>
<h3>理解路由</h3>
<p>所谓路由就是定义</p>
<ul>
<li>地址1:谁来处理,以什么方式处理</li>
<li>地址2:谁来处理,以什么方式处理</li>
</ul>
<div class="highlight"><pre><span class="w"> </span><span class="vg">var</span><span class="w"> </span><span class="vg">express</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'express');</span>
<span class="w"> </span><span class="vg">var</span><span class="w"> </span><span class="vg">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">express</span><span class="p">();</span>
<span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">post</span><span class="p">(</span><span class="c1">'/someur',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">listen</span><span class="p">(</span><span class="il">5000</span><span class="p">);</span>
</pre></div>
<p>说明一下
例如定义两个路由,一个对应get请求,一个对应post请求;当客户端向http://localhost:5000/发送get请求的时候,则会触发:</p>
<div class="highlight"><pre><span class="vg">app</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="p">});</span>
</pre></div>
<p>当客户端向http://localhost:5000/someur发送post请求的时候,则会触发:</p>
<div class="highlight"><pre><span class="vg">app</span><span class="o">.</span><span class="vg">post</span><span class="p">(</span><span class="c1">'/someur',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="p">});</span>
</pre></div>
<h3>session</h3>
<p>一个session就是一系列某用户和服务器间的通讯。服务器有能力分辨出不同的用户。</p>
<p>一个session的建立是从一个用户向服务器发第一个请求开始,而以用户显式结束或session超时为结束。
其工作原理是这样的:</p>
<ol>
<li>当一个用户向服务器发送第一个请求时,服务器为其建立一个session,并为此session创建一个标识号</li>
<li>这个用户随后的所有请求都应包括这个标识号。服务器会校对这个标识号以判断请求属于哪个session</li>
<li>当用户在一段时间没有任何操作,session就会自动超时</li>
</ol>
<p>这种机制不使用IP作为标识,是因为很多机器是通过代理服务器方式上网,没法区分每一台机器。</p>
<p>对于session标识号(sessionID),有两种方式实现:cookies和URL重写,此处不详细讲解。</p>
<h4>express的session</h4>
<p>nodejs本身不管session,因为用了express框架,express基于connect,connect中有session管理的能力。connect是插件式架构,它的插件称之为“中间件”,其中有个中间件就是叫作session。</p>
<p>到了4.xx版本之后,session管理和cookies等许多模块都不再直接包含在express中,而是需要单独下载添加。</p>
<p>https://github.com/expressjs/session</p>
<h4>应用场景: 登陆</h4>
<ul>
<li>在登陆页面完成用户鉴权,鉴权成功后,在session里存储用户信息</li>
<li>一段时间没有任何操作,session就会自动超时,此时用户点击页面的时候,后台会判断是否存在当前用户的session</li>
<li>一半超时会重定向到登陆界面,提示此操作需要用户登陆</li>
</ul>
<h4>应用场景: 购物车</h4>
<ul>
<li>保证当前session里有用户信息,用户是登陆状态的</li>
<li>用户在购物页面操作,点击加入购物车,此时在session里增加一条信息,存储当前物品信息</li>
<li>用户结算的时候,从session获取物品价格和数量,计算出总价,订单完成后,清理session</li>
</ul>
<h3>理解模板</h3>
<ul>
<li>常用模板有jade,ejs,handlebars以及artTemplate等</li>
<li>在express里如何用生成器指定模板</li>
<li>morgan说明</li>
</ul>
<h4>jade node模板引擎</h4>
<ul>
<li>http://jade-lang.com/</li>
</ul>
<p>此引擎构建在node之上,需要经过node编译成html代码,例如:</p>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">express</span><span class="p">();</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">set</span><span class="p">(</span><span class="c1">'views', path.join(__dirname, 'views'));</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">set</span><span class="p">(</span><span class="c1">'view engine', 'jade');</span>
</pre></div>
<p>开启express服务,指定模板路径为views,模板引擎为jade,当客户端访问指定路由时,express便会去给对应的jade文件配置参数,并编译此jade模板:</p>
<div class="highlight"><pre><span class="vg">router</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/', function(req, res) {</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">render</span><span class="p">(</span><span class="c1">'index', { title: 'Express' });</span>
<span class="p">});</span>
</pre></div>
<p>index jade模板:</p>
<div class="highlight"><pre><span class="vg">extends</span><span class="w"> </span><span class="vg">layout</span>
<span class="vg">block</span><span class="w"> </span><span class="vg">content</span>
<span class="w"> </span><span class="vg">h1</span><span class="o">=</span><span class="w"> </span><span class="vg">title</span>
<span class="w"> </span><span class="vg">p</span><span class="w"> </span><span class="vg">Welcome</span><span class="w"> </span><span class="vg">to</span><span class="w"> </span><span class="err">#</span><span class="p">{</span><span class="vg">title</span><span class="p">}</span>
</pre></div>
<p>最终在客户端输出:</p>
<p><img src="./images/expressimg3.jpg" alt="Mou icon"></p>
<h3>理解public目录</h3>
<ul>
<li>常规做法</li>
</ul>
<p>app.js里</p>
<div class="highlight"><pre><span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">express</span><span class="o">.</span><span class="vg">static</span><span class="p">(</span><span class="vg">path</span><span class="o">.</span><span class="vg">join</span><span class="p">(</span><span class="vg">__dirname</span><span class="p">,</span><span class="w"> </span><span class="c1">'public')));</span>
</pre></div>
<p>它就是用来托管public中得所有文件。可以以http方式访问</p>
<h4>如果public/index.html不存在</h4>
<p>此时如何使用其他页面做为入口,需要再<code>/</code>路由定义处,redirect到对应页面(by kezhi)。</p>
<h4>如何在静态页面处理请求参数</h4>
<p>在静态页面处理请求参数,是通过连接地址把参数传递过去,通过前端jacascript取出做处理(by kezhi)。</p>
<h4>理解express.static</h4>
<p>说明http-server用法</p>
<p>区分express.static和http-server的差别:功能一样,用法上有差异</p>
<h4>路由冲突</h4>
<p>当<code>public/index.html</code>和路由的<code>/</code>冲突</p>
<p>此时按照<code>public/index.html</code>走</p>
<h3>HTTP</h3>
<p>请查看<a href="https://github.com/nodeonly/nodejs-tutorial/blob/master/doc/demo/day1/http/readme.md">HTTP</a></p>
<h2>任务</h2>
<p>此处开始是大家每个人都必须亲手做的练习</p>
<ol>
<li>准备工作</li>
<li>路由定制方式</li>
<li>如何处理get请求</li>
<li>如何处理post请求</li>
<li>如何实现文件上传</li>
<li>request里如何取值</li>
<li>response返回</li>
<li>完成api返回</li>
<li>完成登陆</li>
<li>完成购物车</li>
</ol>
<h3>准备工作</h3>
<p>安装supervisor(by kezhi)</p>
<h3>路由定制方式</h3>
<p>路由定制方式有2种</p>
<ul>
<li>常规做法</li>
<li>使用路由重定向</li>
</ul>
<h4>常规定义路由</h4>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">express</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'express');</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">express</span><span class="p">();</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="p">});</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">post</span><span class="p">(</span><span class="c1">'/someur',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'hello,world');</span>
<span class="p">});</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">listen</span><span class="p">(</span><span class="il">5000</span><span class="p">);</span>
</pre></div>
<p>定义了2个请求</p>
<ul>
<li>/</li>
<li>/someurl</li>
</ul>
<h4>使用路由重定向</h4>
<p>in app.js</p>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">routes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'./routes/index');</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">users</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'./routes/users');</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="c1">'/', routes);</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="c1">'/users', users);</span>
</pre></div>
<p>然后in <code>/routes/index.js</code>里</p>
<div class="highlight"><pre><span class="n">var</span> <span class="n">express</span> <span class="o">=</span> <span class="n">require</span><span class="p">(</span><span class="c">'express');</span>
<span class="n">var</span> <span class="n">router</span> <span class="o">=</span> <span class="n">express</span><span class="p">.</span><span class="n">Router</span><span class="p">()</span><span class="err">;</span>
<span class="n">router</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="c">'/get', function(req, res) {</span>
<span class="n">res</span><span class="p">.</span><span class="n">render</span><span class="p">(</span><span class="c">'index', { title: 'Express' });</span>
<span class="p">})</span><span class="err">;</span>
<span class="n">router</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="c">'/posttapi', function(req, res) {</span>
<span class="n">res</span><span class="p">.</span><span class="n">render</span><span class="p">(</span><span class="c">'index', { title: 'Express' });</span>
<span class="p">})</span><span class="err">;</span>
<span class="n">module</span><span class="p">.</span><span class="n">exports</span> <span class="o">=</span> <span class="n">router</span><span class="err">;</span>
</pre></div>
<p>此时的router里可以增加各种请求的方法。</p>
<p>这种写法是模块化写法,可以按照业务或者其他分类组织代码,使代码具有更高的可读性。</p>
<h3>如何处理get请求</h3>
<p>我们可以在一个html文件里向端口发送get请求,首先要在访问http://localhost:3000下,端口能向浏览器输出此html,默认情况下,express是会输出pubblic文件夹下的index.html文件,在没有特别指明的情况下,所以注释掉:</p>
<div class="highlight"><pre><span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="c1">'/', routes);</span>
</pre></div>
<p>这样在get请求的url为'/'时,express会找到pubblic文件夹;我们可以自定义路由:</p>
<div class="highlight"><pre><span class="c1">//自定义路由</span>
<span class="k">var</span> <span class="n">myHttpGet</span> <span class="o">=</span> <span class="n">require</span><span class="p">('.</span><span class="o">/</span><span class="n">routes</span><span class="o">/</span><span class="n">getserver</span><span class="p">');</span>
<span class="n">app</span><span class="p">.</span><span class="k">use</span><span class="p">('</span><span class="o">/</span><span class="n">getserver</span><span class="p">',</span> <span class="n">myHttpGet</span><span class="p">);</span>
</pre></div>
<p>当get请求的url为/getserver时,express会执行myHttpGet模块,在routes文件夹下实现myHttpGet模块:</p>
<div class="highlight"><pre><span class="n">var</span> <span class="n">express</span> <span class="o">=</span> <span class="n">require</span><span class="p">(</span><span class="c">'express');</span>
<span class="n">var</span> <span class="n">router</span> <span class="o">=</span> <span class="n">express</span><span class="p">.</span><span class="n">Router</span><span class="p">()</span><span class="err">;</span>
<span class="o">/*</span> <span class="k">GET</span> <span class="n">http</span><span class="p">.</span><span class="o">*/</span>
<span class="n">router</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="c">'/', function(req, res) {</span>
<span class="n">res</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">req</span><span class="p">.</span><span class="n">query</span><span class="p">)</span><span class="err">;</span>
<span class="p">})</span><span class="err">;</span>
<span class="n">module</span><span class="p">.</span><span class="n">exports</span> <span class="o">=</span> <span class="n">router</span><span class="err">;</span>
</pre></div>
<p>当我们在html里用ajax向此路由发送get请求时,我们可以取到参数,做一些处理后,用:</p>
<div class="highlight"><pre><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="vg">resJson</span><span class="p">);</span>
</pre></div>
<p>返回给ajax对象:</p>
<div class="highlight"><pre><span class="vg">oGetBtn</span><span class="o">.</span><span class="vg">onclick</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">function</span><span class="p">(){</span><span class="w"> </span>
<span class="w"> </span><span class="err">$</span><span class="o">.</span><span class="vg">ajax</span><span class="p">({</span>
<span class="w"> </span><span class="nl">type:</span><span class="w"> </span><span class="s2">"GET"</span><span class="p">,</span>
<span class="w"> </span><span class="nl">url:</span><span class="w"> </span><span class="s2">"http://localhost:3000/getserver"</span><span class="p">,</span>
<span class="w"> </span><span class="nl">data:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">'method':'GET',</span>
<span class="w"> </span><span class="c1">'name':'rainBow',</span>
<span class="w"> </span><span class="c1">'sex':'man'</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nl">dataType:</span><span class="w"> </span><span class="s2">"json"</span><span class="p">,</span>
<span class="w"> </span><span class="nl">success:</span><span class="w"> </span><span class="vg">function</span><span class="p">(</span><span class="vg">data</span><span class="p">){</span>
<span class="w"> </span><span class="vg">var</span><span class="w"> </span><span class="vg">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">JSON</span><span class="o">.</span><span class="vg">stringify</span><span class="p">(</span><span class="vg">data</span><span class="p">);</span>
<span class="w"> </span><span class="vg">oResBox</span><span class="o">.</span><span class="vg">innerHTML</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">str</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">});</span>
<span class="p">};</span>
</pre></div>
<p>点击GET按钮发送GET请求,并把发出去的参数整理成json格式并返回:</p>
<p><img src="./images/expressimg4.jpg" alt="Mou icon"></p>
<h3>如何处理post请求</h3>
<p>在myHttpGet模块里添加接收此路由下得post请求代码,对于post请求,用req.body接收post参数:</p>
<div class="highlight"><pre><span class="cm">/* POST http.*/</span>
<span class="n">router</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="sc">'/'</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
<span class="n">res</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">req</span><span class="p">.</span><span class="n">body</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
<p>点击按钮post发送post请求:</p>
<div class="highlight"><pre><span class="err">$</span><span class="o">.</span><span class="vg">ajax</span><span class="p">({</span>
<span class="w"> </span><span class="nl">type:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
<span class="w"> </span><span class="nl">url:</span><span class="w"> </span><span class="s2">"http://localhost:3000/getserver"</span><span class="p">,</span>
<span class="w"> </span><span class="nl">data:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">'method':'POST',</span>
<span class="w"> </span><span class="c1">'name':'rainBow',</span>
<span class="w"> </span><span class="c1">'sex':'man'</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nl">dataType:</span><span class="w"> </span><span class="s2">"json"</span><span class="p">,</span>
<span class="w"> </span><span class="nl">success:</span><span class="w"> </span><span class="vg">function</span><span class="p">(</span><span class="vg">data</span><span class="p">){</span>
<span class="w"> </span><span class="vg">var</span><span class="w"> </span><span class="vg">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">JSON</span><span class="o">.</span><span class="vg">stringify</span><span class="p">(</span><span class="vg">data</span><span class="p">);</span>
<span class="w"> </span><span class="vg">oResBox</span><span class="o">.</span><span class="vg">innerHTML</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">str</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">});</span>
</pre></div>
<p><img src="./images/expressimg5.jpg" alt="Mou icon"></p>
<p>更多,带有参数的post请求</p>
<div class="highlight"><pre><span class="vg">router</span><span class="o">.</span><span class="vg">post</span><span class="p">(</span><span class="c1">'/post/:id', function(req, res) {</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">status</span><span class="p">(</span><span class="il">200</span><span class="p">)</span><span class="o">.</span><span class="vg">json</span><span class="p">({</span>
<span class="w"> </span><span class="nl">data:</span><span class="p">{</span>
<span class="w"> </span><span class="nl">id:</span><span class="vg">req</span><span class="o">.</span><span class="vg">param</span><span class="p">(</span><span class="c1">'id'),</span>
<span class="w"> </span><span class="nl">name:</span><span class="c1">'sss',</span>
<span class="w"> </span><span class="nl">kkk:</span><span class="vg">req</span><span class="o">.</span><span class="vg">body</span><span class="o">.</span><span class="vg">kkk</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">})</span>
<span class="p">});</span>
</pre></div>
<h3>如何实现文件上传</h3>
<p>什么是多部请求?</p>
<div class="highlight"><pre><span class="vg">var</span><span class="w"> </span><span class="vg">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">express</span><span class="p">();</span>
<span class="vg">var</span><span class="w"> </span><span class="vg">multer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="vg">require</span><span class="p">(</span><span class="c1">'multer')</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">multer</span><span class="p">({</span><span class="w"> </span>
<span class="w"> </span><span class="nl">dest:</span><span class="w"> </span><span class="c1">'./uploads/',</span>
<span class="w"> </span><span class="nl">rename:</span><span class="w"> </span><span class="vg">function</span><span class="w"> </span><span class="p">(</span><span class="vg">fieldname</span><span class="p">,</span><span class="w"> </span><span class="vg">filename</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="vg">return</span><span class="w"> </span><span class="vg">filename</span><span class="o">.</span><span class="vg">replace</span><span class="p">(</span><span class="o">/\</span><span class="vg">W</span><span class="o">+/</span><span class="vg">g</span><span class="p">,</span><span class="w"> </span><span class="c1">'-').toLowerCase() + Date.now()</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}))</span>
</pre></div>
<p>在路由里</p>
<div class="highlight"><pre><span class="vg">router</span><span class="o">.</span><span class="vg">post</span><span class="p">(</span><span class="c1">'/post/formdata', function(req, res) {</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'respond with a resource');</span>
<span class="w"> </span><span class="vg">console</span><span class="o">.</span><span class="vg">log</span><span class="p">(</span><span class="vg">req</span><span class="o">.</span><span class="vg">body</span><span class="p">,</span><span class="w"> </span><span class="vg">req</span><span class="o">.</span><span class="vg">files</span><span class="p">);</span>
<span class="w"> </span><span class="vg">console</span><span class="o">.</span><span class="vg">log</span><span class="p">(</span><span class="vg">req</span><span class="o">.</span><span class="vg">files</span><span class="o">.</span><span class="vg">pic</span><span class="o">.</span><span class="vg">path</span><span class="p">);</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">json</span><span class="p">(</span><span class="vg">req</span><span class="o">.</span><span class="vg">body</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
<p>这里的req.files就可以渠道对应的files的详情,该放到db或者云存储就大胆的存储</p>
<h3>request里如何取值</h3>
<ul>
<li>body</li>
<li>params</li>
<li>query</li>
</ul>
<p>各自举例</p>
<p>body处理post请求参数,把参数整理成json各式:</p>
<div class="highlight"><pre><span class="vg">router</span><span class="o">.</span><span class="vg">post</span><span class="p">(</span><span class="c1">'/', function(req, res) {</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="vg">req</span><span class="o">.</span><span class="vg">body</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
<p>query处理get请求参数,整理成json各式:</p>
<div class="highlight"><pre><span class="vg">router</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/www:soso', function(req, res) {</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="vg">req</span><span class="o">.</span><span class="vg">query</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
<h3>response返回</h3>
<ul>
<li>text</li>
<li>xml</li>
<li>json</li>
</ul>
<h3>完成api返回</h3>
<h3>完成登陆</h3>
<h3>完成购物车</h3>
<h2>实践积累</h2>
<p>试着说明package.json的众多方面</p>
<h4>package.json</h4>
<p>package.json是描述项目文件,描述项目所依赖的模块,当我们把一个项目发布到npm时,其实不用把我们所依赖的模块一起发不上去,只需要把依赖的模块名称填写到package.json里面,当别人npm install的时候,npm会去识别package.json中所依赖的模块名称,然后下载下来:</p>
<ul>
<li><code>npm install --save</code> vs <code>npm install --save-dev</code></li>
<li><code>npm start</code> vs <code>npm test</code> (scripts自定义)</li>
<li>如何写一个npm,以及发布</li>
</ul>
<p>当我们通过npm安装某一模块时,运用<code>npm install --save</code>或者<code>npm install --save-dev</code>,npm则会把我们的项目依赖信息写入package.json中。</p>
<p><code>npm install --save</code> 和 <code>npm install --save-dev</code>的区别:</p>
<p>devDependencies下列出的模块,是我们开发时用的,比如grunt-contrib-uglify,我们用它混淆js文件,它们不会被部署到生产环境。dependencies下的模块,则是我们生产环境中需要的依赖。</p>
<h4>npm参数说明</h4>
<p>npm install --save 和 npm install --save-dev的区别:</p>
<p>说明</p>
<ul>
<li>save会自动保存到package.json里</li>
<li>save-dev会保存到devDependencies模块下,save会保存到dependencies</li>
</ul>
<p>devDependencies下列出的模块,是我们开发时用的,比如grunt-contrib-uglify,我们用它混淆js文件,它们不会被部署到生产环境。dependencies下的模块,则是我们生产环境中需要的依赖。</p>
<h4>npm start</h4>
<p>新建项目npmStart:</p>
<p><img src="./images/npmstart.png" alt="Mou icon"></p>
<p>配置package.json中得script参数:</p>
<div class="highlight"><pre><span class="p">{</span>
<span class="w"> </span><span class="s2">"name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"example1"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"version"</span><span class="o">:</span><span class="w"> </span><span class="s2">"0.0.0"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"private"</span><span class="o">:</span><span class="w"> </span><span class="vg">true</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"scripts"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"start"</span><span class="o">:</span><span class="w"> </span><span class="s2">"node http.js"</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>cd到此目录,运行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">start</span>
</pre></div>
<p>即可运行http.js文件,这就相当于是node http.js的快捷运行方式。</p>
<h4>npm发布模块</h4>
<p>如果需要向npm发布自己的模块,那么需要注册账号密码,终端运行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">adduser</span>
</pre></div>
<p>按照提示填写账号密码邮箱,新建项目,配置package.json文件:</p>
<div class="highlight"><pre><span class="p">{</span>
<span class="w"> </span><span class="s2">"name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"hellonpm"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"description"</span><span class="o">:</span><span class="w"> </span><span class="s2">"hello world test app"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"version"</span><span class="o">:</span><span class="w"> </span><span class="s2">"0.0.1"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"private"</span><span class="o">:</span><span class="w"> </span><span class="vg">false</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"dependencies"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"express"</span><span class="o">:</span><span class="w"> </span><span class="s2">"2.5.9"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"ejs"</span><span class="o">:</span><span class="s2">"0.4.2"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"superagent"</span><span class="o">:</span><span class="s2">"0.3.0"</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>name即为我们的模块名称,要注意的是private必须设置为false,模块才能被发布,dependencies是指我们的模块需要依赖哪些其他的模块,cd到express文件夹下:</p>
<p><img src="./images/npm.jpg" alt="Mou icon"></p>
<p>终端运行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">publish</span>
</pre></div>
<p><img src="./images/npm2.jpg" alt="Mou icon"></p>
<p>模块发布成功!</p>
<p>cd到任意文件夹运行:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="vg">hellonpm</span>
</pre></div>
<p>即可安装我们上传的hellonpm模块!</p>
<h2>测试</h2>
<div class="highlight"><pre><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">--</span><span class="vg">save</span><span class="o">-</span><span class="vg">dev</span><span class="w"> </span><span class="vg">mocha</span>
<span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">--</span><span class="vg">save</span><span class="o">-</span><span class="vg">dev</span><span class="w"> </span><span class="vg">chai</span>
<span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">--</span><span class="vg">save</span><span class="o">-</span><span class="vg">dev</span><span class="w"> </span><span class="vg">sinon</span>
<span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">--</span><span class="vg">save</span><span class="o">-</span><span class="vg">dev</span><span class="w"> </span><span class="vg">supertest</span>
<span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">--</span><span class="vg">save</span><span class="o">-</span><span class="vg">dev</span><span class="w"> </span><span class="vg">zombie</span>
</pre></div>
<p>see <a href="https://github.com/nodeonly/nodejs-tutorial/blob/master/doc/day5_test.md">node 测试</a></p>
<h2>调试</h2>
<h3>node debug</h3>
<p>V8 提供了一个强大的调试器,可以通过 TCP 协议从外部访问。Nodejs提供了一个内建调试器来帮助开发者调试应用程序。想要开启调试器我们需要在代码中加入debugger标签,当Nodejs执行到debugger标签时会自动暂停(debugger标签相当于在代码中开启一个断点)。代码如下:</p>
<p>see <code>demo/day1/debug/app_debug1.js</code></p>
<div class="highlight"><pre><span class="n">var</span> <span class="n">express</span> <span class="o">=</span> <span class="n">require</span><span class="p">(</span><span class="c">'express');</span>
<span class="n">var</span> <span class="n">app</span> <span class="o">=</span> <span class="n">express</span><span class="p">()</span><span class="err">;</span>
<span class="n">app</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="c">'/',function(req,res){</span>
<span class="n">debugger</span><span class="err">;</span>
<span class="n">res</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="c">'hello,world');</span>
<span class="p">})</span><span class="err">;</span>
<span class="n">app</span><span class="p">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">5005</span><span class="p">)</span><span class="err">;</span>
<span class="n">module</span><span class="p">.</span><span class="n">exports</span> <span class="o">=</span> <span class="n">app</span><span class="err">;</span>
</pre></div>
<p>执行命令:<code>node debug app_debug1.js</code> 就可以进入调试模式。</p>
<p>当然,首先需要在程序代码中手动添加中断debugger; , 这样当以调试模式运行时,程序会自动中断,然后等候你调试,就像GDB一样,可以用help命令查看自己都可以使用哪些调试命令。</p>
<div class="highlight"><pre><span class="vg">debug</span><span class="o">></span><span class="w"> </span><span class="vg">help</span>
<span class="nl">Commands:</span><span class="w"> </span><span class="vg">run</span><span class="w"> </span><span class="p">(</span><span class="vg">r</span><span class="p">),</span><span class="w"> </span><span class="vg">cont</span><span class="w"> </span><span class="p">(</span><span class="vg">c</span><span class="p">),</span><span class="w"> </span><span class="vg">next</span><span class="w"> </span><span class="p">(</span><span class="vg">n</span><span class="p">),</span><span class="w"> </span><span class="vg">step</span><span class="w"> </span><span class="p">(</span><span class="vg">s</span><span class="p">),</span><span class="w"> </span><span class="vg">out</span><span class="w"> </span><span class="p">(</span><span class="vg">o</span><span class="p">),</span><span class="w"> </span><span class="vg">backtrace</span><span class="w"> </span><span class="p">(</span><span class="vg">bt</span><span class="p">),</span><span class="w"> </span><span class="vg">setBreakpoint</span><span class="w"> </span><span class="p">(</span><span class="vg">sb</span><span class="p">),</span><span class="w"> </span><span class="vg">clearBreakpoint</span><span class="w"> </span><span class="p">(</span><span class="vg">cb</span><span class="p">),</span>
<span class="vg">watch</span><span class="p">,</span><span class="w"> </span><span class="vg">unwatch</span><span class="p">,</span><span class="w"> </span><span class="vg">watchers</span><span class="p">,</span><span class="w"> </span><span class="vg">repl</span><span class="p">,</span><span class="w"> </span><span class="vg">restart</span><span class="p">,</span><span class="w"> </span><span class="vg">kill</span><span class="p">,</span><span class="w"> </span><span class="vg">list</span><span class="p">,</span><span class="w"> </span><span class="vg">scripts</span><span class="p">,</span><span class="w"> </span><span class="vg">breakOnException</span><span class="p">,</span><span class="w"> </span><span class="vg">breakpoints</span><span class="p">,</span><span class="w"> </span><span class="vg">version</span>
</pre></div>
<p>这里就和gdb等调试器一模一样了</p>
<p>注意,如果出现</p>
<div class="highlight"><pre><span class="o"><</span><span class="w"> </span><span class="vg">Failed</span><span class="w"> </span><span class="vg">to</span><span class="w"> </span><span class="vg">open</span><span class="w"> </span><span class="vg">socket</span><span class="w"> </span><span class="vg">on</span><span class="w"> </span><span class="vg">port</span><span class="w"> </span><span class="il">5858</span><span class="p">,</span><span class="w"> </span><span class="vg">waiting</span><span class="w"> </span><span class="il">1000</span><span class="w"> </span><span class="vg">ms</span><span class="w"> </span><span class="vg">before</span><span class="w"> </span><span class="vg">retrying</span>
</pre></div>
<p>请结束掉所有debug进程</p>
<div class="highlight"><pre><span class="vg">ps</span><span class="w"> </span><span class="o">-</span><span class="vg">ef</span><span class="o">|</span><span class="vg">grep</span><span class="w"> </span><span class="vg">debug</span><span class="o">-</span><span class="vg">brk</span><span class="o">|</span><span class="vg">awk</span><span class="w"> </span><span class="c1">'{print $2}'|xargs kill -9</span>
</pre></div>
<h3>node-inspector</h3>
<p>上面这种方式稍微有些麻烦,我们写JS代码调试的时候一般都用FireBug或谷歌浏览器内置的调试工具,nodejs程序当然也可以这样子来调试,但是首先需要安装一个node-inspector的东西</p>
<p>node-inspector是通过websocket方式来转向debug输入输出的。因此,我们在调试前要先启动node-inspector来监听Nodejs的debug调试端口。</p>
<p>这个需要用npm来安装,只需要执行下列语句:</p>
<div class="highlight"><pre><span class="vg">npm</span><span class="w"> </span><span class="vg">install</span><span class="w"> </span><span class="o">-</span><span class="vg">g</span><span class="w"> </span><span class="vg">node</span><span class="o">-</span><span class="vg">inspector</span>
</pre></div>
<p>安装完成之后,通常可以直接这样启动在后台:</p>
<div class="highlight"><pre><span class="vg">node</span><span class="o">-</span><span class="vg">inspector</span><span class="w"> </span><span class="o">&</span>
</pre></div>
<p>默认会监听8080端口,当然,也可能通过使用--web-port参数来修改。然后,在执行node程序的时候,多加个参数:--debug-brk, 如下:</p>
<div class="highlight"><pre><span class="vg">node</span><span class="w"> </span><span class="o">--</span><span class="vg">debug</span><span class="o">-</span><span class="vg">brk</span><span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">js</span>
</pre></div>
<p>或者</p>
<div class="highlight"><pre><span class="vg">node</span><span class="o">-</span><span class="vg">debug</span><span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">js</span>
</pre></div>
<p>控制台会返回“debugger listening on port 5858”, 现在打开浏览嚣,访问http://localhost:8080,这时候就会打开一个很像Chrome内置调试工具的界面,并且代码断点在第一行,下面就可以使用这个来调试了。</p>
<p><img src="./images/debug.png" alt=""></p>
<ul>
<li>增加断点,查看调用栈,变量等</li>
<li>使用console打印查看日志</li>
</ul>
<p>使用方法和chrome的inspect element调试web开发是一样的。</p>
<p>调试还是很方便的,而且可以异地调试。</p>
<h2>部署实战</h2>
<h3>开发环境下</h3>
<p>在开发环境使用 nodemon,supervisor </p>
<h3>产品环境下</h3>
<p>在生产环境使用pm2,forever</p>
<h3>集群与负载</h3>
<ul>
<li>nginx</li>
<li>haproxy</li>
</ul>
<h2>压力测试</h2>
<h3>ab</h3>
<p>ab是apache自带的一个很好用的压力测试工具,当安装完apache的时候,就可以在bin下面找到ab</p>
<div class="highlight"><pre><span class="vg">ab</span><span class="w"> </span><span class="o">-</span><span class="vg">n1000</span><span class="w"> </span><span class="o">-</span><span class="vg">c100</span><span class="w"> </span><span class="nl">http:</span><span class="o">//</span><span class="mf">127.0.0.1</span><span class="o">:</span><span class="il">4100</span>
</pre></div>
<h3>wrk</h3>
<p>安装</p>
<div class="highlight"><pre><span class="vg">git</span><span class="w"> </span><span class="vg">clone</span><span class="w"> </span><span class="nl">https:</span><span class="o">//</span><span class="vg">github</span><span class="o">.</span><span class="vg">com</span><span class="o">/</span><span class="vg">wg</span><span class="o">/</span><span class="vg">wrk</span>
<span class="vg">cd</span><span class="w"> </span><span class="vg">wrk</span>
<span class="vg">make</span>
<span class="vg">sudo</span><span class="w"> </span><span class="vg">cp</span><span class="w"> </span><span class="o">-</span><span class="vg">rf</span><span class="w"> </span><span class="vg">wrk</span><span class="w"> </span><span class="o">/</span><span class="vg">bin</span><span class="o">/</span>
</pre></div>
<p>测试</p>
<div class="highlight"><pre><span class="vg">wrk</span><span class="w"> </span><span class="o">-</span><span class="vg">t8</span><span class="w"> </span><span class="o">-</span><span class="vg">c400</span><span class="w"> </span><span class="nl">http:</span><span class="o">//</span><span class="mf">127.0.0.1</span><span class="o">:</span><span class="il">4100</span>
<span class="vg">Running</span><span class="w"> </span><span class="il">10</span><span class="vg">s</span><span class="w"> </span><span class="vg">test</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="nl">http:</span><span class="o">//</span><span class="mf">127.0.0.1</span><span class="o">:</span><span class="il">4100</span>
<span class="w"> </span><span class="il">8</span><span class="w"> </span><span class="vg">threads</span><span class="w"> </span><span class="vg">and</span><span class="w"> </span><span class="il">400</span><span class="w"> </span><span class="vg">connections</span>
<span class="w"> </span><span class="vg">Thread</span><span class="w"> </span><span class="vg">Stats</span><span class="w"> </span><span class="vg">Avg</span><span class="w"> </span><span class="vg">Stdev</span><span class="w"> </span><span class="vg">Max</span><span class="w"> </span><span class="o">+/-</span><span class="w"> </span><span class="vg">Stdev</span>
<span class="w"> </span><span class="vg">Latency</span><span class="w"> </span><span class="mf">99.83</span><span class="vg">ms</span><span class="w"> </span><span class="mf">16.70</span><span class="vg">ms</span><span class="w"> </span><span class="mf">175.72</span><span class="vg">ms</span><span class="w"> </span><span class="mf">76.86</span><span class="o">%</span>
<span class="w"> </span><span class="vg">Req</span><span class="o">/</span><span class="vg">Sec</span><span class="w"> </span><span class="mf">325.50</span><span class="w"> </span><span class="mf">161.75</span><span class="w"> </span><span class="mf">665.00</span><span class="w"> </span><span class="mf">50.27</span><span class="o">%</span>
<span class="w"> </span><span class="il">22709</span><span class="w"> </span><span class="vg">requests</span><span class="w"> </span><span class="vg">in</span><span class="w"> </span><span class="mf">10.01</span><span class="vg">s</span><span class="p">,</span><span class="w"> </span><span class="mf">5.65</span><span class="vg">MB</span><span class="w"> </span><span class="vg">read</span>
<span class="w"> </span><span class="vg">Socket</span><span class="w"> </span><span class="nl">errors:</span><span class="w"> </span><span class="vg">connect</span><span class="w"> </span><span class="il">155</span><span class="p">,</span><span class="w"> </span><span class="vg">read</span><span class="w"> </span><span class="il">3461</span><span class="p">,</span><span class="w"> </span><span class="vg">write</span><span class="w"> </span><span class="il">0</span><span class="p">,</span><span class="w"> </span><span class="vg">timeout</span><span class="w"> </span><span class="il">775</span>
<span class="vg">Requests</span><span class="o">/</span><span class="nl">sec:</span><span class="w"> </span><span class="mf">2267.99</span>
<span class="vg">Transfer</span><span class="o">/</span><span class="nl">sec:</span><span class="w"> </span><span class="mf">578.07</span><span class="vg">KB</span>
</pre></div>
<h2>阅读文档</h2>
<h3>getting start</h3>
<p>入门文档,如果你看完了上面的内容,就可以不要看了</p>
<h3>guide</h3>
<p>此处是开发指南,建议完全看一遍</p>
<p>Error handling</p>
<p>监听server服务错误,如get请求的时候输出一个没定义的变量a,这时express捕捉到错误,并返回'Something broke!':</p>
<div class="highlight"><pre><span class="vg">app</span><span class="o">.</span><span class="vg">get</span><span class="p">(</span><span class="c1">'/',function(req,res){</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="vg">a</span><span class="p">);</span>
<span class="p">});</span>
<span class="vg">app</span><span class="o">.</span><span class="vg">use</span><span class="p">(</span><span class="vg">function</span><span class="p">(</span><span class="vg">err</span><span class="p">,</span><span class="w"> </span><span class="vg">req</span><span class="p">,</span><span class="w"> </span><span class="vg">res</span><span class="p">,</span><span class="w"> </span><span class="vg">next</span><span class="p">){</span>
<span class="w"> </span><span class="vg">console</span><span class="o">.</span><span class="vg">error</span><span class="p">(</span><span class="vg">err</span><span class="o">.</span><span class="vg">stack</span><span class="p">);</span>
<span class="w"> </span><span class="vg">res</span><span class="o">.</span><span class="vg">status</span><span class="p">(</span><span class="il">500</span><span class="p">)</span><span class="o">.</span><span class="vg">send</span><span class="p">(</span><span class="c1">'Something broke!');</span>
<span class="p">});</span>
</pre></div>
<p>终端输出:</p>
<p><img src="./images/errhadding1.jpg" alt="Mou icon"></p>
<p>浏览器返回:</p>
<p><img src="./images/errhadding2.jpg" alt="Mou icon"></p>
<p>Debugging Express</p>
<p>Expressy已经内置了debug模块,如果要用debug运行app.js:</p>
<div class="highlight"><pre><span class="err">$</span><span class="vg">DEBUG</span><span class="o">=</span><span class="nl">express:</span><span class="o">*</span><span class="w"> </span><span class="vg">node</span><span class="w"> </span><span class="vg">app</span><span class="o">.</span><span class="vg">js</span>
</pre></div>
<p><img src="./images/debug1.jpg" alt="Mou icon"></p>
<h3>知道如何查api文档</h3>
<p>中文文档地址 </p>
<p>http://www.expressjs.com.cn</p>
<p>如何在mac下面使用Dash查看离线文档</p>
<h2>更多</h2>
<ul>
<li>connect</li>
<li>express框架源码</li>
<li>反向代理(proxy,比如haproxy,nginx)</li>
<li>集群部署</li>
<li><p>可以把session存储到redis等缓存中</p>
<div class="highlight"><pre><span class="c1">// 设置 Session</span>
<span class="n">app</span><span class="p">.</span><span class="k">use</span><span class="p">(</span><span class="n">session</span><span class="p">({</span>
<span class="nl">store:</span> <span class="k">new</span> <span class="n">RedisStore</span><span class="p">({</span>
<span class="nl">host:</span> <span class="s">"127.0.0.1"</span><span class="p">,</span>
<span class="nl">port:</span> <span class="mh">6379</span><span class="p">,</span>
<span class="nl">db:</span> <span class="s">"test_session"</span>
<span class="p">}),</span>
<span class="nl">resave:</span><span class="n">false</span><span class="p">,</span>
<span class="nl">saveUninitialized:</span><span class="n">false</span><span class="p">,</span>
<span class="nl">secret:</span> <span class="p">'</span><span class="n">keyboard</span> <span class="n">cat</span><span class="p">'</span>
<span class="p">}))</span>
</pre></div></li>
<li><p>dsdsds</p></li>
</ul>
<h2>总结</h2>
</article>
</div>
</div>
</body>
</html>
<script type="text/javascript" src="toc/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="toc/js/jquery.ztree.all-3.5.min.js"></script>
<script type="text/javascript" src="toc/js/ztree_toc.js"></script>
<script type="text/javascript" src="toc/toc_conf.js"></script>
<SCRIPT type="text/javascript" >
<!--
$(document).ready(function(){
var css_conf = eval(markdown_panel_style);
$('#readme').css(css_conf)
var conf = eval(jquery_ztree_toc_opts);
$('#tree').ztree_toc(conf);
});
//-->
</SCRIPT>