Categories
Node.js Tips

Node.js Tips — Closing Sockets, Writing Responses, and Parsing HTML

Spread the love

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Log the Output of the npm install Command

To log the output of the npm install command, we can route stderr to stdout.

For example, we can write:

npm install 2>&1 | tee log.txt

2>&1 routes stderr to stdout.

tee reads the standard output and writes it to both standard out and one or more files.

We write to log.txt as specified in the command.

Parsing of Pages with Node.js and XPath

To parse HTML with XPaths, we parse the HTML with parse5 .

It doesn’t parse it into a DOM object but it’s fast and W3C compliant.

We can serialize it to XHTML with xmlserializer ,

Then can use the xmldom to get the DOM.

And we use the xpath library to make our XPath queries.

For instance, we can write:

const fs = require('mz/fs');
const xpath = require('xpath');
const parse5 = require('parse5');
const xmlSer = require('xmlserializer');
const DOMParser = require('xmldom').DOMParser;

(async () => {
  const html = await fs.readFile('./foo.html');
  const document = parse5.parse(html.toString());
  const xhtml = xmlSer.serializeToString(document);
  const doc = new DOMParser().parseFromString(xhtml);
  const select = xpath.useNamespaces({
    x: "http://www.w3.org/1999/xhtml"
  });
  const nodes = select("/html/body/header/div/div[1]/a[2]", doc);
  console.log(nodes);
})();

We import the fs library to read the foo.htmk file.

Then we parse the document with parse5 to a document object.

Then we transform the HTML to XHTML with the xmlserializer ‘s serializeToString method.

Then we create a new DOMParser instance by parsing the transformed string.

Next, we create a select object with the userNamespace method to let us select DOM elements by XPath.

Then we call select to select elements by XPath.

doc is the DOM object returned from DOMParser .

nodes has the returned nodes.

Also, we can use the libxmljs library to get nodes by XPath.

For instance, we can write:

const libxmljs = require("libxmljs");
const xml =  `
<?xml version="1.0" encoding="UTF-8"?>'
<root>
  <child foo="bar">
    <grandchild baz="foo">some content</grandchild>
  </child>
  <sibling>with content!</sibling>
</root>`;

const xmlDoc = libxmljs.parseXml(xml);
const gchild = xmlDoc.get('//grandchild');
console.log(gchild.text())

We use the libxmljs by passing in an XML string to the parsXml method.

Then we cal pass in an XPath string to the get method to get the item.

And the text will have the text for the selected node, which is some content .

Write After End Error in Node.js Webserver

If we’re using the net module to create a web server, then when we write a message, we’ve to pass in a callback as the 2nd argument to call end on it.

For example, we can write:

const netSocket = require('net').Socket();
netSocket.connect(9090);
netSocket.write('hello', err => netSocket.end());

We call netSocket.end() in the callback of the 2nd argument to close the socket after the message is written.

We’ve to do that because write is async. There’s no guarantee that write is done before end is we don’t pass it into the callback.

So something like:

const netSocket = require('net').Socket();
netSocket.connect(9090);
netSocket.write('hello');
netSocket.end();

will get us the ‘write after end’ error.

Difference Between response.setHeader and response.writeHead

response.setHeader lets us set a single header for implicit headers.

If the header already exists, then its value will be replaced.

We can use an array of strings to send multiple headers with the same name.

response.writeHead sends a response header to the request.

One method takes an object with the status code and the response headers.

To use setHeader , we can write:

const body = "hello world";
response.setHeader("Content-Length", body.length);
response.setHeader("Content-Type", "text/plain");
response.setHeader("Set-Cookie", "type=foo");
response.status(200);

We set one response header with one setHeader call.

The status code is set separately with response.status .

On the other hand, with writeHead , we set the response status codes and headers all at once.

For example, we can write:

const body = "hello world";
response.writeHead(200, {
  "Content-Length": body.length,
  "Content-Type": "text/plain",
  "Set-Cookie": "type=foo"
});

We set the response status code in the first argument and all the response headers in the object in the 2nd argument.

Conclusion

response.setHeader and response.writeHead are different.

We can parse HTML or XML and use XPath to query the nodes.

To end a socket created with net , we’ve to call it in the callback that’s passed into the 2nd argument of write .

We can log npm install errors to a file by redirecting the output.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *