NodeJS學習筆記 (8)網絡服務-http-server(ok)

http服務端概覽

建立server

幾行代碼搞定html

var http = require('http'); var requestListener = function(req, res){ res.end('ok'); }; var server = http.createServer(requestListener); // var server = new http.Server(requestListener); 跟上面是等價的 server.listen(3000);


獲取請求方信息

HTTP版本、HTTP method、headers、url

var http = require('http'); var server = http.createServer(function(req, res){ console.log('客戶端請求url:' + req.url); console.log('http版本:' + req.httpVersion); console.log('http請求方法:' + req.method); res.end('ok'); }); server.listen(3000);

效果以下:node

客戶端請求url:/hello
http版本:1.1
http請求方法:GET
http headers:{"host":"127.0.0.1:3000","connection":"keep-alive","cache-control":"max-age=0","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","accept-encoding":"gzip, deflate, sdch, br","accept-language":"zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4"}

獲取get請求參數

var http = require('http'); var url = require('url'); var querystring = require('querystring'); var server = http.createServer(function(req, res){ var urlObj = url.parse(req.url); var query = urlObj.query; var queryObj = querystring.parse(query); console.log( JSON.stringify(queryObj) ); res.end('ok'); }); server.listen(3000);

運行以下命令git

curl http://127.0.0.1:3000/hello\?nick\=chyingp\&hello\=world

服務端輸出以下github

{"nick":"chyingp","hello":"world"}

獲取post請求參數

代碼以下web

var http = require('http'); var url = require('url'); var querystring = require('querystring'); var server = http.createServer(function(req, res){ var body = ''; req.on('data', function(thunk){ body += thunk; }); req.on('end', function(){ console.log( 'post body is: ' + body ); res.end('ok'); }); }); server.listen(3000);

經過curl構造極簡post請求shell

curl -d 'nick=casper&hello=world' http://127.0.0.1:3000

服務端打印以下。注意,在post請求中,不一樣的Content-type,post body有不小差別,感興趣的同窗能夠本身試下。windows

post body is: nick=casper&hello=world

好比本例中的post請求,HTTP報文大概以下服務器

POST / HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/x-www-form-urlencoded Cache-Control: no-cache nick=casper&hello=world

枯燥的事件

首先,咱們來看下有哪些事件網絡

checkContinue、checkExpectation、clientError、close、connect、connection、request、upgradeapp

error

var http = require('http'); var PORT = 3000; var noop = function(){}; var svr = http.createServer(noop); var anotherSvr = http.createServer(noop); anotherSvr.on('error', function(e){ console.error('出錯啦!' + e.message); }); svr.listen(PORT, function(){ anotherSvr.listen(PORT); });

運行代碼,輸出以下

出錯啦!listen EADDRINUSE :::3000

connect vs connection

二者差異很是大,雖然字眼看着有點像。

  • connect:當客戶端的HTTP method爲connect時觸發。
  • connection:當TCP鏈接創建時觸發,大部分時候能夠忽略這個事件(目測模塊內部本身用到而已)。此外,能夠經過 req.connection 來獲取這個socket(從nodejs源碼來看,req.socket、req.connection 都指向了這個socket)。此外,socket上的readable事件不會觸發(具體緣由請看模塊內部實現,反正我是還沒研究)

大部分時候都不會用到,除非你要開發HTTP代理。當客戶端發起 connect 請求時觸發(注意繞過了 requestListener)

var http = require('http'); var PORT = 3000; var server = http.createServer(function(req, res){ res.end('ok'); }); // 注意:發起connect請求的例子在 ./httpServerEventConnectClient.js 裏 server.on('connect', function(req, socket, head){ console.log('connect事件觸發'); socket.end(); // 反正我就只想舉個例子,沒打算正經處理。。。 }); server.listen(PORT);

request

當有新的鏈接到來時觸發。那跟 connection 有什麼區別呢?

好了,keep-alive閃亮登場!在持久化鏈接的狀況下,多個 request 可能對應的是 一個 connection。

先來看下沒有keep-alive的場景

var http = require('http'); var PORT = 3000; var requestIndex = 0; var connectionIndex = 0; var server = http.createServer(function(req, res){ res.end('ok'); }); server.on('request', function(req, res){ requestIndex++; console.log('request event: 第'+ requestIndex +'個請求!'); }); server.on('connection', function(req, res){ connectionIndex++; console.log('connection event: 第'+ connectionIndex +'個請求!'); }); server.listen(PORT);

經過curl連續發送3個請求,看下效果

for i in `seq 1 3`; do curl http://127.0.0.1:3000; done

服務端輸出以下

connection event: 第1個請求!
request event: 第1個請求!
connection event: 第2個請求!
request event: 第2個請求!
connection event: 第3個請求!
request event: 第3個請求!

而後,再來看下有keep-alive的場景。用 postman 構造包含 keep-alive 的請求,最終的HTTP請求報文以下

GET / HTTP/1.1 Host: 127.0.0.1:3000 Connection: keep-alive Cache-Control: no-cache Postman-Token: 6027fda7-f936-d3ac-e54f-dafcbf5e58ff

連續發送3個請求,服務端打印日誌以下

connection event: 第1個請求!
request event: 第1個請求!
request event: 第2個請求!
request event: 第3個請求!

不經常使用接口

server.close([callback]);

關閉服務器。其實就是 (new net.Server()).close(),中止接受新的鏈接。 已經鏈接上的請求會繼續處理,當全部鏈接結束的時候,server 正式關閉,並拋出 close 事件。 通常提供了callback,就不用監聽close; 監聽了close,就不用添加callback。

其餘server.listen()

其實除了 server.listen(PORT) 這種監聽方式外,還有如下幾種相對不那麼經常使用的監聽方式。用到的時候看看文檔就好了。

server.listen(handle[, callback]):監聽本地文件描述符(fd)(windows不支持),或者server,或者socket server.listen(path[, callback]):監聽本地socket,建立一個 UNIX socket server 。 server.listen([port][, hostname][, backlog][, callback])

網絡超時 server.setTimeout(msecs, callback)

設置網絡鏈接的超時時間。當超過 msecs 沒有響應時,網絡就會自動斷開。

若是傳了 callback,那麼當 timeout 發生時,就會將timeout的socket做爲參數傳給callback。

注意,通常狀況下超時的socket會自動銷燬。但當你傳了callback後,你就須要手動end或者destroy這個socket。

不經常使用屬性

server.listening:是否在監聽鏈接 server.timeout:設置超時時間(毫秒),注意,修改這個值,只會對新創建的鏈接產生影響。此外,將timeout設置爲0,就會禁用自動超時行爲。(目測不推薦) server.maxHeadersCount:客戶端最多傳送的header數量,默認是1000,若是設置爲0,則沒有限制。(問題:若是超過1000怎麼辦??)

相關文章
相關標籤/搜索