node.js +Express4 write your own blog website [1]


Wei node.js +Express4 write your own blog website [1]

  • Preface
  • 1. Demand
  • 2. Technology selection
  • 3. Text, hands on
    • 3.1 Hello, Express
    • 3.2 routing in Express
    • 3.3 meet Middleware


This series of articles can be seen as a personal blog node record, but also as an advanced version of nodejs Hello world example. I hope it can be a little bit of direction for people like me who want to quickly get started with nodejs. I have just started to enter the nodejs world, so there are some elementary, introductory, and even wrong knowledge and views in this article. Please do not hesitate to point out.

Because it’s an “advanced version” of Hello world, this article will skip over some places that I think are very basic even for novices like me, such as how to build an environment and how to use NPM. There are enough articles about these on the Internet.

Therefore, if you don’t know anything about nodejs, this little book is highly recommendedGetting started with nodeIt is not long, but the explanation is detailed and easy to understand. I believe it’s a great learning start.

Finally, almost all of the code in this article can be found in theThis projectIn order to make the explanation more convenient, I may have made some modifications. Any comments and criticism are welcome~

1. Demand

I don’t know if you’ve seen itBlog like a hackerOr a similar introductionJekyllTo write blog articles? In line with the spirit of “no tossing, no death, no wheel making” and “unhappiness”. Today, try building a static website like Jekyll from scratch. This website should at least meet the following requirements:

  1. Automatically parse markdown file into HTML
  2. The corresponding URL is generated according to certain file name rules
  3. It would be better if you could automatically classify articles according to their tag / category or any other custom attributes
  4. I haven’t thought of it yet~

If you’ve tried Jekyll or similar systems, you’ll probably find that the list above is basically a minimal Jekyll website. So, let’s analyze how to implement it.

2. Technology selection

Needless to say, what we are going to develop is a website. The basic technology has also confirmed that nodejs will not make other choices (this is the title).

It’s hot right nowMEANWeb dev stack is definitely worth a try. However, according to the initial requirements, static blogs do not need to introduce database or complex page interaction structure for the time being. In order to quickly implement a prototype, only E [express] + n [odejs] in m.e.a.n is enough.

aboutExpressOr the basic knowledge of nodejs, such as the construction of development environment, will not be repeated here. I do all the work in the following article synchronously under MAC / Ubuntu / windows, which is basically nodejs environment + sublimetext / VIM + git (cross platform software is a like).

Go straight to the topic.

3. Hands on

Before doing a big job with sleeves up, give the following work a simple decomposition and sorting: refine the list of requirements above, our first goal is to display the article on the page!

It’s simple, but it’s true. Take this opportunity to learn the basic knowledge of nodejs and express.

3-1 Hello, Express

New project

|   |--app.js
|   |--package.json

package.json It provides us with a unified control package dependency and program self description entry. Well, you can think of it as SLN / csproj file in C ා project. =I’m a. Net farmer). The contents are as follows:

        "name": "my-blog",
        "version": "0.0.1",
        "author": "NarK",
            "express": "4.x"

The content is very clear and does not explain, but in thehereYou can see package.json We can do more than that. We’ll talk about it later. Run after savingnpm installWait for the dependency package installation to complete.

