Skip to content

Commit

Permalink
Merge eaad6be into da21aa8
Browse files Browse the repository at this point in the history
  • Loading branch information
azu committed Sep 16, 2015
2 parents da21aa8 + eaad6be commit f7ed9f2
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 6 deletions.
68 changes: 66 additions & 2 deletions ja/connect/README.md
Expand Up @@ -23,7 +23,7 @@ Echoサーバとは、送られてきたリクエストの内容をそのまま
```

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

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

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

> **Note** _middleware_となる関数の引数が4つであると、それはエラーハンドリングの_middleware_とするという、Connectの独自のルールがあります。
> **Note** _middleware_となる関数の引数が4つであると、それはエラーハンドリングの_middleware_とするという、Connect独自のルールがあります。
## どういう仕組み

Connectの_middleware_がどのような仕組みで動いているのかを見ていきます。

`app`に登録した_middleware_は、リクエスト時に呼び出されています。
そのため、`app`のどこかに利用する_middleware_を保持していることは推測できると思います。

Connectでは`app.stack`に_middleware_を配列として保持しています。
次のようにして`app.stack`の中身を表示見ることで、_middleware_が登録順で保持されていることがわかります。

[import connect-trace-example.js](../../src/connect/connect-trace-example.js)

後は、サーバがリクエストを受け取った時に、それぞれの_middleware_を順番に呼び出しています。

上記の例だと以下の順番で_middleware_が呼び出されることになります。

- errorHandler
- nosniff
- hello

エラーハンドリングの_middleware_は処理中にエラーが起きた時のみ呼ばれます。
そのため、通常は [nosniff.js](#nosniff.js) -> [hello.js](#hello.js) の順で呼び出されます。

[import nosniff.js](../../src/connect/nosniff.js)

`nosniff.js`は、処理が終わったら`next()`を呼び出していて、
この`next()`が次の_middleware_へ行くという意味になります。

次に、`hello.js`を見てみると、`next()`がないことがわかります。

[import hello.js](../../src/connect/hello.js)

`next()`がないということは`hello.js`がこの連続する_middleware_の最後となっていることがわかります。
仮に、これより先に_middleware_が登録されていたとしても無視されます。

つまり、処理的には以下のようにstackを先頭から一個づつ取り出して、処理していくという方法が取られています。

```js
let req = "...",
res = "...";
function next(){
let middleware = app.stack.shift();
// nextが呼ばれれば次のmiddleware
middleware(req, res, next);
}
next();// 初回
```


このような_middleware_を繋げた形を_middleware stack_と呼ぶことがあります。

このような_middleware stack_で構成されるHTTPサーバとして、
PythonのWSGI MiddlewareやRubyのRackなどが該当します。

ConnectはRackと同じく`use`で_middleware_を指定することからも分かりますが、
Rackを参考にして実装されています。

- [Ruby - Rack解説 - Rackの構造とRack DSL - Qiita](http://qiita.com/higuma/items/838f4f58bc4a0645950a#2-5 "Ruby - Rack解説 - Rackの構造とRack DSL - Qiita")

次に、この_middleware stack_をどう処理しているのかを、
具体的な実装を書きながら見て行きましょう。

## 実装してみよう
2 changes: 2 additions & 0 deletions src/connect/connect-example.js
Expand Up @@ -6,6 +6,7 @@ import assert from "assert";
import connect from "connect";
import http from "http";
import fetch from "node-fetch";

const responseText = "response text";
let app = connect();
// add Error handling
Expand All @@ -14,6 +15,7 @@ app.use(errorHandler());
app.use(nosniff());
// respond to all requests
app.use(hello(responseText));

//create node.js http server and listen on port
let server = http.createServer(app).listen(3000, request);

Expand Down
22 changes: 22 additions & 0 deletions src/connect/connect-trace-example.js
@@ -0,0 +1,22 @@
"use strict";
import errorHandler from "./errorHandler";
import hello from "./hello";
import nosniff from "./nosniff";
import connect from "connect";

const responseText = "response text";
let app = connect();
// add Error handling
app.use(errorHandler());
// add "X-Content-Type-Options" to response
app.use(nosniff());
// respond to all requests
app.use(hello(responseText));

// print middleware list
app.stack.map(({handle}) => console.log(handle));
/* =>
[Function: errorHandling]
[Function: nosniff]
[Function: hello]
*/
4 changes: 2 additions & 2 deletions src/connect/errorHandler.js
@@ -1,6 +1,6 @@
"use strict";
export default function errorHandler() {
return function (err, req, res, next) {
export default function () {
return function errorHandling(err, req, res, next) {
console.error(err.stack);
res.status(500).send(err.message);
next();
Expand Down
2 changes: 1 addition & 1 deletion src/connect/hello.js
@@ -1,6 +1,6 @@
"use strict";
export default function (text) {
return function (req, res) {
return function hello(req, res) {
res.end(text);
};
}
2 changes: 1 addition & 1 deletion src/connect/nosniff.js
Expand Up @@ -8,7 +8,7 @@ function setHeaders(res, headers) {
});
}
export default function () {
return function (req, res, next) {
return function nosniff(req, res, next) {
setHeaders(res, {
"X-Content-Type-Options": "nosniff"
});
Expand Down

0 comments on commit f7ed9f2

Please sign in to comment.