中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Node.js創建HTTP文件服務器的使用示例

發布時間:2020-08-26 01:41:13 來源:腳本之家 閱讀:200 作者:foruok 欄目:web開發

HelloWorld示例只有演示意義,這次我們來搞一個實際的例子:文件服務器。我們使用Node.js創建一個HTTP協議的文件服務器,你可以使用瀏覽器或其它下載工具到文件服務器上下載文件。

為了讀取文件,我們會用到File System模塊(名字是”fs”),Stream,我們還要分析URL,區別HTTP方法,還會用到EventEmitter。

文件服務器FileServer的代碼

先上代碼吧,依然是簡單的:

// 引入http模塊
var http = require("http"); 
var fs = require("fs");

// 創建server,指定處理客戶端請求的函數
http.createServer(
  function(request, response) {
    //判斷HTTP方法,只處理GET 
    if(request.method != "GET"){
      response.writeHead(403);
      response.end();
      return null;
    }

    //此處也可使用URL模塊來分析URL(https://nodejs.org/api/url.html)
    var sep = request.url.indexOf('?');
    var filePath = sep < 0 ? request.url : request.url.slice(0, sep);
    console.log("GET file: " + filePath);

    //當文件存在時發送數據給客戶端,否則404
    var fileStat = fs.stat("."+filePath, 
      function(err, stats){
        if(err) {
          response.writeHead(404);
          response.end();
          return null;
        }
        //TODO:Content-Type應該根據文件類型設置
        response.writeHead(200, {"Content-Type": "text/plain", "Content-Length": stats.size});

        //使用Stream
        var stream = fs.createReadStream("."+filePath);

        stream.on('data',function(chunk){
          response.write(chunk);
        });

        stream.on('end',function(){
          response.end();
        });

        stream.on('error',function(){
          response.end();
        });
      }
    );
  }
).listen(8000); 

console.log("Hello World start listen on port 8000");

最大的變化,就在傳遞給createServer方法的參數了。

我們根據request.method作了判斷,不是GET就返回403。如果是呢,就判斷文件是否存在,不存在,返回404,存在就讀取數據寫給客戶端。邏輯就是這么簡單。下面我們來介紹用到的新知識。

File System

要使用FileSystem,得用require引入fs模塊,就如前面代碼里那樣。File System的API老長老長了,看這里吧:https://nodejs.org/api/fs.html。我們只說用到的特性。

獲取文件狀態

在我們的FileServer里,收到和客戶端請求時先通過fs.stat()方法獲取文件狀態。fs.stat()方法原型如下:

fs.stat(path, callback)

第一個參數是文件路徑,第二個參數是回調函數。fs.stat()方法是異步的,結果通過回調函數callback返回。callback的原型如下:

function(err, stats)

第一個參數指示是否出現了錯誤,第二個參數是一個對象,類型是fs.Stats,保存了文件的狀態信息,比如大小、創建時間、修改時間等。

FileServer的代碼獲取到文件狀態后,讀取大小,調用http.ServerResponse的writeHead方法,設置HTTP狀態碼為200,還設置了Content-Length頭部。代碼如下:

復制代碼 代碼如下:
response.writeHead(200, {"Content-Type": "text/plain", "Content-Length": stats.size})

ReadStream

接下來呢,我們調用fs.createReadStream創建了一個ReadStream對象。ReadStream是Stream,也是EventEmitter。

fs.createReadStream方法原型如下:

fs.createReadStream(path[, options])

第一個參數是文件路徑,第二個參數是可選的JSON對象,用來指定打開文件的一些選項,默認值如下:

{ flags: ‘r', 
encoding: null, 
fd: null, 
mode: 0666, 
autoClose: true 
}

autoClose屬性默認為true,讀完文件或讀取出錯時,文件會被自動關閉。fd屬性可以關聯一個已有的文件描述符,這樣就會忽略path,根據一個已經打開的文件來創建流。options還可以有start和end項,指定起、止位置,讀取文件的特定區域。如果我們要實現斷點續傳,就需要這個了,用法類似這樣:

fs.createReadStream('sample.mp4', {start: 1000, end: 10000});

