© Jörg Krause 2017

Jörg Krause, Programming Web Applications with Node, Express and Pug , 10.1007/978-1-4842-2511-0_4

4. The Most Important Node Modules

Jörg Krause

(1)Berlin, Germany

This chapter shows the most important modules, with which elementary tasks in a Web application can be settled. Thereby it concerns the actual Node library.

Global Modules

Gobal modules are always present and do not have to be agreed upon.

Timer

Interval timers abstract to a large extent the possibilities offered according to standard by JavaScript. Absolutely use the Node variant, in order to get no problems later with other parallel running modules.

setTimeout

This instruction agrees upon the call of the callback function after a certain period in milliseconds. Optionally, arguments can be indicated. The function gives an object of the type “timeoutObject”, which can be used with “clearTimeout()”.

Syntax: setTimeout(callback, delay[, arg][, ...])
A435076_1_En_4_Figa_HTML.jpg Real Time

Node is not real time–capable and does not guarantee that the call of time-controlled callback function takes place accurately at the agreed-upon function.

clearTimeout

This function prevents the call.

Syntax: clearTimeout(timeoutObject)

setInterval

This function also corresponds to the internal JavaScript function; however, it runs under the control of Node. The callback function is called repetitive at expiration of the interval. The function gives an object of the type intervalObject, which can be used with clearInterval().

Syntax: setInterval(callback, delay[, arg][, ...])

clearInterval

This function stops the repetitive call.

Syntax: clearInterval(intervalObject)

unref

This method is offered by the objects timeoutObject and intervalObject. If a Node application ends, and interval timers are still in action, the execution is continued nevertheless, until the last interval timer ran off. With unref, it can be shown that the completion of the application stops and does not continue to implement the remaining interval timers. The repeated call of unref on the same object does not have an effect.

The functions shift the interval timer into the major loop of the application. Too many such interval timers can affect the achievement of the major loop. They should unref from there consciously and only if absolutely necessary.

ref

Before with unref into the major loop transferred interval timer can go back to its regular condition with this function. The repeated call does not have an effect.

setImmediate / clearImmediate

The method setImmediate is a more highly priotizied interval timer, which releases after I/O events and is called before setTimeout and setInterval. This interval timer gives an object immediateObject back, which can be used with clearImmediate(). Several callback functions are placed in a queue and processed in order, as they were defined. The execution of the queue takes place once per run of the major loop of the application. A new placed object is thus then implemented only if the major loop goes through next time.

Syntax: setImmediate(callback[, arg][, ...])
clearImmediate stops the execution of the timer indicated by immediateObject.
Syntax: clearImmediate(immediateObject)

Global Objects

Global objects are active in all modules. They do not have to be agreed upon separately.

global

This is the global name area . A variable in JavaScript is global in the global name area, even if it was defined with var. In Node this is not the case—the global name area is always the current module. Only by explicit access to global does a global name area become possible.

process

The process object shows information about the process.

console

With this object you have access to the console .

Buffer

The buffer obect contains the handling of buffered data.

require

This function requests a module. This function is not really global, but in each module it is automatically agreed upon locally, so that it is always available like a global function.

The method require.resolve uses the search mechanism for modules, but doesn’t load the module in case of success, but instead returns the path under which it was found. Modules can be locally or globally installed, so that the discovery page quite varies. With require.cache, modules within the object are cached if they return the features. If the module is removed from the cache by deletion of the key, the next call of ‘require’ will load the module again.

__filename

This is the file name of the up-to-date implemented code file. The name contains the dissolved, absolute path. This does not have to be the same path that the command line tool used. If the call takes place in a module, the module is the implemented code file and the path points to the module.

If, for example, the file example.js is implemented in the path /User/joerg/Apps, the following call /User/joerg/Apps/example.js returns:

console.log(__filename);

__filename is globally usable, however, in each module in which it is locally defined.

__dirname

This is the listing in which the up-to-date implemented file is. If, for example, the file example.js is implemented in the path /User/joerg/Apps*, the following call /User/joerg/Apps returns:

console.log(__dirname);

__dirname is globally usable; however, in each module it is locally defined.

module

This is a reference to the current module. The feature module.exports is used to make the functions exported by the module available. They are made available by the call of require().

module is globally usable; however, in each module it is locally defined.

exports

This is an alias for module.exports and shortens only the writing effort.

exports is globally usable; however, it is locally defined in each module.

HTTP and HTTPS

With the HTTP and HTTPS modules, almost all HTTP and HTTPS modules are supported. Communication on this level is very elementary. Frameworks such as Express abstract this and rely on http. Nevertheless, it can be meaningful for many cases to implement protocol actions directly.

Node can deal with Streams—thus there is a sequential river of bytes. This is way more effective than holding the entire data for one procedure in only one memory (buffering). The http module worries about processing data with Streams and faciliates programming substantially.

Basics

HTTP consists of a command line and head fields , which describe the instruction more clearly. In Node, the head fields are made available as JSON . An appropriate object would thus look as follows:

