Skip to content

Commit d679c5d

Browse files
committed
Merge pull request #60 from azu/fix_57
Connectの仕組み
2 parents da21aa8 + c521902 commit d679c5d

File tree

6 files changed

+95
-6
lines changed

6 files changed

+95
-6
lines changed

ja/connect/README.md

+67-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Echoサーバとは、送られてきたリクエストの内容をそのまま
2323
```
2424

2525
`app.use(middleware)` という形で、_middleware_と呼ばれる関数には`request``response`といったオブジェクトが渡されます。
26-
そのため、リクエストみてフィルタリングしたり、任意のレスポンスを返したり出来るようになっています。
26+
この`request``response`を_middleware_で処理することでログを取ったり、任意のレスポンスを返したり出来るようになっています。
2727

2828
Echoサーバでは `req.pipe(res);` という形でリクエストをそのままレスポンスとして流す事で実現されています。
2929

@@ -47,4 +47,69 @@ Echoサーバでは `req.pipe(res);` という形でリクエストをそのま
4747
基本的にどの_middleware_も`app.use(middleware)`という形で拡張でき、
4848
モジュールとして実装すれば再利用もしやすい形となっています。
4949

50-
> **Note** _middleware_となる関数の引数が4つであると、それはエラーハンドリングの_middleware_とするという、Connectの独自のルールがあります。
50+
> **Note** _middleware_となる関数の引数が4つであると、それはエラーハンドリングの_middleware_とするという、Connect独自のルールがあります。
51+
52+
## どういう仕組み
53+
54+
Connectの_middleware_がどのような仕組みで動いているのかを見ていきます。
55+
56+
`app`に登録した_middleware_は、リクエスト時に呼び出されています。
57+
そのため、`app`のどこかに利用する_middleware_を保持していることは推測できると思います。
58+
59+
Connectでは`app.stack`に_middleware_を配列として保持しています。
60+
次のようにして`app.stack`の中身を表示してみると、_middleware_が登録順で保持されていることがわかります。
61+
62+
[import connect-trace-example.js](../../src/connect/connect-trace-example.js)
63+
64+
Connectが登録された_middleware_をどう処理するかというと、
65+
サーバがリクエストを受け取った時に、それぞれ順番に呼び出しています。
66+
67+
上記の例だと以下の順番で_middleware_が呼び出されることになります。
68+
69+
- errorHandler
70+
- nosniff
71+
- hello
72+
73+
エラーハンドリングの_middleware_は処理中にエラーが起きた時のみ呼ばれます。
74+
75+
そのため、通常は [nosniff.js](#nosniff.js) -> [hello.js](#hello.js) の順で呼び出されます。
76+
77+
[import nosniff.js](../../src/connect/nosniff.js)
78+
79+
`nosniff.js`は、HTTPヘッダを設定し終わったら`next()`を呼び出していて、
80+
この`next()`が次の_middleware_へ行くという意味になります。
81+
82+
次に、`hello.js`を見てみると、`next()`がないことがわかります。
83+
84+
[import hello.js](../../src/connect/hello.js)
85+
86+
`next()`がないということは`hello.js`がこの連続する_middleware_の最後となっていることがわかります。
87+
仮に、これより先に_middleware_が登録されていたとしても無視されます。
88+
89+
つまり、処理的には以下のようにstackを先頭から一個づつ取り出して、処理していくという方法が取られています。
90+
91+
Connectの行っている処理を抽象的なコードで書くと以下のような形となっています。
92+
93+
```js
94+
let req = "...",
95+
res = "...";
96+
function next(){
97+
let middleware = app.stack.shift();
98+
// nextが呼ばれれば次のmiddleware
99+
middleware(req, res, next);
100+
}
101+
next();// 初回
102+
```
103+
104+
105+
このような_middleware_を繋げた形を_middleware stack_と呼ぶことがあります。
106+
107+
_middleware stack_で構成されるHTTPサーバとして、PythonのWSGI MiddlewareやRubyのRackなどがあります。
108+
ConnectはRackと同じく`use`で_middleware_を指定することからも分かりますが、
109+
Rackを参考にして実装されています。
110+
111+
- [Ruby - Rack解説 - Rackの構造とRack DSL - Qiita](http://qiita.com/higuma/items/838f4f58bc4a0645950a#2-5 "Ruby - Rack解説 - Rackの構造とRack DSL - Qiita")
112+
113+
次は、先ほど抽象的なコードとなっていたものを、具体的な実装にしていきます。
114+
115+
## 実装してみよう

src/connect/connect-example.js

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import assert from "assert";
66
import connect from "connect";
77
import http from "http";
88
import fetch from "node-fetch";
9+
910
const responseText = "response text";
1011
let app = connect();
1112
// add Error handling
@@ -14,6 +15,7 @@ app.use(errorHandler());
1415
app.use(nosniff());
1516
// respond to all requests
1617
app.use(hello(responseText));
18+
1719
//create node.js http server and listen on port
1820
let server = http.createServer(app).listen(3000, request);
1921

src/connect/connect-trace-example.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"use strict";
2+
import errorHandler from "./errorHandler";
3+
import hello from "./hello";
4+
import nosniff from "./nosniff";
5+
import connect from "connect";
6+
7+
const responseText = "response text";
8+
let app = connect();
9+
// add Error handling
10+
app.use(errorHandler());
11+
// add "X-Content-Type-Options" to response
12+
app.use(nosniff());
13+
// respond to all requests
14+
app.use(hello(responseText));
15+
16+
// print middleware list
17+
app.stack.map(({handle}) => console.log(handle));
18+
/* =>
19+
[Function: errorHandling]
20+
[Function: nosniff]
21+
[Function: hello]
22+
*/

src/connect/errorHandler.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
2-
export default function errorHandler() {
3-
return function (err, req, res, next) {
2+
export default function () {
3+
return function errorHandling(err, req, res, next) {
44
console.error(err.stack);
55
res.status(500).send(err.message);
66
next();

src/connect/hello.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22
export default function (text) {
3-
return function (req, res) {
3+
return function hello(req, res) {
44
res.end(text);
55
};
66
}

src/connect/nosniff.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function setHeaders(res, headers) {
88
});
99
}
1010
export default function () {
11-
return function (req, res, next) {
11+
return function nosniff(req, res, next) {
1212
setHeaders(res, {
1313
"X-Content-Type-Options": "nosniff"
1414
});

0 commit comments

Comments
 (0)