Skip to content

Instantly share code, notes, and snippets.

@yosuke-furukawa
Forked from shigeki/hello.js
Created November 23, 2012 06:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yosuke-furukawa/4134211 to your computer and use it in GitHub Desktop.
Save yosuke-furukawa/4134211 to your computer and use it in GitHub Desktop.
第1回Node.js入門勉強会 レポート課題(回答しました。 by yosuke_furukawa)
var http = require('http');
server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
server.close();
});
server.listen(8080, 0, function () {
console.log('Server running at http://localhost:8080/');
});

第1回の勉強会で重要だった点の一つは server.close() の挙動でした。 今回は、この server.close() の挙動についての課題です。

課題

A君は、ブラウザで1回閲覧したら HelloWorld のWebサーバが終了するプログラムを作ろうと hello.js を作りました。 だけど Chrome でアクセスすると下のようなエラーになってしまい、プログラムが正常に終了しません。

課題1

なぜエラーが発生したのかその理由を記述しなさい。

課題2

このプログラムを修正してエラーが発生せずA君がやりたかったプログラムを作りなさい。

提出方法

gist か ブログかに記載して、URLをメーリングリストに連絡してください。

##提出期限

次回勉強会開催まで。(その前に出そろえば答え合わせでもしましょうか)

> node hello.js
Server running at http://localhost:8080/

net.js:1046
    throw new Error('Not running');
          ^
Error: Not running
    at Server.close (net.js:1046:11)
    at Server.<anonymous> (/home/ohtsu/hello.js:5:10)
    at Server.EventEmitter.emit (events.js:99:17)
    at HTTPParser.parser.onIncoming (http.js:1807:12)
    at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:111:23)
    at Socket.socket.ondata (http.js:1704:22)
    at TCP.onread (net.js:403:27)
@yosuke-furukawa
Copy link
Author

課題

A君は、ブラウザで1回閲覧したら HelloWorld のWebサーバが終了するプログラムを作ろうと hello.js を作りました。
だけど Chrome でアクセスすると下のようなエラーになってしまい、プログラムが正常に終了しません。

課題1

なぜエラーが発生したのかその理由を記述しなさい。

回答1

2回closeが呼ばれているから。

closeを呼ぶと新規の接続は受け付けなくなるが、既存の接続は生きたままになる。
ブラウザによって挙動は違うかもしれないが、chrome等のブラウザはウェブページにリクエストする際に、該当のページ(ここでは、"/")と既存の接続を使って"/favicon.ico"へ2回アクセスしに来る。

この時の挙動として、
1回目の"/"の時にレスポンスを返した後、server.closeが呼ばれる。
2回目の"/favicon.ico"のリクエストの時に2回目のserver.close()が呼ばれる。★(この時の挙動は以下のように書き換えると分かりやすい。)

この2回目のcloseの時、既に起動していないため、エラーとして起動中ではない事を表すnew Error('Not running');
が投げられる。

var http = require('http');
var server = http.createServer(function (req, res) {
    console.log(req.url);
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
    console.log('server close');
    server.close();
});

server.listen(8080, 0, function () {
    console.log('Server running at http://localhost:8080/');
});

出力すると以下のようになり、2回リクエストが来て、server.closeが呼ばれていることが分かる。

/
server close
/favicon.ico
server close

課題2

このプログラムを修正してエラーが発生せずA君がやりたかったプログラムを作りなさい。

回答2

server.on('connection')でconnectionイベントをフックして、接続時にcloseさせればclose処理は2回呼ばれなくなる。
あと、最後にかならずリクエストをdestroyして、レスポンスを返した後、明示的に切断するようにしておく。

var http = require('http');
var server = http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
    // 接続を切る。
    req.connection.destroy();
});

server.on('connection', function() {
    server.close();
});
server.listen(8080, 0, function () {
    console.log('Server running at http://localhost:8080/');
});

@yosuke-furukawa
Copy link
Author

結構時間かかってしまいました。
外村さんのやり方見ると、destroyよりもendイベントを検知してから切断したほうが良いのかな。。。

@hokaccha
Copy link

req.connection.destroyreq.connection.endどっちがいいのか、req.on('end')を待ったほうがいいのか、というところは僕もどっちがいいかわからなかったので答え合わせで大津さんに聞きたいと思ってました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment