Node.js is a JavaScript based language, so front-end developers should be a natural. Typically we use it for CLI tools or Web servers, and there are mature frameworks for Web servers, such as Express and Koa. But both Express and Koa encapsulate the native API of Node.js, so you can actually write a Web server using the native API without using any framework. This article will show you how to write a Web server using native apis without using a framework. Because in my plan, I will write Express and Koa source code parsing later, both of which are implemented using native apis. So this article is actually a pre-knowledge of both source code parsing to help us better understand the meaning and source code of frameworks like Express and Koa. This article is only to illustrate the use of native API, code is ugly, please do not imitate in the actual work!

Examples of working code for this article have been uploaded to GitHub for fun:Github.com/dennis-jian…

Hello World

To set up a simple Web server, use the native HTTP module and a simple Hello World program with a few lines of code:

const http = require('http')

const port = 3000

const server = http.createServer((req, res) = > {
  res.statusCode = 200
  res.setHeader('Content-Type'.'text/plain')
  res.end('Hello World')
})

server.listen(port, () = > {
  console.log('Server is running on http://127.0.0.1:${port}/ `)})Copy the code

CreateServer creates a server that has no logic and simply returns Hello World when accessed. Once the server is created, run it on port 3000 using server.listen.

This example is simple, but it doesn’t seem to do anything except output a Hello World. It’s far from a typical Web server.

  1. Does not supportHTTPVerbs, such asGET.POSTEtc.
  2. Routing not supported
  3. No static resource hosting
  4. Unable to persist data

The first three points are essential basic functions of a Web server. The fourth point depends on the situation. After all, the Web server of many nodes is only an intermediate layer, and it really deals with the database to do persistence or all kinds of micro services.

So let’s write a Web server that actually works, which is to fill in the blanks.

Handles routing and HTTP verbs

Our Hello World is not completely disabled, because the code location is still in http.createserver, where we add routing. To differentiate ourselves from static resources, our API requests start with/API. To do route matching is not difficult, the simplest is to use the if condition directly on the line. In order to get the requested address, we need to use the URL module to parse the sent address. Http verbs can be obtained directly using req.method. So http.createServer is modified as follows:

const url = require('url');

const server = http.createServer((req, res) = > {
  // Get the parts of the URL
  // url.parse can parse req.url into an object
  // It contains pathName, queryString, etc
  const urlObject = url.parse(req.url);
  const { pathname } = urlObject;

  // API begins with an API request
  if (pathname.startsWith('/api')) {
    // Determine the route
    if (pathname === '/api/users') {
      // Get the HTTP verb
      const method = req.method;
      if (method === 'GET') {
        // Write a false data
        const resData = [
          {
            id: 1.name: 'Ming'.age: 18
          },
          {
            id: 2.name: 'little red'.age: 19}]; res.setHeader('Content-Type'.'application/json')
        res.end(JSON.stringify(resData));
        return; }}}});Copy the code

Now go to/API /users to get the list of users:

Static file support

API requests that do not start with/API are considered static files. Different files have different content-Types. For this example, only.jpg is supported. Just add an else to our if (pathname.startswith (‘/ API ‘)). Returning a static file requires:

  1. usefsModule reads the file.
  2. The return file is set differently according to the file typeContent-Type.

So our else looks like this:

/ /... Omit before and after code...

else {
  // Use the path module to get the file name extension
  const extName = path.extname(pathname);

  if (extName === '.jpg') {
    // Use the fs module to read files
    fs.readFile(pathname, (err, data) = > {
      res.setHeader('Content-Type'.'image/jpeg'); res.write(data); res.end(); }}})Copy the code

Then let’s try this with an image in the same directory:

Data persistence

There are several ways to persist data, usually in databases and, to a lesser extent, in files. Save the database is more troublesome, but also need to create and connect the database, we are not good demo here, we show a save file example. If (method === ‘GET’) {if (method === ‘GET’) {if (method == ‘GET’) {if (method == ‘GET’);

/ /... Omit other code...

else if (method === 'POST') {
  // Note that data may be transferred in multiple chunks
  // We need to concatenate these chunks
  let postData = ' ';
  req.on('data'.chunk= > {
    postData = postData + chunk;
  })

  req.on('end'.() = > {
    // Insert content into db.txt after data transfer
    fs.appendFile(path.join(__dirname, 'db.txt'), postData, () = > {
      res.end(postData);  // Write the data and return it again}); })}Copy the code

Then let’s test the API:

Let’s see if it’s in the file:

conclusion

At this point, we have a web server with basic functionality. The code is not complicated, but it is helpful to understand how the Node Web server works. But there’s a big problem with this code: it’s ugly! All the code is written in a pile, and HTTP verbs and route matching are all judged using if conditions. If you have hundreds of apis and a dozen or so verbs, the code is a disaster! So we should take routing, HTTP verbs, static files, data persistence out of the equation and make the whole application more elegant and scalable. This is why frameworks like Express and Koa exist. In the next article, we will take a look at the Express source code to see how it solves this problem

Examples of working code for this article have been uploaded to GitHub for fun:Github.com/dennis-jian…

At the end of this article, thank you for your precious time to read this article. If this article gives you a little help or inspiration, please do not spare your thumbs up and GitHub stars. Your support is the motivation of the author’s continuous creation.

Welcome to follow my public numberThe big front end of the attackThe first time to obtain high quality original ~

“Front-end Advanced Knowledge” series:Juejin. Cn/post / 684490…

“Front-end advanced knowledge” series article source code GitHub address:Github.com/dennis-jian…