原文:https://github.com/chyingp/nodejs-learning-guide
自己敲代碼:
ClientRequest概覽
當你調用 http.request(options) 時,會返回 ClientRequest實例,主要用來創建HTTP客戶端請求。
在前面的章節里,已經對http模塊的的其他方面進行了不少介紹,如http.Server、http.ServerResponse、http.IncomingMessage。
有了前面的基礎,詳細本文不難理解,本文更多的以例子為主。
簡單的GET請求
下面構造了個GET請求,訪問 http://id.qq.com/ ,並將返回的網頁內容打印在控制台下。
var http = require('http'); var options = { protocol: 'http:', hostname: 'id.qq.com', port: '80', path: '/', method: 'GET' }; var client = http.request(options, function(res){ var data = ''; res.setEncoding('utf8'); res.on('data', function(chunk){ data += chunk; }); res.on('end', function(){ console.log(data); }); }); client.end();
當然,也可以用便捷方法 http.get(options) 進行重寫
var http = require('http'); http.get('http://id.qq.com/', function(res){ var data = ''; res.setEncoding('utf8'); res.on('data', function(chunk){ data += chunk; }); res.on('end', function(){ console.log(data); }); });
簡單的post請求
在下面例子中,首先創建了個http server,負責將客戶端發送過來的數據回傳。
接着,創建客戶端POST請求,向服務端發送數據。需要注意的點有:
- method 指定為 POST。
- headers 里聲明了 content-type 為 application/x-www-form-urlencoded。
- 數據發送前,用 querystring.stringify(obj) 對傳輸的對象進行了格式化。
var http = require('http'); var querystring = require('querystring'); var createClientPostRequest = function(){ var options = { method: 'POST', protocol: 'http:', hostname: '127.0.0.1', port: '3000', path: '/post', headers: { "connection": "keep-alive", "content-type": "application/x-www-form-urlencoded" } }; // 發送給服務端的數據 var postBody = { nick: 'chyingp' }; // 創建客戶端請求 var client = http.request(options, function(res){ // 最終輸出:Server got client data: nick=chyingp res.pipe(process.stdout); }); // 發送的報文主體,記得先用 querystring.stringify() 處理下 client.write( querystring.stringify(postBody) ); client.end(); }; // 服務端程序,只是負責回傳客戶端數據 var server = http.createServer(function(req, res){ res.write('Server got client data: '); req.pipe(res); }); server.listen(3000, createClientPostRequest);
各種事件
在官方文檔里,http.RequestClient相關的事件共有7個。跟HTTP協議密切相關的有3個,分別是 connect、continue、upgrade,其他4個分別是 abort、aborted、socket、response。
- 其他:abort、aborted、socket、response
- 與HTTP協議相關:connect、continue、upgrade
跟HTTP協議相關的會相對復雜些,因為涉及HTTP協議的設計細節。其他3個相對簡單。下面分別進行簡單的介紹。
response事件
最容易理解的一個,當收到來自服務端的響應時觸發,其實跟 http.get(url, cbk) 中的回調是一樣的,看下程序運行的打印信息就知道。
var http = require('http'); var url = 'http://id.qq.com/'; var client = http.get(url, function(res){ console.log('1. response event'); }); client.on('response', function(res){ console.log('2. response event'); }); client.end();
打印信息:
1. response event
2. response event
socket事件
當給client分配socket的時候觸發,如果熟悉net模塊對這個事件應該不陌生。大部分時候並不需要關注這個事件,雖然內部其實挺復雜的。
abort/aborted 事件
這兩個事件看着非常像,都是請求中斷時觸發,差異在於中斷的發起方:
- abort:客戶端主動中斷請求(第一次調用 client.abort() 時觸發)
- aborted:服務端主動中斷請求,且請求已經中斷時觸發。
continue事件
當收到服務端的響應 100 Continue
時觸發。熟悉HTTP協議的同學應該對 100 Continue
有所了解。當客戶端向服務端發送首部 Expect: 100-continue
,服務端經過一定的校驗后,決定對客戶端的后續請求放行,於是返回返回 100 Continue
,知會客戶端,可以繼續發送數據。(request body)
upgrade事件
同樣是跟HTTP協議密切相關。當客戶端向客戶端發起請求時,可以在請求首部里聲明 'Connection': 'Upgrade'
,以此要求服務端,將當前連接升級到新的協議。如果服務器同意,那么就升級協議繼續通信。這里不打算展開太多細節,直接上官方文檔的代碼
const http = require('http'); // Create an HTTP server var srv = http.createServer( (req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('okay'); }); srv.on('upgrade', (req, socket, head) => { socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + 'Upgrade: WebSocket\r\n' + 'Connection: Upgrade\r\n' + '\r\n'); socket.pipe(socket); // echo back }); // now that server is running srv.listen(1337, '127.0.0.1', () => { // make a request var options = { port: 1337, hostname: '127.0.0.1', headers: { 'Connection': 'Upgrade', 'Upgrade': 'websocket' } }; var req = http.request(options); req.end(); req.on('upgrade', (res, socket, upgradeHead) => { console.log('got upgraded!'); socket.end(); process.exit(0); }); });
其他
除了上面講解到的屬性、方法、事件外,還有下面方法沒有講到。並不是它們不重要,篇幅有限,后面再展開。
- client.abort():中斷請求;
- client.setTimeout(timeout):請求超時設置;
- client.flushHeaders() 及早將請求首部發送出去;
- client.setSocketKeepAlive():當內部分配 socket 並連接上時,就會內部調用 socket.keepAlive();
- client.setNoDelay([noDelay]):當內部分配 socket 並連接上時,就會內部調用 socket.setNoDelay();
參考鏈接
upgrade機制: https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism
官方文檔: https://nodejs.org/api/http.html#http_class_http_clientrequest
nodejs源碼: https://github.com/nodejs/node/blob/master/lib/_http_client.js