1   {
2     'content-length': '123',
3     'content-type': 'text/plain',
4     'connection': 'keep-alive',
5     'host': 'mysite.com',
6     'accept': '*/*'
7   }

The keys are always converted according to the specification in small letters. The values are never changed. That is already the whole interface of Node. Generally, Node is very simple with this module. Neither the head fields nor contents of a message are examined, evaluated, or treated internally.

Head fields , which have several values use “,” (comma) for the separation of the values. The only exceptions are the head fields for Cookies, which an array accepts. If fields permit only one value, Node controls this and throws an exception.

Arriving or sent head fields are made available as a rough object. This is an array with sequential pairs of keys and values that looks as follows:

1   [ 'Content-Length', '123456',
2      'content-type', 'text/plain',
3      'CONNECTION', 'keep-alive',
4      'Host', 'mysite.com',
5      'accept', '*/*' ]

Transformation and control actions take place thereafter so that the head files actually made available or sent can deviate from it.

Fields

The section describes fields , which make values available and which refer to the internal configuration.

http.METHODS returns in the form of arrays a list with HTTP verbs, which are supported. http.STATUS_codes is an array with the status codes, which know HTTP and the assigned summary. For 404 this is defined exemplarily as follows:

http.STATUS_CODES[404] === 'Not Found'

Methods

The methods make the appropriate actions possible regarding the protocol processing “http.createServer” a new instance of the HTTP server returns. Thus HTTP requests can be received and processed. The syntax looks as follows:

http.createServer([requestListener])

The callback function requestListener is a method, which gets the received data.

With http.request(option[,callback]), Node sends a request to another server. Node is thus, in this case, the client. Node uses several connections, if this is possible. However, the method treats this internally, so that you must give no consideration with programming to it. The following syntax is used:

http.request(options [, callback])

The options can be JSON or a character string. If it is a character string, url.parse() will automatically be used, in order to parse the character string. The callback method supplies an object with the answer (response).

The options have the following meaning:

  • host: the domain name or the IP address, where the request is sent. Without information, this is called “localhost.”

  • hostname: If url.parse() is used, you should use hostname instead of host.

  • port: the port for the request. Standard is the port 80.

  • localAddress: If you have several network cards, you can hereby instruct which local address (network card with the appropriate connection) is to be used by Node.

  • socketPath: Under Unix, this refers to Unix domain Sockets.

  • These are terminals for interprocess communication. You can use this on a local system or host:port syntax.

  • method: The verb (HTTP method) is in capital letters. Default value is here: GET.

  • path: the path to resources for the requirement. The default value is ‘/’. The path should contain the Querystring, if this is to be used, e.g., /index.html?=12. Illegal indications lead to an exception.

  • headers: a JSON object with the information of the header fields

  • auth: the kind of authentication. It produces the header field.

  • Authorization.

  • agent: the behavior of the Clients steers. If the information takes place, the head field Connection: keep-alive is produced. Possible values for this parameter are:

    • undefined (default): Global information for the mentioned combination is host and port.

    • object of the type agent: explicit information of all values

    • No connecting pool is formed. Each request ends with Connection: close.

  • keepAlive: The connection is kept open in a connecting pool, so that other connecting desires can access at a later time. The standard is false.

  • keepAliveMsecs: If keepAlive is used, hereby the time can be indicated in milliseconds, to which a TCP package is sent as a sign of life. The default value is 1000.

The method gives an instant to the class http.ClientRequest back. This is a writable stream. For the request, if data is needed (for example because during a POST requirement a form is sent), then these data will be written in the stream.

 1   var postData = querystring.stringify({
 2     'msg' : 'Hello World!'
 3   });
 4
 5   var options = {
 6     hostname: 'www.google.com',
 7     port: 80,
 8     path: '/upload',
 9     method: 'POST',
10     headers: {
11       'Content-Type': 'application/x-www-form-urlencoded',
12       'Content-Length': postData.length
13     }
14   };
15
16   var req = http.request(options, function(res) {
17     console.log('STATUS: ' + res.statusCode);
18     console.log('HEADERS: ' + JSON.stringify(res.headers));
19     res.setEncoding('utf8');
20     res.on('data', function (chunk) {
21       console.log('BODY: ' + chunk);
22     });
23   });
24
25   req.on('error', function(e) {
26     console.log('problem with request: ' + e.message);
27   });
28
29   req.write(postData);
30   req.end();

The actual writing takes place with req.write(postData). The use of req.end() is necessary here because the stream is otherwise closed. After terminating, no further data can be written. The requirement object req knows an even error, to which you can react in order to intercept errors. Errors can occur if one of the procedures fails with sending (dissolution of DNS, TCP error, error when parsing the head fields, etc.).

If the head filed Connection: keep-alive is manually inserted, Node recognizes this and keeps the connection open until the next request is sent.

If the head field Content-length is sent, then the use of computer field is switched off. Computer field is block-by-block sending of data. The information takes place via the head field Transfer- Encoding: chunked.