app.js It is our main program document in the future.


    var express = require('express');
    var app = express();

    app.get('/', function(req, res) {
      res.send('hello world');


The above code is directly fromExpress official website API docCopy, by the way, this project uses the latest version of 4. X.

In this way, the simplest server under express is realized, and the browser is opened to accesshttp://localhost:3000It will take effect.

OK, so that’s the end of the article.

I’m just kidding. As can be seen from the above code, theRouting controlWe don’t need to parse the request manually and write one sentence after anotherif (method === 'POST' && path === '/home')Such judgments. Instead, it’s pretty graphic and easy to writeapp.verb(path, callback)method. Verb can be post, get, etc.

In the request processing method,res.send(content)It also provides a simple way to respond if the specified is not displayedContent-Type, express will automatically infer the response type according to the parameters of the send method, and the following table is listed:

Data Type       Content-Type
Buffer          application/octet-stream
String          text/html
Array/Object    Json representation
Number          return a respond text: 200 <=> "OK" for example


So obviously, next we just read the content of the article from the file, and then res.send () it’s OK in a moment.

Take a look at nodejsFile system related APIsAfter adding the code to read the file, app.js The contents are as follows:

    var express = require('express');
    var fs = require('fs');
    var app = express();

    app.get('/', function(req, res) {
      fs.readFile('./blogs/', function (err, data) {
        if (err) res.send(err);


Of course, remember to create the blogs folder and File (write some content casually, otherwise you can’t see the effect).

Code complete ~ switch to terminal, inputnodemon app.jsLet’s see if we have successfully read the first article of this blog.

Oh, by the way, a gadget is highly recommendednodemon。 In a word: with nodemon installed globally, we can use nodemon xxx.js In this way, the program will automatically detect the files related to this program, and automatically restart the process at any time to reflect the latest changes. In fact, nodejs is a necessary tool in the process of debugging!

To get to the point, I’m happy to open the Chrome browser localhost:3000 However, the expected text did not appear. Instead, a file download query box appeared. shit! Who told me that the send() method will automatically infer the content type!? Turn on network detection and find out that the returned content type isapplication/octet-stream。 (after testing, it also prompts to download files in Firefox. What’s funny is that ie11 shows the contents of the files on the page honestly and directly… Brother ie, why are you always different from others…)

Well ~ I went through nodejs’s document again, andfs.readFile(path, callback (err, data))At the end of the paper, there is a sentence

If no encoding is specified, then the raw buffer is returned.

Get ~ this is the result of not carefully reading the document. You can see from the table above,bufferCorrespondingcontent-typeIt isapplication/octet-streamHere, change the code:

fs.readFile('./blogs/', 'utf-8', function (err, data) {
    if (err) res.send(err);

Refresh the page (nodemon has automatically restarted when we save the code file:[nodemon] restarting due to changes...)When, when! What? You said this page is not good at all? Don’t care about these details… We just output the contents of the markdown file as it is. We didn’t even convert the HTML. Of course, it’s not good-looking. Don’t be impatient~

Above, we set up a simple hello express project package.json Simple routing control in express,res.send()fs.readFile()In this way, the function of reading the local file and displaying it to the page is completed. Next, on this basis, we will automatically detect all blog files in the specified format and map them to the corresponding URL one by one.

Routing in 3-2 Express

Obviously, our website will not have only one blog post, and the front page of the website should not print out an article straightly. So the next step is to think about the routing structure of the website,

|-- Home
|   |--Blog
|   |   |--blogA
|   |   |--blogB
|   |   |--blog...
|   |--xxx

Then, the home page should naturally display a list of articles, and click the article to guide onehost/blog/xxxxxTo display the content of the corresponding article. A fairly common way of organizing~

With the experience of the previous section, we can write code like this very soon:


app.get('/blog/blogA', function (req, res) {
  fs.readFile('./blogs/', 'utf-8', function (err, data) {
    if (err) res.send(err);

By analogy, 200 articles have written 200 such routing methods =. =

Of course not… So, in order to read all the markdown files in the specified directory in batches, we need to set up a standard naming format for it, such as: *. MD, which I will recognize as long as it is a markdown file; but maybe we can make the standard more strict.

For example: imitate the default naming format of

In this way, we can even rely on the file name to simply do a group by date for them. Or directly reflected in the URL, such ashost/blog/2014/04/30/express-plus-nodejs-making-my-own-blog

Therefore, our routing method can be changed from 200 to one

app.get('/blog/:year/:month/:day/:title', function (req, res) {
  var fileName = 
    './blogs/' +
    req.params.year + '-' + 
    req.params.month + '-' + + '-' + 
    req.params.title + '.md';
  fs.readFile(fileName, 'utf-8', function (err, data) {
    if (err) {

Here we know another very convenient routing function of express: Well, I don’t know what it’s called, let’s call itName request parameters? In short, in theapp.verb(url, callback (req, res))We can use the:argnameName part of the URL in the form ofreq.params.argnameGet, as shown above.

Make sure that the correct folder and the markdown file named according to the rules are established. After that, start the program to visit it~

In this way, usingyyyy-MM-dd-blog-title.mdWith the naming request parameters in express, such as/blog/:year/:month/:day/:titleSuch a URL can be used to parse and point to the corresponding arbitrary MD file.

The next step is to get the URL of the file from the local existing file in reverse, so as to generate a list of articles for users to click on.

function getBlogList(blogDir) {
  fs.readdir(blogDir, function (err, files) {
    var blogList = [];
    if (files && files.length) {
        files.forEach(function (filename) {
          //split file name and generate url...
          //create a blogItem { title: blogTitle, url: blogUrl }
    return blogList;

Due to the limitation of space, I have removed some details such as the regular verification of the file name format, the parsing of the file name and the process of generating the URL (just simply intercepting the string). In short, after the above tedious string processing, we finally get a form such as

  { title: 'blogA', url: '/blog/2014/04/01/blogA'},
  { title: 'blogB', url: '/blog/2014/05/08/blogB'},

Such an object.

So we can display links to all articles on the front page:

app.get('/', function (req, res) {
  var html = '';
  var blogList = getBlogList('./blog');
  if (blogList && blogList.length) {
    blogList.forEach(function (blog) {
      html += '<a href="'+ blog.url +'">' + blog.title + '</a><br/>';
  } else {
    res.send('No Blogs Found.');

It’s done ~ now users can access any article that exists in the blog folder and named according to the rules through the list on the home page.

Let’s get to know middleware 3

Finally came to expressConnect(a basic component of express, of course, can also be used as a separate framework, mainly responsible for the implementation of middleware mechanism).

For an explanation of middleware, seeA short guide to Connect Middleware。 I don’t want to show off my humble opinions here. In short, you can think of the middleware mechanism as a sewage treatment system with layers of filtration (=). =Sorry, but this is the first metaphor that came to my mind…).requestAfter one middleware after another, some finished processingresponseTo the client, some continue to flow into the next middleware.

In fact, in our previous code, we have inadvertently used this feature:


app.get('/', function (req, res){
  //index page

app.get('/blog/:year/:month/:day/:title', function (req, res) {
  //blog page


app.verb()In essence, it is a middleware with advanced routing function. Request comes first from top to bottomapp.get('/')To determine whether the URL matches or not, it will enter the processing method if it matches, otherwise it will continue to flow to the next middleware.

So, if we want to add a custom 404 not found page, how should we take advantage of this feature of middleware?

Simple, just put it at the bottom of the filter


app.get('/', ...);
app.get('/blog/', ...);
app.get('/wiki/', ...);
app.get('*', function (req, res) {
  res.send(404, "Oops! We didn't find it");

The request paths that can be resolved and matched are processed one by one in the corresponding middleware and the results are returned. All the remaining requests that can reach the bottom layer cannot be resolved by the existing routes, so 404 is returned.

Simple and natural way to deal with it!

Sometimes, after a request is processed by the first matching middleware, we may want it to continue to the next matching middleware and use it explicitly in the processing methodnext()That’s fine.

app.use(function (req, res, next) {
  console.log(req.method + ',' + req.url);

app.get('/', ...);


This is the end of the introduction of middleware. More knowledge and application will be mentioned one by one later. Let’s return to the current project.

Now that our website can guide users from the home page to any article, it’s time to formally convert the markdown file into HTML format for readers to read

Thank you for watching.


Do you have any black cat Sheriff fan