Skip to content

Instantly share code, notes, and snippets.

@mazzo46
Forked from shigeki/hello.js
Created November 22, 2012 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mazzo46/4129036 to your computer and use it in GitHub Desktop.
Save mazzo46/4129036 to your computer and use it in GitHub Desktop.
第1回Node.js入門勉強会 レポート課題(回答しました)

課題1「エラーの原因」

server.close() が2回呼ばれたが、1回目の server.close() で既に閉じていたため、「Not running error」が起きた。

server.close() は、サーバを閉じる(新規の接続をしない)が、生きている接続が切断されるまでは完全に閉じない。 Chrome はひとつのコネクションで複数のリクエストを送る。今回の場合は、favicon.ico が2個目のリクエストになっている。chrome://net-internals/#events でその動きが確認できる。この2個目のリクエスト時に、エラーが発生した。

動きを確認するために、telnet を用いて、HTTP/1.0 でアクセスしてみると、

> telnet 127.0.0.1 8080 
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 200 OK
Content-Type: text/plain
Date: Fri, 23 Nov 2012 08:13:54 GMT
Connection: close

Hello World
Connection closed by foreign host.

となり、node を実行しているターミナルでも即座にnodeコマンドが終了したことを確認できた。本来、A君が想定した挙動である。

HTTP/1.1 でアクセスしてみると、

> telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 200 OK
Content-Type: text/plain
Date: Fri, 23 Nov 2012 13:21:14 GMT
Connection: keep-alive
Transfer-Encoding: chunked

c
Hello World

0

となり、サーバは稼働したままであることが確認できる。しばらくすると、nodeコマンドも終了し、telnet側で Connection closed by foreign host. が示される。

課題2「コードの修正」

問題点は2つある。

  1. Chromeがひとつのコネクションで複数のリクエストを送るので、リクエストのたびに起動する http.createServer() のコールバックに server.close() を記述しているとこのエラーが発生してしまう
  2. Keep Alive な接続なので、 server.close() しても、すぐにはサーバが終了しない

前者に関しては connection イベント内に記述しておければ、リクエストのたびに実行されることはない。後者に関しては、レスポンスヘッダーに Connection: close を記入して対応する。

// hello2.js
var http = require('http');
server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain', 'Connection': 'close'});
  res.end('Hello World¥n');
});

server.on('connection', function() {
  this.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 でアクセスすると下のようなエラーになってしまい、プログラムが正常に終了しません。

// hello.js
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/');
});
> 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)

課題1

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

課題2

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

提出方法

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

##提出期限

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

@mazzo46
Copy link
Author

mazzo46 commented Nov 26, 2012

once() で記述するといいんじゃないだろうかと思いましたが、家に戻らないと確認できないのでメモ。

// hello.js
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/');
});
// hello3.js
var http = require('http');
server = http.createServer();

server.once('request', function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain', 'Connection': 'close'});
  res.end('Hello World\n');
  server.close();
});

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

@mazzo46
Copy link
Author

mazzo46 commented Nov 26, 2012

上記の hello3.js の修正だと、Safariだとうまくサーバがクローズしますが、Chromeだと即座にクローズしません。二回目のリクエストのときも、Connection: close しないといけないということだと思いますが。

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