標籤:status 正則 資料 mat server event 啟動 org 出錯
http伺服器和用戶端
node.js標準庫提供了http模組,其中封裝了一個高效的http伺服器和一個簡易的http用戶端,http.Server是一個基於事件的HTTP伺服器,他的核心由Node.js下層的C++部分實現,而介面由JavaScript封裝,兼顧了效能和簡易性,http.request則是一個http用戶端工具,用於向http服務發起請求;
建立HTTP伺服器1. http.createServer()
//伺服器執行個體var httpServer = require("http")httpServer.createServer(function(req,res){ res.writeHead(200,{"Content-Type":"text/html"}); res.write("<h2>hello world</h2>"); res.end("<h3>你好</h3>");}).listen(2333);console.log("http server is listening at port 2333,localhost:2333");
http.createServer建立了一個http.server執行個體,將一個函數作為HTTP請求處理函數,這個函數接受兩個參數,分別是請求對象(req)和響應對象(res),在函數體內,res顯式的寫回了響應代碼200(表示請求成功),指定回應標頭為"Content-Type":"text/html",然後寫入響應體通過res.end()結束並發送,最後調用listen函數,啟動伺服器並且監聽2333連接埠
2. http.Server類
http.server是一個基於事件的http伺服器,所有的請求都被封裝為獨立的事件,開發人員只需要對他的事件編寫響應函數即可實現HTTP伺服器的所有功能,它繼承自EventEmitter
- connection: 當TCP連結建立時,該事件被觸發,提供一個參數socket,為net.Socket的執行個體,connection事件的粒度要大於request,因為用戶端在keep-Alive模式下可能在同一個連結內發送多次請求
wsServer.on(‘connection‘,function(sock){ sock.on(‘a‘,function(num1,num2){ console.log(`接到了瀏覽器發送的資料:${num1}`) }) setInterval(function(){ sock.emit(‘ttt‘,Math.random()) },500)})
- close: 當伺服器關閉時,該事件被觸發,注意不是在使用者串連斷開時,等等事件
- request: 每次接收到一個請求時觸發。
var server = new http.Server(); server.on("request", function (req, res) { res.writeHead(200, { "Content-Type": "text/html" }); res.write("<h2>node.js</h2>"); res.end("<h3>test</h3>");}).listen(2333); console.log("http server is listening at port 2333:2333");
3. http.ServerResponse
http.ServerResponse是返回給用戶端的資訊,決定了使用者最終能看到的結果,它也是由http.Server的request事件發送的,作為第二個參數傳遞,一般簡稱response或者res。
http.ServerResponse有三個重要的成員函數,用於返迴響應頭,響應內容以及結束請求:
(1)response.writeHead(statsCode,[headers]):向請求的用戶端發送回應標頭,statusCode是HTTP狀態代碼如200(請求成功),404(未找到)等,headers是一個類似關聯陣列的對象,表示回應標頭的每個屬性,該函數在請求內最多隻能調用一次,如果不調用,則會自動產生一個回應標頭。
(2)response.write(data,[encoding]):向請求的用戶端發送響應內容,data是一個buffer或者字串,表示要發送的內容,如果data是字串,那麼需要指定encoding編碼方式,預設是utf-8,在response.end之前調用,response.write可以被調用多次;
(3)response.end([data],[encoding]):結束響應,告知用戶端所有發送已經完成,當所有要返回的內容發送完畢的時候,該函數必須調用一次,他可接受兩個參數,意義和response.write相同,如果不調用該函數,用戶端將永遠處於等待狀態;
建立HTTP用戶端
http提供了兩個函數==http.request==和==http.get==,作為用戶端向HTTP伺服器發起請求;
1. http.request(options[, callback])
const postData = querystring.stringify({ ‘msg‘ : ‘Hello World!‘});const options = { hostname: ‘www.google.com‘, port: 80, path: ‘/upload‘, method: ‘POST‘, headers: { ‘Content-Type‘: ‘application/x-www-form-urlencoded‘, ‘Content-Length‘: Buffer.byteLength(postData) }};const req = http.request(options, (res) => { console.log(`狀態代碼: ${res.statusCode}`); console.log(`回應標頭: ${JSON.stringify(res.headers)}`); res.setEncoding(‘utf8‘); res.on(‘data‘, (chunk) => { console.log(`響應主體: ${chunk}`); }); res.on(‘end‘, () => { console.log(‘響應中已無資料。‘); });});req.on(‘error‘, (e) => { console.error(`請求遇到問題: ${e.message}`);});// 寫入資料到請求主體req.write(postData);req.end();
注意,在例子中調用了 req.end()。 使用 http.request() 必須總是調用 req.end() 來表明請求的結束,即使沒有資料被寫入請求主體。
如果請求過程中遇到任何錯誤(DNS 解析錯誤、TCP 級的錯誤、或實際的 HTTP 解析錯誤),則在返回的請求對象中會觸發 ‘error‘ 事件。 對於所有的 ‘error‘ 事件,如果沒有註冊監聽器,則拋出錯誤。
以下是需要注意的幾個特殊的要求標頭。
發送 ‘Connection: keep-alive‘ 會通知 Node.js,伺服器的串連應一直持續到下一個請求。
發送 ‘Content-Length‘ 要求標頭會禁用預設的塊編碼。
發送 ‘Expect‘ 要求標頭會立即發送要求標頭。 通常情況下,當發送 ‘Expect: 100-continue‘ 時,逾時時間與 continue 事件的監聽器都需要被設定。 詳見 RFC2616 章節 8.2.3。
發送 Authorization 要求標頭會替代 auth 選項計算基本驗證。
2. http.get(options[, callback])該對象在HTTP伺服器內部被建立。作為第二個參數唄傳入‘request‘事件
接收與http.request()相同的設定。 method一直設定為GET,忽略繼承自原型的屬性
- 返回: <http.ClientRequest>
http.get(‘http://nodejs.org/dist/index.json‘, (res) => { const { statusCode } = res; const contentType = res.headers[‘content-type‘]; let error; if (statusCode !== 200) { error = new Error(‘請求失敗。\n‘ + `狀態代碼: ${statusCode}`); } else if (!/^application\/json/.test(contentType)) { error = new Error(‘無效的 content-type.\n‘ + `期望 application/json 但擷取的是 ${contentType}`); } if (error) { console.error(error.message); // 消耗響應資料以釋放記憶體 res.resume(); return; } res.setEncoding(‘utf8‘); let rawData = ‘‘; res.on(‘data‘, (chunk) => { rawData += chunk; }); res.on(‘end‘, () => { try { const parsedData = JSON.parse(rawData); console.log(parsedData); } catch (e) { console.error(e.message); } });}).on(‘error‘, (e) => { console.error(`錯誤: ${e.message}`);});
3. http.ClientRequest
該對象在http.request()內部被建立並返回。它表示著一個正則處理的請求,其要求標頭已進入隊列。要求標頭仍可使用 setHeader(name, value)、getHeader(name) 和 removeHeader(name) 進行修改。實際的要求標頭會與第一個資料區塊一起發送或當調用request.end()時發送。
const http = require(‘http‘);const net = require(‘net‘);const url = require(‘url‘);// 建立一個 HTTP Proxy 伺服器const proxy = http.createServer((req, res) => { res.writeHead(200, { ‘Content-Type‘: ‘text/plain‘ }); res.end(‘okay‘);});proxy.on(‘connect‘, (req, cltSocket, head) => { // 串連到一個伺服器 const srvUrl = url.parse(`http://${req.url}`); const srvSocket = net.connect(srvUrl.port, srvUrl.hostname, () => { cltSocket.write(‘HTTP/1.1 200 Connection Established\r\n‘ + ‘Proxy-agent: Node.js-Proxy\r\n‘ + ‘\r\n‘); srvSocket.write(head); srvSocket.pipe(cltSocket); cltSocket.pipe(srvSocket); });});// Proxy 伺服器正在運行proxy.listen(1337, ‘127.0.0.1‘, () => { // 發送一個請求到Proxy 伺服器 const options = { port: 1337, hostname: ‘127.0.0.1‘, method: ‘CONNECT‘, path: ‘www.google.com:80‘ }; const req = http.request(options); req.end(); req.on(‘connect‘, (res, socket, head) => { console.log(‘已串連!‘); // 通過Proxy 伺服器發送一個請求 socket.write(‘GET / HTTP/1.1\r\n‘ + ‘Host: www.google.com:80\r\n‘ + ‘Connection: close\r\n‘ + ‘\r\n‘); socket.on(‘data‘, (chunk) => { console.log(chunk.toString()); }); socket.on(‘end‘, () => { proxy.close(); }); });});
4. http.Agent
負責為HTTP用戶端管理串連的持續與複用。它為一個給定的主機和連接埠維護著一個等待請求的隊列,且為每個請求重複使用一個單一的socket串連直到隊列為空白,此時socket會唄銷毀到一個串連池中等待被有著相同主機與連接埠的請求再次使用。 是否被銷毀或被放入串連池取決於 keepAlive 選項。
http.get(options, (res) => { // 處理事情}).on(‘socket‘, (socket) => { socket.emit(‘agentRemove‘);});
當 socket 觸發 ‘close‘ 事件或 ‘agentRemove‘ 事件時,它會被移出代理。 當打算長時間保持開啟一個 HTTP 要求且不想它留在代理中,則可以如上處理
【node】node的核心模組---http模組,http的伺服器和用戶端