==============
$ sudo yum install -y git openssl-devel gcc-c++ make lua-devel.x86_64 ncurses-devel
$ sudo yum install mercurial
$ cd /usr/local/src
$ sudo hg clone -r 29e57603bf6f3a2e3c178a63d332ed4d2eccfa82 https://vim.googlecode.com/hg/ vim7.3.1314
$ cd vim7.3.1314
$ sudo ./configure --enable-multibyte --with-features=huge --disable-selinux --prefix=/usr/local --enable-luainterp=yes --with-lua-prefix=/usr
$ sudo make && sudo make install
$ cd ~
$ git clone https://github.com/2tom/docs.git
$ mv docs/vimrc ~/.vimrc
$ vim$ git clone git://github.com/creationix/nvm.git .nvm
$ cd .nvm
$ git checkout v0.24.0
$ cd ../
$ . .nvm/nvm.sh
$ nvm install v0.12.1
$ nvm use v0.12.1$ npm install -g yo grunt-cli gulp bowersetTimeout(function() {
console.log('Timeout');
}, 1000);
console.log('Waiting');var http = require('http');
http.createServer(function (req, res){
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('Hello World\n');
}).listen(1337, '192.168.57.31');
console.log('Server running');var http = require('http');
http.createServer(function (req, res){
var num = parseInt(req.url.slice(1));
if (isNaN(num)) {
res.end();
return;
}
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('fib('+num+') = ' + fib(num));
}).listen(1337, '192.168.57.31');
console.log('running');
function fib(n){
if (n === 0 || n === 1) return n;
return fib(n - 1) + fib(n - 2);
}"use strict";
var count = 0;
module.exports = {
say:function(name){
count++;
console.log('Hello ' + name);
},
getCount:function(){
return count;
},
resetCount:function(){
count = 0;
}
}$ node
> var hello = require('./hello');
undefined
> hello
{ say: [Function], getCount: [Function], resetCount: [Function] }
> hello.say('a');
Hello a
undefined
> hello.say('a');
Hello a
undefined
> hello.getCount();
2$ node
> require.resolve('./hello');
'/home/vagrant/hello.js'
> require.resolve('http');
'http'- node.js の http.createServer()は、APIに登録するコールバック関数はrequestイベント発生時に実行される
- javascriptで利用しているイベントはECMA-262では定義されておらず、W3CのDOM Class2 において定義されている
- node.jsでイベント自体を定義して、任意のタイミングで発生させ、そのイベントに応じた処理をする場合、処理の流れは以下のとおり
- イベントを発生するオブジェクトを作成する
- イベント発生時の処理関数(リスナ)を作成する
- イベントを定義する
- 任意のタイミングでイベントを発生させる// オブジェクトの作成
var events = require('events');
var emitter = new events.EventEmitter();
// リスナの作成
var sampleListener = function(arg1){
console.log(arg1);
}
// リスナをイベントに紐付け
emitter.on('occur', sampleListener);
or
// イベント発生
emitter.emit('occur', 'occured');
// 一度限りのイベント
emitter.once('occur', ')- EventEmitterオブジェクトには複数のリスナを登録可能
- デフォルトは10個以上のリスナ登録で警告(登録は実行できている)
- setMaxListeners()を利用すると数量変更可能(0 で無制限)
- emitter.listeners(event)で登録済みリスナを確認可能
- removeListener()でリスナ削除(全て消す場合はremoveAllListeners())
- process.on()でシグナルの受信が可能
process.on('SIGTERM', function(){
//終了処理
});- whileで実装されている
- setTimout()のコールバック実行
- process.nextTick()のコールバック実行
- I/Oイベント発生
- I/Oイベントのコールバック実行
- process.nextTick()のコールバック実行
var http = require('http');
var server = http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello');
});
server.listen(1337);
while(true); //このエントリにより、process.nextTick()で実行された
//初期化が完了せず、I/Oイベントであるrequestが飛んできても
// I/Oイベントが実施されない- events.EventEmiiterでイベントを発生させる場合、下記問題が発生する場合がある
var events = require('events');
var util = require('util');
function SyncEmitter(){
this.emit('bar');
}
util.inherits(SyncEmitter, events.EventEmitter);
var foo = new SyncEmitter;
// new の時点でevent bar がemitされており、
// 下記リスナが実行されない。
foo.on('bar', function(){
console.log('bar emitted');
});- 上記のようなケースに対応する場合は、process.nextTick()を使って リスナの登録処理後に非同期イベントが発生するようにする
var events = require('events');
var util = require('util');
function AsyncEmitter(){
var self = this;
process.nextTick(function(){
self.emit('bar');
});
}
util.inherits(AsyncEmitter, events.EventEmitter);
var foo = new AsyncEmitter();
// ここで正常にリスナが呼ばれる
foo.on('bar', function(){
console.log('bar event emitted');
});- コールバックの実行もprocess.nextTick()で非同期に呼び出すことが可能
- 下記ケースでは、コールバックを同期的に実行しようとしてエラーになります
var events = require('events');
var util = require('util');
function SyncCB(cb){
if(cb)cb();
}
util.inherits(SyncCB, events.EventEmitter);
SyncCB.prototype.setbaz = function(arg){
this.baz =arg;
}
//コールバック中にオブジェクトメソッドfoo.setbaz()を実行していますが、
//変数fooにオブジェクトが代入される前であるため、undefinedのエラーが発生
var foo = new SyncCB(function(){
foo.setbaz('bar');
console.log(foo.baz);
});上記ケースの解決方法として、process.nextTick()を使って非同期にコールバックを実行する
var events = require('events');
var util = require('util');
function AsyncCB(cb){
if(cb){
process.nextTick(function() {
cb();
});
}
}
util.inherits(AsyncCB, events.EventEmitter);
AsyncCB.prototype.setbaz = function(arg){
this.baz = arg;
}
var foo = new AsyncCB(function(){
foo.setbaz('bar');
console.log(foo.baz);
});- ストリームはNodeにおいて様々なオブジェクト内で、データの流れを扱う際に利用される抽象的なインタフェース
- ストリームにおいて、入出力データはバッファ単位でストリーム上を流れている(チャンク)
- ストリームはすべてのEventEmmiterのインスタンスとなっており、状態変更がイベントによって通知される
-
データ読み込みを司る
-
入力ストリームのイベント
//data
- 読み込み開始でイベント発生
- リスナ関数にはBufferオブジェクトもしくは、ストリームオブジェクトがsetEncoding(encoding)メソッドでエンコード指定されていれば文字列が渡される
- setEncoding()にはutf8, ascii, base64を指定可能(デフォルトはutf8)
- dataイベントが発生しなくなるとendが生成
//end
- dataイベントが発生しなくなった際に生成される
//close
- ファイル記述子が閉じられた段階で生成される
//error
- 読み込み中にエラーが発生した場合に生成され、リスナに例外オブジェクトが渡される
- errorイベントリスナが登録されていない場合は uncaughtExceptionが発生- メソッド
//destroy()
- データ読み込み処理を破棄する
- destory発行以降はイベントを生成せず、ファイル記述子は閉じられる
//pause()
- dataイベント発生を中断
- 主に入力データを出力ストリームに出力する際に利用
//resumre()
- dataイベントを再開
- 主に入力データを出力ストリームに出力する際に利用
//pipe(destination, [options])
- 出力ストリームに入力ストリームを接続
- destination = 出力ストリーム
- 入力ストリームの読み込みが完了した後、出力ストリームを閉じない場合false指定(デフォルトはtrue)-
プロパティ
-
readableプロパティを確認することで読み込みの可否が判断できる
-
sample
$ cat instream.js
var path = require('path');
fs = require('fs');
var filePath = path.join(__dirname, 'a.txt');
var readStream = fs.createReadStream(filePath);
readStream.setEncoding('utf8');
readStream.on('data', function(data){
console.log(data);
});
readStream.on('end', function(){
console.log('end');
});
readStream.on('error', function(err){
console.log('error occured');
console.log(err);
});- データ書き込みを司る
- 出力ストリームのイベント
//drain
- dataイベントが発生しなくなるとendが生成
//error
- dataイベントが発生しなくなった際に生成される
//close
- ファイル記述子が閉じられた段階で生成される
//pipe
- 読み込み中にエラーが発生した場合に生成され、リスナに例外オブジェクトが渡される
- errorイベントリスナが登録されていない場合は uncaughtExceptionが発生- メソッド
//write()
- データ書き込み
- write()にはBufferを渡せる
- write(string, [encoding],[fd]) という形で文字列を書き込み可能
- fdを使用するとUNIXストリームでのみのサポート
- write()は出力対象のデータがカーネルバッファにフラッシュされるとtrue, バッファがいっぱいの場合はfalse
- falseをうけた場合はdrainイベントを利用
- drainイベントはカーネルバッファに空きができると発生するため、
- write()->'drain'->write()という形でwriteを再開する形式が一般的
//end()
- 書き込みを終了
- Bufferと文字列を渡すことができる
//destroy()
- ファイル記述子をcloseする
- 出力キューに溜まっていたデータは送信されない
//destroySoon()
- 出力キューのデータが空になった時点でファイル記述子をcloseする-
プロパティ
-
writeableプロパティを確認することで読み込みの可否が判断できる
-
stream sample
var path = require('path'),
fs = require('fs');
var outputFilePath = path.join(__dirname, 'write.txt');
var writeStream = fs.createWriteStream(outputFilePath);
var inputFilePath = path.join(__dirname, 'read.txt');
var readStream = fs.createReadStream(inputFilePath);
writeStream.on('pipe', function(){
console.log('readableStream pipes writeStream');
})
writeStream.on('error', function(err){
console.log('error occured');
console.log(err);
});
writeStream.on('close', function(){
console.log('writable stream closed');
});
readStream.pipe(writeStream);
readStream.on('data', function(data){
console.log('>> data event occured');
});
readStream.on('end', function(){
console.log('read end');
});
readStream.on('error', function(err){
console.log('error occured');
console.log(err);
});- バイナリデータを扱う際に利用する
- v8ヒープ外部でメモリを確保する
- Bufferはバイナリファイルの読み書きに利用する
- Bufferは文字列オブジェクトとして利用する
- デフォルトエンコーディングのUTF−8以外を利用する場合エンコーディングを指定して読み出す
- Bufferはグローバルクラスなのでコードの中でBufferクラスを利用することが可能
- Bufferオブジェクト作成時にサイズを引数に指定する
- オブジェクトを直接引数に指定する方法がある
- sample
$ cat buf.js
var size = 16;
var buf = new Buffer(size);
var arr = [1,2,3,4,5,6,7,8];
var arrayBuf = new Buffer(arr);
var str = "sample";
var stringBuf = new Buffer(str);
console.log(buf);
console.log(arrayBuf);
console.log(stringBuf);
$ node buf.js
<Buffer 00 a8 97 7a 02 00 00 00 00 63 72 65 61 74 65 50>
<Buffer 01 02 03 04 05 06 07 08>
<Buffer 73 61 6d 70 6c 65>- 書き込み
- buf.write(string, [offset], [length], [encoding])
var a = 'test';
buf.write(a, 0, a.length, 'utf-8');- Bufferの文字列利用
var str = 'sample';
buf.write(str);
console.log(buf.toString('utf-8', 0,4));- Bufferの配列
var a = 'buff';
buf.write(a);
console.log(buf[0]);- copy(), concat(), slice() APIが存在する
- var fs = require('fs') でファイルシステムモジュールを使用可能
- fs.writeFile(filename, data, [encoding], [callback]) �- 絶対パス、相対パスが使える
- 相対パスはスクリプトファイルからのパスではなく、process.cwd()が返すパスからの相対になる
- 第1引数:ファイルパス
- 第2引数:書き込む内容(string or bufferの形式)
- 第3引数:ファイルの文字コード(デフォルトはnull)
- 第4引数:コールバック
- fs.readFile(filename, [encoding], [callback])
- ファイルの内容を全て読み込む �- 絶対パス、相対パスが使える
- 相対パスはスクリプトファイルからのパスではなく、process.cwd()が返すパスからの相対になる
- 第1引数:ファイルパス
- 第2引数:ファイルの文字コード(デフォルトはnull)
- 第3引数:コールバック
var fs = require('fs');
fs.writeFile('./target.txt', 'some data', 'utf-8', function(err){
if(err) throw err;
fs.readFile('./target.txt', 'utf-8', function(err, data){
if(err) throw err;
console.log(data);
});
});
- fs.readFile()をfs.writeFile()のコールバックで呼ぶようにしているのは、ファイル書き込み完了後に読み込みが実施されるようにするため
- エラーがある場合には例がをスローしている- メモリを大量に消費させないようにするために利用する
-
fs.createReadStream(path, [options])
-
プロパティ
- flag: ファイルオープンモードの文字列を指定する
- encoding: エンコーディング形式を指定(デフォルトはBuffer形式)
- mode: ファイルのオープンモード, r, r+, w+, a, a+
- bufferSize: 読み込みバッファサイズ(デフォルトは1024*64)
- start: 読み込み開始位置を表す。(デフォルトは0、先頭からよむ)
- end: 読み込み終了位置- イベント
- data: ストリームから新たなデータが読み込まれた時のイベント、リスナは読み込まれたデータを受け取る1つの引数が渡される
- end: ストリームからすべてのデータ読み込みが完了したことを示す。このイベント以降にdataイベントは発生しない
- error: ストリーム読み込みちゅうのエラーを示すイベント。このイベントにリスナが登録されていない場合、イベントループから例外がスローされる
- close: ストリームが閉じた時のイベント。HTTPリクエストなどでは発生しないが、ファイル読み込みなどでは発生する。 $ cat readStream.js
var fs = require('fs');
var rs = fs.createReadStream('./target.txt', {encoding: 'utf-8', bufferSize: 1});
rs.on('data', function(chunk){
console.log(chunk);
});
rs.on('end', function(){
console.log('<EOF>');
});- fs.createWriteStream(path, [options])
- プロパティ
- flags: ファイルオープンモード
- encoding: 文字エンコーディングを指定
- mode: ファイルオープンモードによっては、ファイルが存在しない場合ファイルが新規作成されるvar fs = require('fs');
var stdin = process.stdin; var file = process.argv[2]; var output = fs.createWriteStream(file, {flags: 'a+'}); stdin.resume(); stdin.pipe(output);
----
### ファイル記述子
- ファイルの読み書きを何度も行ったり、特定の箇所を書き換えるなどの処理を行う場合、ストリームや、ファイルの全てを読み書きする方法は不適切
- このような場合はファイル記述子を利用した高度な入出力を行う
- fs.open()でファイルオープン
- fs.open(path, flags, [mode], [callback])
- modeはデフォルト値が0666
- fs.close()でファイルclose
- fs.close(fd, [callback])
- open(),close()共にcallbackは省略可能
- openのコールバック関数は右記形式で記載する"function(err, fd)"
- closeのコールバック関数は右記形式で記載する"fucntion(err)"
#### ファイル記述子を使った入力
- fs.read(fd, buffer, offset, length, position, [callback])
- fd: オープンされているファイル記述子
- buffer: 読み込んだ内容を格納するバッファ
- offset,length: offsetで指定した位置からlengthでした長さまでbufferに格納される
- positionは読み込みを開始する位置
- callbackは読み込み完了後に呼び出されるコールバック関数。関数の形式は"function(err, byteRead, buffer)"
#### ファイル記述子を使った出力
- fs.write(fd, buffer, offset, length, postion, [callback])
- オプションの意味はfs.read()と同じ
- コールバック関数の形式はfunction(err, written, buffer)
----
### ファイルやディレクトリの操作
- fs.rename(path1, path2, [callback]), mvに相当
- fs.mkdir(path, [mode], [callback]), mkdirに相当デフォルトは0666
- fs.rmdir(path, [callback]), rm -rに相当
- fs.readdir(path, [callback]), lsコマンドに相当
- callbackは fuction(err, files)
----
### ソケット(TCP/UDP)
- Nodeは第1級プロトコルはHTTPとしているが、その実装の根幹はソケット通信モジュール
- TCPには"net", UDPには"dgram"を用いる
- net/dgramモジュールは内部的に作成したTCP/UDPオブジェクトを経由してUNIX/Windowsのシステムコールを抽象化したイベントライブラリ"libuv"を利用している
- libuvではシステムコールを呼び出し、通信イベントを管理する機能(UNIX:libev, Windows:IOCP)と組み合わせて通信イベント発生時にnetモジュールに通知するコールバックを実行させている
- net.ServerはTCPサーバを扱うクラスで、events.EventEmitterクラスを継承している
- net.createServer()メソッドを使うとnet.Serverオブジェクトを生成可能
- net.SocketはTCPのSocket接続を行うクラスで、events.EventEmitter, stream.Streamクラスを継承している
- net.connect() / net.createConnection()メソッドからnet.Socketオブジェクトを生成可能
var net = require('net'); var dgram = require('dgram');
#### TCPサーバ
** TCPサーバを生成 **
- net.createServer([options], [connectionListener])
- optionsにはソケットの挙動を指定可能
- allowHalfOpenプロパティ(デフォルトはfalse)を与えることが可能
- connectionListnerは接続を受け付けた時に実行されるリスナ関数var net = require('net'); var server = net.createServer();
** TCPサーバをリッスン **
- server.listen(port, [host], [callback])
- IPアドレス省略時は "0.0.0.0"が利用される
- callbackには"listening"イベントで実行するコールバック関数を指定// listeningイベントリスナを一緒に記述 server.listen(8000, '127.0.0.1', function(){ });
// listeningイベントリスナを別々に記述 server.listen(8000, '127.0.0.1'); server.on('listening', function(){ });
** TCPクライアントから接続を受ける **
- TCPクライアントがサーバとTCP接続を確立するとserverオブジェクトは connectionイベントを生成する。その際net.Socketオブジェクトを引数としてコールバック関数を呼び出すserver.on('connection', function(socket){ //connectionイベントの処理 });
// serverオブジェクト生成とonnectionイベントへのリスナ登録を一緒に行う場合 var server = net.createServer(function(socket)){ });
** TCPクライアントからデータを受信する **
- TCP接続後クライアントから送信されたデータをサーバで受け取るとsocketオブジェクトはdataイベントを発生させる
- dataイベントに登録されたリスナ関数は受信データ"chunk"を引数にして実行される
- “chunk”は何も指定されていない場合はbuffer型でリスナに渡される
- "chunk"はsocket.setEncoding()によって受信データエンコードが指定されている場合は指定された文字列型になるserver.on('connection', function(socket){ socket.on('data', function(chunk){ //dataイベント発生後クライアントから送信されたデータ処理を記載 }); });
** TCPクライアントにデータを送信する **
- TCPサーバからクライアントへデータを送信する場合 socket.write()メソッドを利用する
- OSへ書き込むデータの待ちがなければ、socket.write()はtrueを返却し、直ちにsocketオブジェクトでdrainイベントが発生するsocket.on('connection', function(socket){ var return = socket.write('hello'); socket.on('drain', function{ }); });
** TCPクライアントへのデータ送信が滞る **
- TCPサーバからクライアントへのデータ送信が滞りデータ送信が待ち状態になった場合、送信データはサーバ上のバッファに滞り、socket.write()の戻り値はfalseになる
- この際、サーバ上に溜まっている送信バッファサイズはsocket.buffreSizeで取得できるserver.on('connection', function(socket){ var return = socket.write('hello'); if (return === true){ console.log(socket.bufferSize); }; });
** TCPクライアントへのデータ送信滞留が解消する **
- 滞留が解消するとdrainイベントが生成されるserver.on('connection', function(socket){ var ret = socket.write('hello'); if (ret === false){ console.log(socket.bufferSize); } socket.on('drain', function(){ console.log(socket.bufferSize); }); })
** TCPクライアントから接続終了を受け付ける **
- TCPクライアントからFINを受信するとsocketは読み込み不可となり、endイベントが生成される
- net.createServer()オプションで"allowHalfOpen: true"を指定している場合、この処理は実施されない
// defaultの場合
var server = net.createServer(function(socket){
console.log("new connection:", server.connections);
socket.on('end', function(){
console.log("end connection:", server.connections);
});
});
server.listen(8000);//allowHalfOpen: true の場合
var server = net.createServer({allowHalfOpen: true}, function(socket){
console.log("net connection:", server.connections);
socket.on('end', function() {
console.log("end connection", server.connections);
});
});
server.listen(8000);** TCPクライアントとの接続を終了する **
- TCPサーバがsocketを終了する場合、socket.end()メソッドが使われる
- socketは書き込み不可となり、内部でsocket.destroy()が実施されハンドルが削除される
- server.connectionsが減り、closeイベントが発生する
var server = net.createServer(function(socket){
socket.end();
socket.on('close', function(){
console.log("socket.end");
});
});
server.listen(8000);** TCPサーバを終了する **
- server.close()
- TCPクライアントは socketオブジェクトに対するメソッド操作と、イベントリスナの登録によって実現する
- socketオブジェクト作成によりTCPHandShake:net.connect(port, [connect], [connectListener])
- net.connect() = net.createConnection()は同じ機能を担う
- connectイベント発生後はTCPサーバでのsocket操作と同じメソッド・イベントによりデータ書き込み・受信・終了といったイベント操作が可能になる
** TCPサーバを生成 **
var net = require('net');
var socket = net.connect(1338, 'localhost', function(){
console.log('TCP Client Connected');
socket.end();
});
var net = require('net');
var socket = new net.socket();
socket.connect(1338, 'localhost');
socket.on('connect', function(){
console.log('TCP Client connected');
socket.end();
});
----
### HTTP/HTTPSvar http = require('http'); var https = require('https');
#### http.Serverクラス
- evnets.EventEmitter, net.Serverを継承
- request, connectなどHTTPリクエストに関連したクラスが追加
- 実態はHTTP処理に特化したリスナを持つnet.Server
#### http.ServerRequest, http.ClientResponse(IncomingMessage)
- http.ServerRequest, http.ClientResponseはどちらも、http.IncomingMessageクラスから生成される同じオブジェクト
- events.EventEmitter, stream.Streamを継承
- stream制御を行う pause(), requme(), setEnconding()メソッドを持っている
|property|ServerRequest|ClientResponse|
|----|---|---|
|method|⭕️|❌|
|url|⭕️|❌|
|headers|⭕️|⭕️|
|trailers|⭕️|⭕️|
|httpVersion|⭕️|⭕️|
|connection|⭕️|❌|
|statusCode|❌|⭕️|
|setEncoding()|⭕️|⭕️|
|pause|⭕️|⭕️|
|resume()|⭕️|⭕️|
#### http.ServerResponse, http.ClientRequest(OutgoingMessage)
- http.ServerResponse, http.ClientRequestはどちらもhttp.OutgoingMessageクラスを継承している
- http.ClientRequestクラスはhttp.Agentクラスと密接に関連している
- socket, responseのイベントはHTTP接続時に発生するイベントであり、
- connect, upgrade, continueイベントはHTTPのリクエストやヘッダをサーバとやりとりする際に発生するイベント
#### http.Serverのエコーサーバ
- httpモジュールを読み込む
- http.Serverオブジェクトを生成する
- http.Serverのrequestイベントにリスナを登録する
- リクエストイベントリスナ内でhttp.ServerRequestオブジェクトのデータイベントを受け取り終了時に標準出力する
- http.Serverのconnectionイベントにリスナを登録する
- connectionイベントリスナ内でsocketオブジェクトのデータイベントを受け取り、終了時に標準出力する
- http.ServerでtcpポートをLISTENする
- http.Serverでerror, clientErrorイベントのリスナを登録し、エラーメッセージを標準出力するvar http = require('http'); var server = http.Server(); var port = 8000;
server.on('request', function(req, res) { var data = ''; req.on('data', function(chunk) { data += chunk; }); req.on('end', function() { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Body Echo:' + data + '\n'); }); });
server.on('connection', function(socket) { console.log('=== raw socket data ==='); socket.on('data', function(chunk){ console.log(chunk.toString()); }); socket.on('end', function(){ console.log('======================='); }); });
server.on('clientError', function(e) { console.log('Client Error: ', e.message); });
server.on('error', function(e) { console.log('Server Error: ', e.message); });
server.listen(port, function() { console.log('listening on ' + port); });
var http = require('http'); var port = 8000; var obj = {}; var server = http.createServer(function(req, res) { var remoteAddress = req.connection.remoteAddress; var header = {'Connection': 'close', 'Content-Length': 0}; var key = req.url;
switch(req.method) { case 'POST': if (obj[key]) { res.writeHead(403, header); res.end(); } else { var data = ''; req.on('data', function(chunk) { data += chunk; }); req.on('end', function() { try { obj[key] = JSON.parse(data); res.writeHead(200, header); console.log('POST', key, obj[key], ' from ' + remoteAddress); } catch (e) { res.writeHead(400, e.message, header); } res.end(); }); } break;
case 'GET':
if (obj[key]) {
var json= JSON.stringify(obj[key]);
res.writeHead(200, {
'Content-Length': Buffer.byteLength(json),
'Content-Type': 'application/json',
'Connection': 'close'
});
res.write(json);
console.log('GET', key, ' from ' + remoteAddress);
} else {
res.writeHeat(404, header);
}
res.end();
break;
case 'PUT':
if (obj[key]) {
var data = '';
req.on('data', function(chunk) {
data += chunk;
});
req.on('end', function() {
try {
obj[key] = JSON.parse(data);
res.writeHead(200, header);
console.log('PUT', key, obj[key], ' from ' + remoteAddress);
} catch(e) {
res.writeHead(400, e.message, header);
}
res.end();
});
} else {
res.writeHead(400, header);
res.end();
}
break;
case 'DELETE':
if (obj[key]) {
delete obj[key];
res.writeHead(200, header);
console.log('DELETE', key, ' from ' + remoteAddress);
} else {
res.writeHead(404, header);
}
res.end();
break;} });
server.on('error', function(e) { console.log('Server Error', e.message); });
server.on('clientError', function(e) { console.log('Client Error', e.message); });
server.listen(port, function() { console.log('listening on ' + port); });
-----
#### environment
#### appieries auth
#### basic auth
#### file upload
#### dynamo db
#### search and dlsite