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.