Home >Web Front-end >JS Tutorial >Detailed explanation of the steps to create an HTTP file server with Node.js
This time I will bring you a detailed explanation of the steps to create an HTTP file server with Node.js. What are the precautions for creating an HTTP file server with Node.js? The following is a practical case, let's take a look.
The HelloWorld example is only for demonstration purposes. This time we will take a practical example: file server. We use Node.js to create a file server with HTTP protocol. You can use a browser or other download tools to download files from the file server.
In order to read the file, we will use the File System module (named "fs"), Stream, we will also analyze the URL, distinguish the HTTP method, and use EventEmitter.
File Server FileServer Code
Let’s start with the code, it’s still simple:
// 引入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");
The biggest change, Just the parameters passed to the createServer method.
We made a judgment based on request.method. If it is not GET, it will return 403. If so, determine whether the file exists. If it does not exist, return 404. If it exists, read the data and write it to the client. The logic is that simple. Below we introduce the new knowledge used.
File System
To use FileSystem, you must use require to introduce the fs module, just like in the previous code. The API of File System is long-standing, take a look here: https://nodejs.org/api/fs.html. We only talk about the features used.
Get file status
In our FileServer, when receiving a client request, we first obtain the file through the fs.stat() method state. The prototype of the fs.stat() method is as follows:
fs.stat(path, callback)
The first parameter is the file path, and the second parameter is the callback function. The fs.stat() method is asynchronous, and the result is returned through the callback function callback. The prototype of callback is as follows:
function(err, stats)
The first parameter indicates whether an error has occurred. The second parameter is an object of type fs.Stats, which saves the status information of the file, such as size, creation time, modification Time etc.
After the FileServer code obtains the file status, it reads the size, calls the writeHead method of http.ServerResponse, sets the HTTP status code to 200, and also sets the Content-Length header. The code is as follows:
Copy code The code is as follows:
response.writeHead(200, {"Content-Type": "text/plain", "Content-Length" : stats.size})
ReadStream
Next, we call fs.createReadStream to create a ReadStream object. ReadStream is a Stream and an EventEmitter.
The fs.createReadStream method prototype is as follows:
fs.createReadStream(path[, options])
The first parameter is the file path, the second parameter is an optional JSON object, used to specify some options for opening the file, the default value As follows:
{ flags: ‘r', encoding: null, fd: null, mode: 0666, autoClose: true }
The autoClose attribute defaults to true. When the file is read or an error occurs, the file will be automatically closed. The fd attribute can be associated with an existing file descriptor, so that the path will be ignored and the stream will be created based on an already open file. Options can also have start and end items, specify the starting and ending positions, and read specific areas of the file. If we want to implement breakpoint resumption, we need this. The usage is similar to this:
fs.createReadStream('sample.mp4', {start: 1000, end: 10000});
encoding is used to specify the encoding of the file. This has special meaning for text files. Currently, 'utf8' and 'ascii are supported ' and 'base64'.
ReadStream reads data asynchronously, reading it piece by piece. When reading part of it, it sends a data event. The data will be passed to the listener associated with the event (actually a callback method). In our code, we just call response.write to write the data to the client. Note that response.write may be called multiple times. And because we set Content-Length, chunked encoding will not be used. If we do not set Content-Length, chunked mode will be enabled by default.
ReadStream will emit the end event when it finishes reading the file, and it will emit the error event when an error occurs. We listen to these two events and simply terminate the response.
We have seen code like stream.on in the sample code. Let’s explain it below.
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内置模块提供的事件的用法完全一样。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of Detailed explanation of the steps to create an HTTP file server with Node.js. For more information, please follow other related articles on the PHP Chinese website!