Fisher Price’s “My First Node Web Server”
Now that you know a bit about Node and NPM, the very basics at least, let’s write some
actual code, beyond the simple example shown earlier, that is, and run it with Node.
Chapter 1 Server-Side aCtion: node and npM
16
When I say that Node makes writing server software trivial, that may well be the
understatement of the year! Perhaps the simplest example (that does something “real,” at
least) is this:
require("http").createServer((inRequest, inResponse) => {
inResponse.end("Hello from my first Node Web server");
}).listen(80);
That remarkedly small bit of code is all it takes in Node to write a web server. Even
though it’s not necessary, just for practice, go ahead and create a directory and use NPM
to init it as a project (and this time, add a -y to the init command, which will use the
defaults for all the prompts rather than making it interactive). Then, type that code into a
file, save it as server.js. Now, at this point, you could start it up like so:
node server.js
But let’s do one more thing first. Open the generated package.json file, and in the
scripts section, add a new attribute to the object:
"start": "node server.js"
What this does is it effectively defines a custom command for NPM. The start
command is one that already exists, but it’s one that does nothing until you add this
entry in package.json, so it may as well not exist! Once you add that entry though, NPM
will look for that start key, take its value, and execute whatever the command is that
you provide in it. The benefit of doing this is that every project you create with Node
and NPM will be startable the same way. Without this, a developer would need to figure
out what file is the main entry point to launch it with Node (and note that the main key
in package.json may not be enough to tell someone this, as is the case here, since the
default value of index.js would be wrong for this project).
Once you add that, go ahead and start the app:
npm start
Yep, that’s it! NPM knows what to do now and will launch Node and tell it to execute
server.js.
Now fire up your favorite web browser and visit http://127.0.01. You’ll be greeted
with the text “Hello from my first Node Web server”. Note, however, that if anything else
on your system is already listening on port 80 then the app won’t actually start, you’ll get
Chapter 1 Server-Side aCtion: node and npM
17
an error instead. In that case, simply change the listen(80) call to a free port and you’ll
be good to go (and, naturally, add the port to the end of the URL in that case too).
If that isn’t a little bit amazing to you, then you’ve probably seen the Flying Spaghetti
Monster (FSM) travel one too many times around your neighborhood and have been
totally desensitized to the amazing! (FSM – yeah, uhh, I’m not gonna even try and
explain what the FSM is; here’s a link:
www.venganza.org
).
Obviously, this is a simplistic example, but it should get the basic idea across well
enough. But what exactly is going on in that simple example at a code level? As it
happens, quite a bit, and most of it is key to how Node works.
The first concept is the idea of importing modules. In the example code, http is a
module. This is one of the core Node modules that Node comes with out of the box, and,
as such, it is compiled directly into the Node binary. Therefore, you won’t find a separate
JavaScript file for it in the Node installation directory for it. This is true of all the Node
core modules, all of which you can find in the Node documentation on the Node site. To
import any of them, you just require() them by name.
Note We’ll look at some of the more commonly used modules in the next
chapter.
You can create your own modules too just by adding other .js files to your project
and require()-ing them. This gets a little more involved, with discussions of things like
scope and exports, and we’ll get to all of that in time. But for now, I wanted to mention
it at least in case you really are entirely new to Node so that you can find the appropriate
section in the Node docs to describe this if you want to jump ahead.
The require() function returns an object that is essentially the API provided by the
module. This object can include methods, attributes, or whatever you want. In fact, it
could conceivably be just a variable with some data in an array. More times than not,
though, it will be an object with some methods and attributes. In the case of http in
this example, one of the methods the object returned is createServer(). This method
creates a web server instance and returns a reference to it.
The argument you pass to this method is a function that serves as a request listener;
that is, the function executed any time a request is made to the server.
Chapter 1 Server-Side aCtion: node and npM
18
This function handles all incoming HTTP request. You can do anything you need to
there, including such things as the following:
• Interrogate the incoming request to determine the HTTP method.
• Parse the request path.
• Examine header values.
You can then perform some branching logic on any or all of these, perhaps access
a database or other durable storage mechanism, and return an appropriate and fully
dynamic response for the specific request.
Creating a web server alone won’t actually do anything. It won’t respond to requests
until you do a little more work. As mentioned, the createServer() method returns a
reference to the web server instance, which itself contains the method listen(). That
method accepts a port number on which the server should listen and, optionally, the
hostname/IP address on which to listen. In the example, the standard HTTP port 80 is
specified, and by default, the local machine loopback address 127.0.0.1 is used if no IP
address is specified, as is the case here. Once you call this method, the server will begin
listening for requests (i.e., assuming nothing else is already using that port on your
system!), and for each request that comes in, it will call the anonymous function passed
to createServer().
This callback function (callback functions being one mechanism by which Node
provides nonblocking functionality, the others being Promises and async/await)
receives two arguments, inRequest and inResponse, which are objects representing
the HTTP request and response, respectively. In this simple example, all this callback
function does is call the end() method on the response object, passing the response
you want to send back. By default, an HTTP 200 response code header will be added
automatically, so this completes the handling of a given request.
With just this little bit of code, you, in fact, know the basics of what you would
require for writing a server for the MailBag app later! But, when we get to that app, we’ll
use something a little more robust (Express, as mentioned earlier), but this gives you a
fundamental idea of what it takes.
Do'stlaringiz bilan baham: |