If an Except head field is used, then the head fields are sent immediately. After Expect: 100-continue, you should listen immediately to the appropriate event (with timeout). RFC2616 section 8.2.3 gives more information in addition.

If the head field Authorization is indicated, the data produced by the option auth is overwritten.

With http.get a shortened variant of the method request stands ready, the one request initiated by means of GET. Since no data is sent with GET, req.end() produces it automatically:

http.get(options[, callback])

An example shows how it goes:

1   http.get("http://www.google.com/index.html", function(res) {
2     console.log("Got response: " + res.statusCode);
3   }).on('error', function(e) {
4     console.log("Got error: " + e.message);
5   });

Classes

Some classes supply further functionality.

http.Server

The HTTP server offers an environment which reacts to actions of protocols by means of events. The events are:

  • request: function (request, response) { }

    Each arriving request releases this event. If the connection remains open (Keep Alive), then it can be that several events per request are released. The parameter request of the type http.IncomingMessage and response is “http.ServerResponse”.

  • connection: function (socket) { }

    Releases, if the TCP stream object was opened. The parameter socket is of the type net.Socket.

  • close: unction () { }

    Releases, if the connection was closed.

  • checkContinue: function (request, response) { }

    This event reacts to Expect: 100-continue. If that is not treated, the server reacts automatically with 100 Continue. If a treatment takes place, then it must be reacted with response.writeContinue(), if data is to be sent. Otherwise, communication with 400 Bad Request or a comparable error will happen. If this event is produced and treated, request won’t be released.

  • connect: function (request, socket, head) { }

    Releases, if the client is connected by means of HTTP CONNECT. The parameter request is http.IncomingMessage. The parameter socket is of the type net.Socket. head against it is an instance of buffer.

  • upgrade: function (request, socket, head) { }

    With opened connection, this event is released if a client wants to upgrade the connection. The parameter request is of the type http.IncomingMessage. The parameter socket is of the type “net.Socket”. head, however, is an instance of buffer. An upgrade is in principle a protocol change, e.g., from HTTP 1.1. to HTTP 2.0. to WebSockets, to IRC, etc. In practice, this is relevant only for WebSockets. In addition, look at the following information: Draft 1.

  • clientError: function (exception, socket) { }

    If the client supplies an eror, this event will be treated.

    The parameter socket is of the type net.Socket.

The events are reached by means of the method on:

1   var http = require("http");
2   var server = http.createServer();
3
4   server.on("request", function (req, res) {
5       res.end("this is the response");
6   });
7
8   server.listen(3000);

Methods for http.Server

The object server itself, the createServer, has some methods, which are likewise interesting.

With server.list, the server begins at the indicated port and the appropriate address—thus the Socket—to listen. If the host name is not indicated, all IP addresses on the machine are launched (only IPv4). The following variants exist:

server.listen(port[, hostname][, backlog][, callback]) server.listen(path[, callback])
server.listen(handle[, callback])

A435076_1_En_4_Figb_HTML.jpg On an Unix system, a Unix Socket in the form of a file names can be used instead of the host name. Alternatively, the Socket path can be used. The other configuration parameters are then non-existing. On Windows, this is not supported:

The parameter backlog is the length of the buffer queue for arriving connections. If a connecting desire arrives and the procedure is still in processing, then Node takes up this request to this queue.

The default value is 511 (!sic). Values to 1,000 are meaningful. Long waiting times in Clients suggest that a connection is to be expected, while Node is also hardly able to process these.

If handle is used, then this is an object that describes the “server” or a “Socket.”

The function is asynchronous and works with the callback method callback.

With server.close, the server stops accepting desired connections:

server.close([callback])

Since connections are not available , a value can be set with “server.setTimeout”, which determines how long the waiting time will take:

server.setTimeout(msecs, callback)

The value is indicated in milliseconds. The default value amounts to two minutes. “server.timeout” shows the set value.

With server.maxHeadersCount, the number of head fields is limited. According to standard this is 1,000; with 0 the value is unlimited.

The class http.ServerResponse

An instance of this class is provided internally. This is the type, which is handed over by the parameter response in the callback function of the event “request.” This is the answer object. It implements a writable stream. This works with events.

close: function () { }                  
  • shows that the connection was closed before end was able to send the data. finish: function () { }

  • is released if the transmission of the answer is settled. For Node, this is the moment of the delivery to the operating system. It is not clear that the data leaves the compuer or that the client received it.

On an instance of this class, various operations are possible. response.writeContinue sends an HTTP/1.1. 100 Continue to the client to request that the data can be sent. With reponse.writeHead, Node sends the head (Status code plus head fields) to the client. The status code is the three-figure HTTP code, for example, 200 or 404. The head fields can be indicated accordingly. The following syntax is applicable:

response.writeHead(statusCode[, statusMessage][, headers])
1   var body = 'hello world';
2   response.writeHead(200, {
3     'Content-Length': body.length,
4     'Content-Type': 'text/plain' }
5   );