encoding用來指定文件的編碼,這對于文本文件有特殊的意義,目前支持'utf8'、'ascii'和'base64'。

ReadStream讀取數據是異步的,一塊一塊的讀,讀到一部分就發送一個data事件,數據呢,會傳遞給與事件關聯的listener(實際上是一個回調方法)。在我們的代碼里,僅僅是調用response.write把數據寫給客戶端。注意,可能會多次調用response.write哦。又因為我們設置了Content-Length,所以不會采用chunked編碼方式。如果我們不設置Content-Length,那默認會啟用chunked方式。

ReadStream讀完文件時會發射end事件,出錯時會發射error事件,我們監聽這兩個事件,簡單的終止響應。

我們在示例代碼中看到了stream.on這種代碼,下面來解釋吧。

EventEmitter

Node.js基于V8引擎實現的事件驅動IO,是其最大最棒的特色之一。有了事件機制,就可以充分利用異步IO突破單線程編程模型的性能瓶頸,使得用JavaScript作后端開發有了實際意義。

EventEmitter的基本用法

events.EventEmitter是一個簡單的事件發射器的實現,具有addListener、on、once、removeListener、emit等方法,開發者可以很方便的調用這些API監聽某個事件或者發射某個事件。

我們在示例中用到的fs.ReadStream就是一個EventEmitter,它實現了stream.Readable接口,而stream.Readable具有data、error、end、close、readable等事件。

通常我們使用EventEmitter的on或addListener來監聽一個事件,這個時間可能會多次觸發,每次觸發,我們提供的回調方法都會被調用。我們示例中的代碼就是這樣:

    stream.on('data',function(chunk){
      response.write(chunk);
    });

Node.js的事件機制,會給某個事件關聯一個回調方法列表,這樣多個關注者就可以監聽同一個事件。每個事件發射時,可能會帶有數據和狀態,這些數據是通過回調方法的參數傳遞出來的。那某一個特定的事件,它對應的回調方法的參數是什么樣子的,則由事件定義的那個類(實例)來決定。EventEmitter的emit方法原型如下:

emitter.emit(event[, arg1][, arg2][, ...])

這個原型說明一個事件的回調方法可以有一個或多個參數,也可以沒有參數。要想知道某個事件的回調方法是否有參數、每個參數的含義,只好去找相關的API文檔。stream.Readable的data事件的參數是chunk,Buffer類型,代表讀到的數據。

如果我們只想監聽某個事件一次,則可以調用EventEmitter的once方法。要想移除一個事件監聽器,可以調用removeListener,想移除所有,則可以調用removeAllListener。

自定義事件

Node.js的很多模塊都繼承自Event模塊。我們自己也可以通過繼承EventEmitter來實現自己的對象,添加自己的自定義事件。

這里有個簡單的例子:

var util=require("util");
var events = require("events");
function Ticker() {
  var self = this;
  events.EventEmitter.call(this);
  setInterval(function(){
    self.emit("tick")
    },
    1000
  );
}
util.inherits(Ticker, events.EventEmitter);

var ticker = new Ticker();
ticker.on("tick", function() {
 console.log("tick event");
});

在這個簡單的例子里,我們定義了Ticker對象,通過全局方法setInterval開啟了一個定時器,每隔1000毫秒發射一個名為“tick”的事件。

Node.js的工具模塊封裝了繼承的方法,我們調用它來的inherits方法來完成Ticker對events.EventEmitter的繼承。

自定義事件的使用方法,和Node.js內置模塊提供的事件的用法完全一樣。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

清水县| 简阳市| 民和| 萨嘎县| 濉溪县| 翼城县| 贡觉县| 滦平县| 太湖县| 天祝| 通州市| 焦作市| 威海市| 新宾| 凉山| 南康市| 曲沃县| 衡南县| 余庆县| 平度市| 邯郸市| 梅州市| 灵武市| 东至县| 会泽县| 鄂尔多斯市| 星子县| 桑日县| 唐海县| 启东市| 淮滨县| 宜州市| 青河县| 清原| 乌兰察布市| 乌拉特前旗| 子长县| 略阳县| 铅山县| 乡城县| 兰考县|