Node.jsのお勉強ということで。
HTTPのClient/Serverを書いてみようと思ったのですが、お題としてJSONをPOSTする/受けるClient/Serverを書いて
みましょうかと。
環境。
$ node -v
v9.4.0
使うモジュールは、HTTPのようです。
HTTP | Node.js v9.4.0 Documentation
APIは、このあたりを参考にすればいいみたいですね。
Server側。
http.createServer
Client側。
http.request
では、書いていってみましょう。
Server側
まずは、Server側から。
お題として、演算子と値2つを受け取り、演算して返すようなServerにしてみます。パスはなんでも良い感じで。結果、このように。
server.js
const http = require("http"); const port = 8080; const logger = fun => console.log(`[${new Date()}] ${fun.call(null)}`); const server = http.createServer((request, response) => { request.setEncoding("utf-8"); request.on("data", chunk => { logger(() => `received data[${chunk}]`); const data = JSON.parse(chunk); const operator = data["operator"]; const a = data["a"]; const b = data["b"]; const responseSender = d => response.end(JSON.stringify(d)); if (operator === "+") { responseSender({ result: a + b}); } else if (operator === "-") { responseSender({ result: a - b}); } else if (operator === "*") { responseSender({ result: a * b}); } else if (operator === "/") { responseSender({ result: a / b}); } else { logger(() => "Bad Request"); response.statusCode = 400; responseSender({ message: `Unknown Operator[${operator}]` }); } }); }); server.on("request", (request, response) => { const socket = request.socket; logger(() => `client connected[${socket.remoteAddress}:${socket.remotePort}] URL[${request.url} ${request.httpVersion}] Method[${request.method}]`); }); server.listen(port); logger(() => "Server startup"); /* server.close(); logger(() => "Server shutdown"); */
HTTPモジュールをロードして
const http = require("http");
http.createServerでサーバーで行う処理を書きます、と。
const server = http.createServer((request, response) => { // ここに処理を書く });
ここで受け取るリクエストはhttp.IncomingMessage、レスポンスはhttp.ServerResponseのようです。
http.IncomingMessage#setEncodingしておくと、Chunkを文字列として受け取ることができます。
request.setEncoding("utf-8"); request.on("data", chunk => { logger(() => `received data[${chunk}]`); const data = JSON.parse(chunk); const operator = data["operator"]; const a = data["a"]; const b = data["b"]; const responseSender = d => response.end(JSON.stringify(d)); if (operator === "+") { responseSender({ result: a + b}); } else if (operator === "-") { responseSender({ result: a - b}); } else if (operator === "*") { responseSender({ result: a * b}); } else if (operator === "/") { responseSender({ result: a / b}); } else { logger(() => "Bad Request"); response.statusCode = 400; responseSender({ message: `Unknown Operator[${operator}]` }); } });
今回は、JSONでパースして演算した結果を返しています。レスポンスは、http.ServerResponse#endで送り返せばよい、と。
const responseSender = d => response.end(JSON.stringify(d));
ステータスコードなども設定することができます。
response.statusCode = 400;
http.createServerで作成したServerにイベントを紐づけることもできるようで、今回は「request」イベントに対してログ出力するようにしてみました。
Event: 'request'
server.on("request", (request, response) => { const socket = request.socket; logger(() => `client connected[${socket.remoteAddress}:${socket.remotePort}] URL[${request.url} ${request.httpVersion}] Method[${request.method}]`); });
あとは、ポートを指定してリッスンすれば起動です。
server.listen(port);
logger(() => "Server startup");
停止はcloseですが、今回はコメントアウト。Ctrl-Cで止めることにします。
/* server.close(); logger(() => "Server shutdown"); */
起動。
$ node server.js [Thu Feb 01 2018 23:54:54 GMT+0900 (JST)] Server startup
確認。
$ curl -XPOST http://localhost:8080/calc -d '{ "operator": "+", "a": 8, "b": 3 }' {"result":11} $ curl -XPOST http://localhost:8080/calc -d '{ "operator": "*", "a": 8, "b": 3 }' {"result":24} $ curl -XPOST http://localhost:8080/calc -d '{ "operator": "?", "a": 8, "b": 3 }' {"message":"Unknown Operator[?]"}
OKそうです。
Server側のログ。
[Thu Feb 01 2018 23:55:36 GMT+0900 (JST)] client connected[::ffff:127.0.0.1:56404] URL[/calc 1.1] Method[POST] [Thu Feb 01 2018 23:55:36 GMT+0900 (JST)] received data[{ "operator": "+", "a": 8, "b": 3 }] [Thu Feb 01 2018 23:55:50 GMT+0900 (JST)] client connected[::ffff:127.0.0.1:56406] URL[/calc 1.1] Method[POST] [Thu Feb 01 2018 23:55:50 GMT+0900 (JST)] received data[{ "operator": "*", "a": 8, "b": 3 }] [Thu Feb 01 2018 23:55:58 GMT+0900 (JST)] client connected[::ffff:127.0.0.1:56408] URL[/calc 1.1] Method[POST] [Thu Feb 01 2018 23:55:58 GMT+0900 (JST)] received data[{ "operator": "?", "a": 8, "b": 3 }] [Thu Feb 01 2018 23:55:58 GMT+0900 (JST)] Bad Request
Client側
続いて、Client側。
Client側は、こんな感じのコードにしてみました。
client.js
const http = require("http"); const host = "localhost"; const port = 8080; const logger = fun => console.log(`[${new Date()}] ${fun.call(null)}`); const options = { host: host, port: port, method: "POST", path: "/calc", headers: { "Content-Type": "application/json" } }; const addReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `add result => ${chunk}`)); }); addReq.write(JSON.stringify({ operator: "+", a: 8, b: 3 })); addReq.end(); const minusReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `minus result => ${chunk}`)); }); minusReq.write(JSON.stringify({ operator: "-", a: 8, b: 5})); minusReq.end(); const multiplyReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `multiply result => ${chunk}`)); }); multiplyReq.write(JSON.stringify({ operator: "*", a: 8, b: 3})); multiplyReq.end(); const divideReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `divide result => ${chunk}`)); }); divideReq.write(JSON.stringify({ operator: "/", a: 8, b: 3})); divideReq.end(); const badReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `bad result => ${chunk}`)); }); badReq.write(JSON.stringify({ operator: "?", a: 8, b: 3})); badReq.end();
Serverと同様に、使うのはHTTPモジュール。
const http = require("http");
http.requestでレスポンスを受け取った時の処理を書くようですが、その第1引数にはホストやポート、HTTPメソッドなどの情報を設定します。
const host = "localhost"; const port = 8080; const options = { host: host, port: port, method: "POST", path: "/calc", headers: { "Content-Type": "application/json" } }; const addReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `add result => ${chunk}`)); }); addReq.write(JSON.stringify({ operator: "+", a: 8, b: 3 })); addReq.end();
http.requestのコールバックで受けとるのは、http.IncomingMessageのようです。
http.IncomingMessage
res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `add result => ${chunk}`));
http.IncomingMessage#setEncodingを使うことで、こちらも文字列としてデータを受け取ることができます。
データの送信は、http.requestの戻り値、http.ClientRequestに対して行います。
http.ClientRequest
writeでデータ送信、終わったらendを呼べばよいようです。
const addReq = http.request(options, res => { // }); addReq.write(JSON.stringify({ operator: "+", a: 8, b: 3 })); addReq.end();
この例は加算のものでしたが、その他の演算子も並べて…
const minusReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `minus result => ${chunk}`)); }); minusReq.write(JSON.stringify({ operator: "-", a: 8, b: 5})); minusReq.end(); const multiplyReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `multiply result => ${chunk}`)); }); multiplyReq.write(JSON.stringify({ operator: "*", a: 8, b: 3})); multiplyReq.end(); const divideReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `divide result => ${chunk}`)); }); divideReq.write(JSON.stringify({ operator: "/", a: 8, b: 3})); divideReq.end(); const badReq = http.request(options, res => { res.setEncoding("utf-8"); res.on("data", chunk => logger(() => `bad result => ${chunk}`)); }); badReq.write(JSON.stringify({ operator: "?", a: 8, b: 3})); badReq.end();
実行。
$ node client.js [Fri Feb 02 2018 00:08:13 GMT+0900 (JST)] add result => {"result":11} [Fri Feb 02 2018 00:08:13 GMT+0900 (JST)] minus result => {"result":3} [Fri Feb 02 2018 00:08:13 GMT+0900 (JST)] multiply result => {"result":24} [Fri Feb 02 2018 00:08:13 GMT+0900 (JST)] divide result => {"result":2.6666666666666665} [Fri Feb 02 2018 00:08:13 GMT+0900 (JST)] bad result => {"message":"Unknown Operator[?]"}
こちらもOKそうですね。
とりあえず、簡単なHttpClient/Serverを書いてみることができましたね。