This method may be called only once and must happen before response.end().

Alternatively you can work with response.write() and response.end(). If response.write() is used and the answer hasn’t been terminated yet, Node computes the head fields accumulated with the call of writeHead.

A435076_1_En_4_Figc_HTML.jpg Content Length

The length head field contains the size in bytes. If the text is coded in UTF-8 or another procedure, that is not the number of indications. Use Buffer.byteLength() in order to determine the correct value. Node does not check whether the information fits in Content-Length.

With response.setTimeout the timeout value is set in milliseconds:

response.setTimeout(msecs, callback)

The callback function callback is called if the time runs out. If no information takes place upon completion, the appropriate objects for Socket, Server, Response, etc., are cleared up. However, if a callback function is present, then you must settle this in the function.

With response.statusCode, you specify which status code is used. This is not necessary if you work with writeHead.

response.statusCode = 404;

The feature contains the actual value after sending the answer.

Specify which status code is used with the response.statusMessage feature. This is not necessary if you work with writeHead. The information is only meaningful if you want to send something else as the standard text:

response.statusMessage = 'Not found';

The feature contains the actual value after sending the answer. response.setHeader produces a head field or replaces it, if it is already present in the list of head fields which can be sent. If several head fields are to be produced, you can use an array. The following syntax is valid:

response.setHeader(name, value)

