1. 程式人生 > >Node.js開發入門—使用http訪問外部世界

Node.js開發入門—使用http訪問外部世界

Node.js的http模組,不但可以構建伺服器,也可以作為客戶端類庫來訪問別的伺服器。關鍵就在兩個方法:

  • http.request(options[,callback])
  • http.get(path[,callback])

除了http,還會用到FileSystem模組Stream中的stream.Readable和stream.Writable。

先來大概介紹一下相關API吧。

API解釋

http.request()方法接受一個options引數,這個引數可以是物件,用來指明你要訪問的網路資源相關的選項,比如hostname、path、port、method等。下面是一個簡單的選項,用來下載“

http://images.huxiu.com/article/cover/201509/14/074513891816.jpg”這個檔案:

var options = {
  hostname: 'images.huxiu.com',
  port: 80,
  method: 'GET',
  path: '/article/cover/201509/14/074513891816.jpg',
  keepAlive: false
};

http.request()方法返回一個http.ClientRequest例項,呼叫http.request()後,必須在調之後的某個地方呼叫一次req.end,類似下面:

var req = http.request(options, function(res){
  console.log(res.statusCode);
});
...
req.end();

否則,請求不會發出去哦,你的程式會“呆”在哪裡,茫然不知所措。

而使用http.get()則不用呼叫req.end(),因為http.get()自動幫我們做了。

我們看到http.request()和http.get()都有一個回撥方法,這個回撥方法的引數res是http.IncomingMessage的例項,一個Readable Stream,我們可以通過它來獲取服務端返回的狀態和資料。

實際上我們也可以不提供回撥給http.request()和http.get(),而是通過監聽ClientRequest的response事件來處理服務端反饋。如你所料,response事件需要的回撥和http.request()及http.get()完全一樣。程式碼類似這樣:

var req = http.request(options);
...
req.end();
req.on('response', function(res){
  ...
});

下載圖片的小示例

示例比較簡單,下載一個圖片並寫入檔案,完成後退出。程式碼如下:

var http = require('http');
var fs = require('fs');

// req is an instance of http.ClientRequest
var req = http.get('http://images.huxiu.com/article/cover/201509/14/074513891816.jpg');

/*
var options = {
  hostname: 'images.huxiu.com',
  port: 80,
  method: 'GET',
  path: '/article/cover/201509/14/074513891816.jpg',
  keepAlive: false
};

var req = http.request(options, function(res){
    console.log(res.statusCode);
});

//req.end() must be called while http.request() is use to issue a request
req.end();
*/

req.on('error', function(e){
  console.log(e);
});

var savedStream = null;
var savedFd = 0;

function endSaved(){
  if(savedStream != null){
    savedStream.end();
  }
}

//res is an instance of http.incomingMessage
req.on('response', function(res){
  console.log('statusCode - ', res.statusCode);
  console.log('contentLength - ', res.headers['content-length']);

  if(res.statusCode == 200){
    savedFd = fs.openSync('test.jpg', 'w');
    if(savedFd > -1){
      savedStream = fs.createWriteStream('test.jpg', {fd: savedFd});
      console.log('write stream created.');
      savedStream.on('finish', function(){
        console.log('data saved finished.');
        process.exit(0);
      });
    }
  }else{
    console.log('error occured.');
    process.exit(1);
  }

  res.on('data', function(chunk){
    //console.log('got data - ', chunk);
    if(savedStream != null){
      if(savedStream.write(chunk)){
        console.log('data write directly.');     
      }
    }
  });

  res.on('close', function(){
      console.log('res closed, end save now.');
      endSaved();
  });
  res.on('end', function(){
    console.log('res end, end save now.');
    endSaved();
  });
  res.on('error',  function(e){
    console.log('res err, end save now.');
    endSaved();
  });
});

我使用http.get()方法來下載圖片。也測試了http.request(),註釋起來的程式碼就是,開啟它,遮蔽http.get()那行程式碼就可以了。

當檔案下載完成時,res(http.IncomingMessage)會發射一個名為“end”的事件,我監聽它來關閉儲存的檔案。

注意我監聽req(http.ClientRequest)的response事件來處理服務端的反饋。開啟檔案時我使用了fs.openSync(),採用同步方式,這樣程式設計更簡單一些。fs.openSync()返回一個檔案描述符(fd),我把它傳遞給fs.createWriteStream來建立一個fs.WriteStream例項,然後使用它來寫檔案。

其它文章: