Node 深入 HTTP 模組

lio-mengxiang發表於2019-03-18

1. HTTP伺服器 #

HTTP全稱是超文字傳輸協議,構建於TCP之上,屬於應用層協議。

1.1 建立HTTP伺服器

let server  = http.createServer([requestListener]);
server.on('request',requestListener);
複製程式碼
  • requestListener 當伺服器收到客戶端的連線後執行的處理
    • http.IncomingMessage 請求物件
    • http.ServerResponse物件 伺服器端響應物件

1.2 啟動HTTP伺服器

server.listen(port,[host],[backlog],[callback]);
server.on('listening',callback);
複製程式碼
  • port 監聽的埠號
  • host 監聽的地址
  • backlog 指定位於等待佇列中的客戶端連線數
let http = require('http');
let server = http.createServer(function(req,res){
}).listen(8080,'127.0.0.1',function(){console.log('伺服器端開始監聽!')});
複製程式碼

1.3 關閉HTTP伺服器

server.close();
server.on('close',function(){});
複製程式碼
let http = require('http');
let server = http.createServer(function(req,res){
});
server.on('close',function(){
    console.log('伺服器關閉');
});
server.listen(8080,'127.0.0.1',function(){
    console.log('伺服器端開始監聽!')
    server.close();
});
複製程式碼

1.4 監聽伺服器錯誤