1   response.setHeader("Content-Type", "text/html");
2   response.setHeader("Set-Cookie", ["type=ninja", "language=javascript
3   "]);

Everyone can determine with response.headersSent, whether the head fields were already sent or not.

response.sendDate is a boolean feature that shows if the head field Date shall be produced. If this head field was already manually entered, the manual entry is not overwritten.

A435076_1_En_4_Figd_HTML.jpg In HTTP ist das Kopffeld Date ein Pflichtfeld. Sie sollten dies nur zu Testzwecken unterdrücken.

response.getHeader is a cunning head field, as long as it wasn’t sent yet. After sending, no access is possible anymore. The name considers upper and lower case—all head field names are written in lower case internally. The syntax of this method is as follows:

response.getHeader(name)

1   var contentType = response.getHeader('content-type');

response.removeHeader removes a head field, as long as it was not sent yet:

1   response.removeHeader("Content-Encoding");

The method response.write writes a quantity of data. That leads to the fact that implicitly specified head fields are sent, because these will transfer before the data. If response.writeHead() was used before, the head fields defined there are used.

response.write(chunk[, encoding][, callback])

The method can be called several times, in order to transmit data block-by-block (chunks). The parameter chunk can be a character string or byte stream. If the data is a character string, the parameter determines encoding, and then how these are converted in bytes. The default value is “utf-8”. The callback method callback is called, if the data was sent.

A435076_1_En_4_Fige_HTML.jpg The method serves for sending data on the lowest level. No processing of contents in any form takes place here.

The method returns true if the data was handed over to the internal buffer, false is returned if the data remained in the memory. “drain” is produced, if the buffer is empty again.

With response.addTrailers(headers), head fields are attached to the end of the message. That can be done only with data, which is supplied to the computer field.

1   response.writeHead(200, { 'Content-Type': 'text/plain',
2                             'Trailer': 'Content-MD5' });
3   response.write(fileData);
4   response.addTrailers({
5      'Content-MD5': "7895bf4b8828b55ceaf47747b4bca667"
6   });
7   response.end();

With “response.end” it is communicated that the transmission is terminated. This method must always be called.

response.end([data][, encoding][, callback])

If data is indicated internally, response.write(data, encoding) is called. The callback function is called if all data was sent.

Class http.ClientRequest

An instance of this class is provided through http.request(). This is the requirement object. The head fields are thereafter still alterable with the methods setHeader(name, value), getHeader(name), and removeHeader(name). Node is in this case the client, which sends requests to another server.

In order to get the answer of the produced and sent request, you hand an event treatment function over for the event response. The event returns an instance of the class IncomingMessage. If the answer should contain data, it can be accessed with the event data. Alternatively you can listen to it with the event readable and then read it actively with the event response.read().

A435076_1_En_4_Figf_HTML.jpg Node does not check whether the information in Content-Length is correct and fits with the content. Do not rely on this value!

 1   var http = require('http');
 2   var net = require('net');
 3   var url = require('url');
 4
 5   // Create proxy for tunnel
 6   var proxy = http.createServer(function (req, res) {
 7     res.writeHead(200, {'Content-Type': 'text/plain'});
 8     res.end('okay');
 9   });
10   proxy.on('connect', function(req, cltSocket, head) {
11     // Connect previous server
12     var srvUrl = url.parse('http://' + req.url);
13     var srvSocket = net.connect(srvUrl.port, srvUrl.hostname, 14                                 function() {
15       cltSocket.write('HTTP/1.1 200 Connection Established ' +
16                       'Proxy-agent: Node-Proxy ' +
17                       ' ');
18       srvSocket.write(head);
19       srvSocket.pipe(cltSocket);
20       cltSocket.pipe(srvSocket);
21     }); // End function
22   });
23
24   // Proxy runs now
25   proxy.listen(1337, '127.0.0.1', function() {
26
27     // Anforderung erstellen
28     var options = {
29       port: 1337,
30       hostname: '127.0.0.1',
31       method: 'CONNECT',
32       path: 'www.google.com:80'
33     };
34
35     var req = http.request(options);
36     req.end();
37
38     req.on('connect', function(res, socket, head) {
39       console.log('got connected!');
40
41       // Anforderung über Tunnel
42       socket.write('GET / HTTP/1.1 ' +
43                    'Host: www.google.com:80 ' +
44                    'Connection: close ' +
45                    ' ');
46       socket.on('data', function(chunk) {
47         console.log(chunk.toString());
48       });
49       socket.on('end', function() {
50         proxy.close();
51       });
52     });
53   });

A further event must be treated if necessary: upgrade. The callback function has the following signature:

function (response, socket, head)

An upgrade is necessary if the client liked to change the protocol, for example, from HTTP 1.1 to HTTP 2.0 or to WebSockets.

 1   var http = require('http');
 2
 3   // Create an HTTP server
 4   var srv = http.createServer(function (req, res) {
 5     res.writeHead(200, {'Content-Type': 'text/plain'});
 6     res.end('okay');
 7   });
 8   srv.on('upgrade', function(req, socket, head) {
 9     socket.write('HTTP/1.1 101 Web Socket Protocol Handshake ' +
10                  'Upgrade: WebSocket ' +
11                  'Connection: Upgrade ' +
12                  ' ');
13  
14     socket.pipe(socket); // Echo zurück
15   });
16
17   // now that server is running
18   srv.listen(1337, '127.0.0.1', function() {
19
20     // make a request
21     var options = {
22       port: 1337,
23       hostname: '127.0.0.1',
24       headers: {
25         'Connection': 'Upgrade',
26         'Upgrade': 'websocket'
27       }
28     };
29
30     var req = http.request(options);
31     req.end();
32
33     req.on('upgrade', function(res, socket, upgradeHead) {
34       console.log('got upgraded!');
35       socket.end();
36       process.exit(0);
37     });
38   });

The event continue arises if the server sends a 100 Continue, which usually is a reaction to the request Expect: 100-continue. This is the request for the client that the data of the message may be sent.

With request.flushHeaders(), a method is available which sends the head fields actively. Normally, Node buffers head fields and sends these not immediately if they are defined. Buffering serves the optimization, so that all head fields fit ideally into a TCP package. With flush() and flushHeaders(), the optimization mechanism is ignored.

The actual writing of the data is done by request.write(chunk[, encoding][, callback]) with block-by-block (chunk) sending of the data. The head field [‘Transfer-Encoding’, ‘chunked’] should be used in order to show the receiving station that the blocks are used for this to work.

The argument chunk can be a buffer or a character string . The callback function is called if the data was sent.

With request.end([data][, encoding][, callback]), the requirement is terminated. If parts of the data were not sent yet, “flush” is forced. If blocks were used, now the final sequence “0 ” is sent.

With data the result is identical to the call of request.write(data, encoding), followed by request.end(callback). The callback function is called if the data was sent.

With request.abort(), the requirement can be canceled. With request.setTimeout(timeout[,callback]), the timeout value is specified.

http.IncomingMessage

An arriving message of the type IncomingMessage is produced by http.Server or http.ClientRequest. The object is handed over as the first argument request and/or response of the event. The object implements a readable stream, and some further methods and features, as well.

With the event close, it is shown that the connection was closed. This event can occur only once.

The feature message.httpVersion shows which HTTP version was used. That is, either “1.1” or “1.0”, etc. To get access to the version details, response.httpVersionMajor and response.httpVersionMinor can be of help.

The head fields can be selected over message.headers. Head fields are always internally marked with small letters. The output means console.log(request.headers); and produces the following JSON object:

1   {
2     'user-agent': 'curl/7.22.0',
3     host: '127.0.0.1:8000',
4     accept: '*/*'
5   }

If you want to read the head fields directly, without the treatment of Node, message.rawHeaders would be the right choice. It is interesting here that this is no listing with pairs of keys, but an array with alternatively head fields and their values.

 1   [
 2     'user-agent',
 3     'this is invalid because there can be only one',
 4     'User-Agent',
 5     'curl/7.22.0',
 6     'Host',
 7     '127.0.0.1:8000',
 8     'ACCEPT',
 9     '*/*'
10   ]

In the end event (and only there) the message.trailers and message.rawTrailers can be queried in blocks (chunks) and transferred. By means of Trailer, block-by-block the messages will correctly be put together.

A temporal delimitation of the processing of the message can be achieved with message.setTimeout(msecs, callback). The information of the time effected is in milliseconds, after the expiration callback is called.

The used HTTP verb can be inferred from the feature message.method. In message.url, the URL stands for the requirement. These features function only if the object comes from http.Server. The following requirements should serve as examples:

1   GET /status?name=ryan HTTP/1.1

2   Accept: text/plain
3   

In request.url stands then: “/status?name=ryan” For processing , the URL serves parse:

1   var url = require('url');
2   console.log(url.parse('/status?name=ryan'));

The following output is produced:

1   {
2     href: '/status?name=ryan',
3     search: '?name=ryan',
4     query: 'name=ryan',
5     pathname: '/status'
6   }

The processing of Querystring can take place in a further step:

1   var url = require('url');
2   console.log(url.parse('/status?name=ryan', true));

The following output is produced:

1   {
2     href: '/status?name=ryan',
3     search: '?name=ryan',
4     query: { name: 'ryan' },
5     pathname: '/status'
6   }

The status code, which is used during the answer of the messages, stands in message.statusCode. The suitable text for that can be found in message.statusMessage. The code is three-figure HTTP code, e.g., 404. This value is only reachable if the object comes from http.ClientRequest.

By means of message.socket access to net.Socket objects exists, which is assigned to the used connection.

HTTPS

HTTPS is HTTP, which continues on TLS (Transport Layer Security). The actual TLS version corresponds to the earlier standard SSL 3.0. TSL is the successor of SSL.

If HTTPS is used, then you can determine the authentication data of the clients with: request.connection.verifyPeer() and request.connection.getPeerCertificate().

The server is provided as follows with HTTP:

https.createServer(options[, requestListener])

 1   // Abruf: https://localhost:8000/
 2   var https = require('https');
 3   var fs = require('fs');
 4
 5   var options = {
 6     key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
 7     cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
 8   };
 9
10   https.createServer(options, function (req, res) {
11     res.writeHead(200);
12     res.end("hello world ");
13   }).listen(8000);
14   Or
15
16   var https = require('https');
17   var fs = require('fs');
18
19   var options = {
20     pfx: fs.readFileSync('server.pfx')
21   };
22
23   https.createServer(options, function (req, res) {
24     res.writeHead(200);
25     res.end("hello world ");
26   }).listen(8000);

The used methods and features resemble to a large extent those of the module http:

 1   var https = require('https');
 2
 3   var options = {
 4     hostname: 'encrypted.google.com',
 5     port: 443,
 6     path: '/',
 7     method: 'GET'
 8   };
 9
10   var req = https.request(options, function(res) {
11     console.log("statusCode: ", res.statusCode);
12     console.log("headers: ", res.headers);
13
14     res.on('data', function(d) {
15       process.stdout.write(d);
16     });
17   });
18   req.end();
19
20   req.on('error', function(e) {
21     console.error(e);
22   });

The argument optionshas further options, unlike “HTTP”:

  • pfx: certificates, private keys and information of the certificate authority (CA). The default value is “null”.

  • key: the private key. The default value is “null”.

  • passphrase: the pass phrase for the private key. The default value is “null”.

  • cert: public x509 certificate. The default value is “null”.

  • ca: an array of certificate authority, which are inquired, in order to dissolve the host

  • ciphers: a character string which merges or excludes the used ciphers. See OpenSSL 2 to take a look at how this is designed.

  • rejectUnauthorized: If true, the certificate will be checked about its certificate authority. An error even arises if the examination fails. The default value is true. You should switch this off in test environments if necessary. This examination takes place on the level of the connection establishment, before the HTTP request was sent.

  • secureProtocol: the method, for example TLSv1. Available methods stand in “SSL_METHODS”.

 1   var options = {
 2     hostname: 'encrypted.google.com',
 3     port: 443,
 4     path: '/',
 5     method: 'GET',
 6     key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
 7     cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
 8   };
 9   options.agent = new https.Agent(options);
10
11   var req = https.request(options, function(res) {
12   ...
13   }

You can also this without an “agent ” object.

 1   var options = {
 2     hostname: 'encrypted.google.com',
 3     port: 443,
 4     path: '/',
 5     method: 'GET',
 6     key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
 7     cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem'),
 8     agent: false
 9   };
10
11   var req = https.request(options, function(res) {
12     ...
13   }

Handling Files and Paths

Node can access files directly over the appropriate modules and all typical operations on these files as well as on paths and folders.

Access to the File System

The file system access under Node is made available by the module fs. All calls can take place both synchronously and asynchronously. While for client page scripts (in principle only asynchronous) one of the calls is meaningful, this can be regarded on the server somewhat differently. Since the result of an action is possibly sending JSON or HTML, one usually waits anyway, until the result is present. Asynchronous calls do not have an advantage. However, if your environment is strongly burdening and scripts have noticeable running times, then Node will only always work on a request and then all synchronous actions for these will occur. All other requests wait. Now, if a script waits substantially for a file operation for this part, then the process is altogether slowed down.

A435076_1_En_4_Figg_HTML.jpg Synchronously or Asynchronously

You rarely do something wrong with asynchronous calls, even if no noticeable effect arises. Program always asynchronously, unless there are good reasons to do it differently and you know the results that will happen from it.

Asynchronous calls always use a callback function as last argument. The callback functions have different signatures. However, it is common that the first argument of the callback function is an exception object (exception), which shows errors. In case of success, this object is undefined or “null,” so that a simple test with if(!exception) can start.

Synchronous calls always produce an immediate exception. If an error arises, use try/catch for treating the error conditions.

Here is a first example of the asynchronous use:

1   var fs = require('fs');
2
3   fs.unlink('/tmp/hello', function (err) {
4     if (err) throw err;
5     console.log('successfully deleted /tmp/hello');
6   });

Here, the same example of the synchronous use (consider the suffix Sync in line 3):

1   var fs = require('fs');
2
3   fs.unlinkSync('/tmp/hello');
4   console.log('successfully deleted /tmp/hello');

Asynchronous calls don’t return in deterministic time. If you start several calls, the sequence is not guaranteed with the return. The following example is therefore error-prone:

1   fs.rename('/tmp/hello', '/tmp/world', function (err) {
2     if (err) throw err;
3     console.log('renamed complete');
4   });
5   fs.stat('/tmp/world', function (err, stats) {
6     if (err) throw err;
7     console.log('stats: ' + JSON.stringify(stats));
8   });

Here it can happen that the call of fs.stat in line 5 is successful, before the renaming in line one with “fs.rename” has been finished. Therefore, you should concatenate several asynchronous calls that connect with each other:

1   fs.rename('/tmp/hello', '/tmp/world', function (err) {
2      if (err) throw err;
3      fs.stat('/tmp/world', function (err, stats) {
4         if (err) throw err;
5         console.log('stats: ' + JSON.stringify(stats));
6      });
7   });

You can work with absolute or relative paths. If you work with relative paths, it should be clear that the origin of the current listing is the process in which the script is implemented. This can be determined with process.cwd(). Usually this is Node core.

Sometimes it can occur that you start the action, but don’t need the result. Then you can omit the callback function. But if an error occurs now, the entrance to the exception object will be missing. In order to arrive nevertheless at this error message, you use the environment variable NODE_DEBUG. The following script shows how this takes place:

File: script.js

1   function bad() {
2     require('fs').readFile('/');
3   }
4   bad();

Use the script as follows:

1   $ env NODE_DEBUG=fs node script.js

The following output occurs:

 1   fs.js:66
 2           throw err;
 3                       ^
 4   Error: EISDIR, read
 5       at rethrow (fs.js:61:21)
 6       at maybeCallback (fs.js:79:42)
 7       at Object.fs.readFile (fs.js:153:18)
 8       at bad (/path/to/script.js:2:17)
 9       at Object.<anonymous> (/path/to/script.js:5:1)
10       <etc.>

This certainly only succeeds if the path cannot really be read. In the example, the root “/” is accessed.

Functions for the File Access

This section shows the most important file access functions. Here, only the asynchronous methods are shown. Most methods also exist synchronously. They then have the suffix “Sync” in the name (“rename” versus “renameSync”). With the synchronous methods, the callback function is void.

fs.rename(oldPath, newPath, callback) renames a file. With fs.ftruncate(fd, len, callback), you empty a file. Either a file description object or a path for the file is used for this.

The function group fs.fchown(fd, uid, gid, callback) and fs.lchown(path, uid, gid, callback) sets the owner of a file. Either a file description object is used or the path for the file. The group fs.fchown(fd, mode, callback), fs.chown(path, mode, callback) sets rights to a file. Either a file description object is used or the path for the file.

A435076_1_En_4_Figh_HTML.jpg These functions are applicable only on Unix systems.

A435076_1_En_4_Figi_HTML.jpg On Windows you now use the function icals if the setting of rights is necessary, which you can access in the Windows command line, e.g., as follows: icacls onlyread.txt /inheritance:r/grant %username%:r

With fs.fstat(fd, callback), fs.stat(path, callback), or fs.lstat(path, callback), you determine information about a file. The callback function has two arguments: err and stats. stats is of the type fs.Stats. Istat processes the link if it’s a symbolic link, not the goal of the link.

With fs.realpath(path[, cache], callback), you determine the genuine path of a file.

1   var cache = {'/etc':'/private/etc'};
2   fs.realpath('/etc/passwd', cache, function (err, resolvedPath) {
3     if (err) throw err;
4     console.log(resolvedPath);
5   });

The method fs.unlink(path, callback) deletes a file. With fs.rmdir(path, callback), a folder is removed. The callback function does not have additional arguments.

With fs.mkdir(path[,mode],callback), a folder is produced. That access t o the folder is specified with 0777 (all to have all rights).

fs.readdir(path, callback) serves to read a folder and place all files in there as an array. The special folders “.” and “..” are not taken up.

The method fs.close(fd, callback) closes an opened file. The callback function does not have additional arguments. fs.open(path, flags[,mode], callback) opens a file for access. The argument flags has the following meaning:

  • “r”: open for reading. An exception releases if the file cannot be opened.

  • “r+”: open for reading and writing. An exception releases if the file cannot be opened or described.

  • “rs”: opens for synchronous access and by avoidance local caches. This can be meaningful with external storage systems; however, it affects the performance negatively.

  • “rs+”: opens for synchronous writable access and by avoidance local Caches. This can be meaningful with external storage systems; however, it affects the peformance negatively.

  • “w”: opens for writing and if the file does not exist, it is produced. If it exists, it is emptied.

  • “wx”: opens for writing and, if the file exists, an exception is produced

  • “w+” opens for reading and writing. If the file does not exist, it is produced. If it exists, it is emptied.

  • “wx+” opens for reading and writing. If the file exists, an exception is produced.

  • “a”: opens for writing and, if the file exists, new data is attached

  • “ax”: opens for writing and, if the file exists, an exception is released

  • “a+”: opens for reading and writing and, if the file exists, new data is attached

  • “ax+”: opens for reading and writing and, if the file exists, an exception is released

mode sets the right of access, if the file is produced . The default value is 0666, writing and reading.

The timestamp of a file can be changed with fs.utimes(path, atime, mtime, callback) and/or with fs.futimes(fd, atime, mtime, callback).

The writing of data happens with fs.write(fd, buffer, offset, length[,position], callback). buffer delivers bites, position the position yet to be.

written is offset, the position in the buffer. The callback function indicates the written bytes, once the number and the buffer. Alternatively fs.write(fd, data[, position[, encoding]], callback) is used.

Reading from data takes place with a description object fd by the means of fs.read(fd, buffer, offset, length, position, callback):

  • buffer is the buffer, where the data is written.

  • offset is the starting point of the buffer.

  • length is the amount of the readable bytes.

  • position is the position in the file.

The callback function indicates the number of really read bytes and the buffer.

Directly works with a file with fs.readFile(filename[,options], callback).

1   fs.readFile('/etc/passwd', function (err, data) {
2     if (err) throw err;
3     console.log(data);
4   });

The writing to a file takes place with fs.writeFile(filename, data[,options],callback).

1   fs.writeFile('message.txt', 'Hello Node', function (err) {
2     if (err) throw err;
3     console.log('It's saved!');
4   });

With fs.appendFile(filename, data[,options],callback) it will be attached directly to existing files.

1   fs.appendFile('message.txt', 'data to append',
2                 function (err) {
3     if (err) throw err;
4       console.log('The "data to append" was appended to file!');
5     });

The method fs.watch(filename[,options][,listener] serves to supervise a file during the process of renaming. The method returns an instance of the type fs.FSWatcher.

A435076_1_En_4_Figj_HTML.jpg Platform Dependence

This method is not available on all platforms. It uses operating system functions, which differ slightly:

  • Linux uses inotify.

  • BSD uses kqueue.

  • OS X uses kqueue for files and FSEvents for folders.

  • Windows uses ReadDirectoryChangesW (Win32 API).

1   fs.watch('somedir', function (event, filename) {
2     console.log('event is: ' + event);
3     if (filename) {
4       console.log('filename provided: ' + filename);
5     } else {
6       console.log('filename not provided');
7     }
8   });

There is a method fs.exists(path, callback), which tests if the file exists. However, the use of this is not recommended.

A435076_1_En_4_Figk_HTML.jpg Caution with Test Functions

Node is a multi-user environment. If a process deletes files and another tests them, then the processes can overlap in such a way that the deletion takes place immediately after the test with “exists” starts. Then the process of the code suggests that the file is present, which is not the case. This is not controllable and leads to so-called “race conditions”—[Race Conditions] ( https://de.wikipedia.org/wiki/Race_Condition ). It is better if you directly access the file and treat errors with “try/catch” blocks.

With fs.access(path[, mode], callback), you test the rights of access for the current user. The return contains values from a list of constants:

  • fs.F_OK: The file is visibile. It says nothing about the rights.

  • fs.R_OK: readable

  • fs.W_OK: writable

  • fs.X_OK: executable

1   fs.access('/etc/passwd', fs.R_OK | fs.W_OK, function(err) {
2     util.debug(err ? 'no access!' : 'can read/write');
3   });

Functions for handling Streams

Streams process data byte by byte, which usually is more efficient.

A435076_1_En_4_Figl_HTML.jpg Streams

Streams are a paradigm in programming. They make data available as sequence during one period. More to the theory can be found on Wikipedia.3

The call fs.createReadStream(path[, options]) returns a ReadStream object. The argument options has these default values:

1   {
2     flags: 'r',
3     encoding: null,
4     fd: null,
5     mode: 0666,
6     autoClose: true
7   }


1   fs.createReadStream('sample.txt', {start: 90, end: 99});

With fs.createWriteStream(path[,options]), a stream to write is provided. The object is of the type WriteStream.

1   {
2     flags: 'w',
3     encoding: null,
4     fd: null,
5     mode: 0666
6   }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.249.220