server.on('error',function(){
    if(e.code == 'EADDRINUSE'){
         console.log('埠號已經被佔用!);   
    }
});
複製程式碼

1.5 connection

let server = http.createServer(function(req,res){
});
server.on('connection',function(){
    console.log(客戶端連線已經建立);
});
複製程式碼

1.6 setTimeout

設定超時時間,超時後不可再複用已經建立的連線,需要發請求需要重新建立連線。預設超時時間時2分鐘

server.setTimeout(msecs,callback);
server.on('timeout',function(){
    console.log('連線已經超時');
});
複製程式碼

1.7 獲取客戶端請求資訊

  • request
    • method 請求的方法
    • url 請求的路徑
    • headers 請求頭物件
    • httpVersion 客戶端的http版本
    • socket 監聽客戶端請求的socket物件
      let http = require('http');
      let fs = require('fs');
      let server = http.createServer(function(req,res){
      if(req.url != '/favicon.ico'){
      let out = fs.createWriteStream(path.join(__dirname,'request.log'));
      out.write('method='+req.method);
      out.write('url='+req.url);
      out.write('headers='+JSON.stringify(req.headers));
      out.write('httpVersion='+req.httpVersion);
      }
      }).listen(8080,'127.0.0.1);
      複製程式碼
let http = require('http');
let fs = require('fs');
let server = http.createServer(function(req,res){
  let body = [];
  req.on('data',function(data){
    body.push(data);
  });
  req.on('end',function(){
      let result = Buffer.concat(body);
      console.log(result.toString());
  });
}).listen(8080,'127.0.0.1);
複製程式碼

1.8 querystring

querystring模組用來轉換URL字串和URL中的查詢字串

1.8.1 parse方法用來把字串轉換成物件

querystring.parse(str,[sep],[eq],[options]);
複製程式碼

1.8.2 stringify方法用來把物件轉換成字串

querystring.stringify(obj,[sep],[eq]);
複製程式碼

1.9 querystring

url.parse(urlStr,[parseQueryString]);
複製程式碼
  • href 被轉換的原URL字串
  • protocal 客戶端發出請求時使用的協議
  • slashes 在協議與路徑之間是否使用了//分隔符
  • host URL字串中的完整地址和埠號
  • auth URL字串中的認證部分
  • hostname URL字串中的完整地址
  • port URL字串中的埠號
  • pathname URL字串的路徑,不包含查詢字串
  • search 查詢字串,包含?
  • path 路徑,包含查詢字串
  • query 查詢字串,不包含起始字串?
  • hash 雜湊字串,包含#

1.10 傳送伺服器響應流

http.ServerResponse物件表示響應物件

1.10.1 writeHead

response.writeHead(statusCode,[reasonPhrase],[headers]);
複製程式碼
  • content-type 內容型別
  • location 將客戶端重定向到另外一個URL地址
  • content-disposition 指定一個被下載的檔名
  • content-length 伺服器響應內容的位元組數
  • set-cookie 在客戶端建立Cookie
  • content-encoding 指定伺服器響應內容的編碼方式
  • cache-cache 開啟快取機制
  • expires 用於制定快取過期時間
  • etag 指定當伺服器響應內容沒有變化不重新下載資料

1.10.2 Header

設定、獲取和刪除Header

response.setHeader('Content-Type','text/html;charset=utf-8');
response.getHeader('Content-Type');
response.removeHeader('Content-Type');
response.headersSent 判斷響應頭是否已經傳送
複製程式碼

1.10.3 headersSent

判斷響應頭是否已經傳送

let http = require('http');
let server = http.createServer(function(req,res){
  console.log(resopnse.headersSent?"響應頭已經傳送":"響應頭未傳送!");
  res.writeHead(200,'ok);
  console.log(resopnse.headersSent?"響應頭已經傳送":"響應頭未傳送!");
});
複製程式碼

1.10.4 sendDate

不傳送Date

res.sendDate = false;
複製程式碼

1.10.5 write

可以使用write方法傳送響應內容

response.write(chunk,[encoding]);
response.end([chunk],[encoding]);
複製程式碼

1.10.6 timeout

可以使用setTimeout方法設定響應讓超時時間,如果在指定時間內不響應,則觸發timeout事件

response.setTimeout(msecs,[callback]);
response.on('timeout',callback);
複製程式碼

1.10.7 close

在響應物件的end方法被呼叫之前,如果連線中斷,將觸發http.ServerResponse物件的close事件

response.on('close',callback);
複製程式碼

1.10.8 parser

net
onconnection

_http_server.js
連線監聽
connectionListenerInternal
socketOnData
onParserExecuteCommon
parserOnIncoming


複製程式碼

2. HTTP客戶端

2.1 向其他網站請求資料

let req = http.request(options,callback);
req.on('request',callback);
request.write(chunk,[encoding]);
request.end([chunk],[encoding]);

複製程式碼
  • host 指定目標域名或主機名
  • hostname 指定目標域名或主機名,如果和host都指定了,優先使用hostname
  • port 指定目標伺服器的埠號
  • localAddress 本地介面
  • socketPath 指定Unix域埠
  • method 指定HTTP請求的方式
  • path 指定請求路徑和查詢字串
  • headers 指定客戶端請求頭物件
  • auth 指定認證部分
  • agent 用於指定HTTP代理,在Node.js中,使用http.Agent類代表一個HTTP代理,預設使用keep-alive連線,同時使用http.Agent物件來實現所有的HTTP客戶端請求
let http = require('http');
let options = {
    hostname: 'localhost',
    port: 8080,
    path: '/',
    method: 'GET'
}
let req = http.request(options, function (res) {
    console.log('狀態嗎:' + res.statusCode);
    console.log('響應頭:' + JSON.stringify(res.headers));
    res.setEncoding('utf8');
    res.on('data', function (chunk) {
        console.log('響應內容', chunk);
    });
});
req.end();
複製程式碼

2.2 取消請求

可以使用abort方法來終止本次請求

req.abort();
複製程式碼

2.3 監聽error事件

如果請求過程中出錯了,會觸發error事件

request.on('error',function(err){});
複製程式碼

2.4 socket

建立連線過程中,為該連線分配埠時,觸發socket事件

req.on('socket',function(socket){
  socket.setTimeout(1000);
  socket.on('timeout',function(){req.abort()});
});
複製程式碼

2.5 get

可以使用get方法向伺服器傳送資料

http.get(options,callback);
複製程式碼

2.6 addTrailers

可以使用response物件的addTrailers方法在伺服器響應尾部追加一個頭資訊

let http = require('http');
let path = require('path');
let crypto = require('crypto');


let server = http.createServer(function (req, res) {
    res.writeHead(200, {
        'Transfer-Encoding': 'chunked',
        'Trailer': 'Content-MD5'
    });
    let rs = require('fs').createReadStream(path.join(__dirname, 'msg.txt'), {
        highWaterMark: 2
    });
    let md5 = crypto.createHash('md5');
    rs.on('data', function (data) {
        console.log(data);
        res.write(data);
        md5.update(data);
    });
    rs.on('end', function () {
        res.addTrailers({
            'Content-MD5': md5.digest('hex')
        });
        res.end();
    });
}).listen(8080);
複製程式碼
let http = require('http');
let options = {
    hostname: 'localhost',
    port: 8080,
    path: '/',
    method: 'GET'
}
let req = http.request(options, function (res) {
    console.log('狀態嗎:' + res.statusCode);
    console.log('響應頭:' + JSON.stringify(res.headers));
    res.setEncoding('utf8');
    res.on('data', function (chunk) {
        console.log('響應內容', chunk);
    });
    res.on('end', function () {
        console.log('trailer', res.trailers);
    });
});
req.end();
複製程式碼

2.7 製作代理伺服器

let http = require('http');
let url = require('url');
let server = http.createServer(function (request, response) {
    let {
        path
    } = url.parse(request.url);
    let options = {
        host: 'localhost',
        port: 9090,
        path: path,
        headers: request.headers
    }
    let req = http.get(options, function (res) {
        console.log(res);
        response.writeHead(res.statusCode, res.headers);
        res.pipe(response);
    });
    req.on('error', function (err) {
        console.log(err);
    });
    request.pipe(req);
}).listen(8080);複製程式碼


相關文章