A guide to getting started with node.js Web application framework Express

  • 2020-03-30 03:05:59
  • OfStack

A, install,

$ npm install express

Or an executable express(1) installation anywhere:

#  This approach is strongly recommended 
$ npm install -g express

Second, get started quickly

The quickest way to get started with express is to generate an application using executable express(1), as shown below:

Create an app:


$ npm install -g express
$ express /tmp/foo && cd /tmp/foo

Install dependency package:

$ npm install -d

Startup server:

$ node app.js

Create a server

To create an express.httpserver instance, simply call the createServer() method. As a general example of this application, we can define routes based on HTTP Verbs. Take app.get () as an example:


var app = require('express').createServer();
app.get('/', function(req, res){
  res.send('hello world');
});
app.listen(3000);

Create an HTTPS server

Initialize an express.HTTPSServer instance as described above. We then pass it a configuration object that accepts the key, cert, and other (properties/methods) mentioned in the HTTPS document.


 var app = require('express').createServer({ key: ... });

Five, configuration,

Aliases such as production/development/stage are optional, as shown in app.configure in application.js. See the following example for practical usage.

The following example will only dumpExceptions (throw a fault) during development and return a stack exception. However, we use methodOverride and bodyParser in both environments. Note the use of app.router, which can (optionally) be used to load the route of the (mount) program, and the first call to app.get(), app.post(), etc., will also load the route.


app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
});
app.configure('development', function(){
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
  var oneYear = 31557600000;
  app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
  app.use(express.errorHandler());
});

For similar environments you can pass multiple environment strings:

app.configure('stage', 'prod', function(){
  // config
});

For any internal Settings (#), Express provides set(key[, val]), enable(key), and disable(key) methods:

See the Settings in the app.set section of application.js.


 app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('views');
    // => "/absolute/path/to/views"
    app.enable('some feature');
    //Set ('some feature', true);
    app.disable('some feature');
    //Set ('some feature', false);
    app.enabled('some feature')
    // => false
 });

To change the environment, we can set the NODE_ENV environment variable, such as:

$ NODE_ENV=production node app.js

This is important because most caching mechanisms are only turned on in the production phase.

Six, set

Seven, routing,

Express provides a set of suggestive and expressive routing apis using HTTP actions. For example, if we want to handle an account whose path is /user/12, we can define the route as follows. Values associated with named placeholders can be accessed by req.params.


app.get('/user/:id', function(req, res){
    res.send('user ' + req.params.id);
});

A route is a string that is internally compiled to regular. For example, when /user/:id is compiled, a simplified version of the regular expression might look like this:

//Modify the official string
//user/([^/]+)/?/

Regular expressions can be passed in and applied to complex scenarios. Since the content groups captured through literal regular expressions are anonymous, we might access them directly through req.params. Therefore, the first set of content we capture will be req.params[0], and the second set will be req.params[1].

app.get(/^/users?(?:/(d+)(?:..(d+))?)?/, function(req, res){
    res.send(req.params);
});

Curl defines routing requests for the above:

$ curl http://dev:3000/user
[null,null]
$ curl http://dev:3000/users
[null,null]
$ curl http://dev:3000/users/1
["1",null]
$ curl http://dev:3000/users/1..15
["1","15"]

Here are some examples of routes associated with paths they might use:

"/user/:id"
/user/12
"/users/:id?"
/users/5
/users
"/files/*"
/files/jquery.js
/files/javascripts/jquery.js
"/file/*.*"
/files/jquery.js
/files/javascripts/jquery.js
"/user/:id/:operation?"
/user/1
/user/1/edit
"/products.:format"
/products.json
/products.xml
"/products.:format?"
/products.json
/products.xml
/products
"/user/:id.:format?"
/user/12
/user/12.json

For example, we can use POST to send json data, and the bodyParser, the middleware that parses the content (or whatever) of the json request, returns the data and stores the result in req.body:

var express = require('express')
  , app = express.createServer();
app.use(express.bodyParser());
app.post('/', function(req, res){
  res.send(req.body);
});
app.listen(3000);

Usually we can use a "fool" placeholder like user/:id with no restrictions. However, if we want to limit the user id to Numbers, for example, we might use /user/:id([0-9]+), which will only take effect if the placeholder contains at least one number (match, match).

8. Passing Route Control

We can control the next adaptive route by calling the third parameter, the next() function. If an adaptation is not found, control is returned to Connect and the middleware is invoked in the order it was added in use(). The same applies to multiple routes defined to the same path, which will be called in turn until one of them decides to respond to a request without calling next().


app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next();
    }
});
app.get('/users', function(req, res){
    // do something else
});

The app.all() method is called only once to conveniently apply the same logic to all HTTP actions. Now we use it to extract a user from the pseudo-data and assign it to req.user.

var express = require('express')
  , app = express.createServer();
var users = [{ name: 'tj' }];
app.all('/user/:id/:op?', function(req, res, next){
  req.user = users[req.params.id];
  if (req.user) {
    next();
  } else {
    next(new Error('cannot find user ' + req.params.id));
  }
});
app.get('/user/:id', function(req, res){
  res.send('viewing ' + req.user.name);
});
app.get('/user/:id/edit', function(req, res){
  res.send('editing ' + req.user.name);
});
app.put('/user/:id', function(req, res){
  res.send('updating ' + req.user.name);
});
app.get('*', function(req, res){
  res.send(404, 'what???');
});
app.listen(3000); 


Ix. Middleware

Routing middleware

Routing can take advantage of router middleware to pass more than one callback function (or array) into its method. This feature is great for restricting access, downloading data via routing, and so on.

Normally asynchronous data retrieval might look like the following example, where we use the :id parameter to try to load a user:


app.get('/user/:id', function(req, res, next){
  loadUser(req.params.id, function(err, user){
    if (err) return next(err);
    res.send('Viewing user ' + user.name);
  });
});

To ensure the DRY principle and improve readability, we can apply this logic to a middleware. As shown below, abstracting this logic into the middleware will allow you to reuse it while keeping our routing clean.

function loadUser(req, res, next) {
  // You would fetch your user from the db
  var user = users[req.params.id];
  if (user) {
    req.user = user;
    next();
  } else {
    next(new Error('Failed to load user ' + req.params.id));
  }
}
app.get('/user/:id', loadUser, function(req, res){
  res.send('Viewing user ' + req.user.name);
});

Multiple routes can be used and applied sequentially to a deeper level of logic, such as restricting access to a user account. The following example only allows an authenticated user to edit his or her account.

function andRestrictToSelf(req, res, next) {
  req.authenticatedUser.id == req.user.id
    ? next()
    : next(new Error('Unauthorized'));
}
app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
  res.send('Editing user ' + req.user.name);
});

Keeping in mind that routing is simply a function, as shown below, we can define a function that returns to the middleware to create a more expressive and flexible solution.

function andRestrictTo(role) {
  return function(req, res, next) {
    req.authenticatedUser.role == role
      ? next()
      : next(new Error('Unauthorized'));
  }
}
app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
  res.send('Deleted user ' + req.user.name);
});

The commonly used middleware "stack" can be passed through an array (which is applied recursively) and can be mixed and matched to any degree.

var a = [middleware1, middleware2]
  , b = [middleware3, middleware4]
  , all = [a, b];
app.get('/foo', a, function(){});
app.get('/bar', a, function(){});
app.get('/', a, middleware3, middleware4, function(){});
app.get('/', a, b, function(){});
app.get('/', all, function(){});

For the complete code for this example, see the repository route middleware example.

There may be times when we want to "skip" the remaining routing middleware and continue to match subsequent routes. To do this, we simply call next() with the 'route' string -- next('route'). If no remaining routes match the requested URL, Express will return 404 Not Found.

Eleven, HTTP method

So far, I've been exposed to app.get() several times, and Express provides other common HTTP actions, such as app.post(), app.del(), and so on.

A common example of the use of POST is to submit a form. Let's simply set the method property of the form to post in HTML, and control will be assigned to the route defined below.


<form method="post" action="/">
     <input type="text" name="user[name]" />
     <input type="text" name="user[email]" />
     <input type="submit" value="Submit" />
</form>

By default Express does not know how to handle the content of this request, so we must add the bodyParser middleware, which will parse the content of the application/x-www-form-urlencoded and application/json requests, and store the variables in req.body. We can use this middleware like the following example:

app.use(express.bodyParser());

As shown below, our route will have access to the req.body.user object, which will contain both properties when there is a name and an email defined.

app.post('/', function(req, res){
  console.log(req.body.user);
  res.redirect('back');
});

When we want to use a method like PUT in a form, we can use a hidden input named _method, which can be used to modify the HTTP method. To do this, we first need methodOverride middleware, which must appear after the bodyParser in order to use the form values contained in its req.body.

app.use(express.bodyParser());
app.use(express.methodOverride());

Why these methods are not owned by default is simply because they are not required for the full functionality required by Express. The use of methods depends on your application, you may not need them, the client can still use methods like PUT and DELETE, you can use them directly, because methodOverride provides a very good solution to form. Here's how to use the method PUT, which might look like:

<form method="post" action="/">
  <input type="hidden" name="_method" value="put" />
  <input type="text" name="user[name]" />
  <input type="text" name="user[email]" />
  <input type="submit" value="Submit" />    
</form>
app.put('/', function(){
    console.log(req.body.user);
    res.redirect('back');
});

Error handling

Xiii. Route parameter pretreatment


14. View processing

View file using < Name> . < Engine> Such a format, where < Engine> Is the name of the module required to come in. For example, layout. Ejs will tell the view system to require('ejs'), the loaded module must (export) the exports.compile(STR, options) method, and return a Function to accommodate Express. App.register () can be used to change this default behavior by mapping file extensions to specific engines. For example, "foo.html" can be handled by ejs.

Xv. View parts

1. FirstInCollection true when it is the first object
2. Index of indexInCollection in the aggregator object
3. LastInCollection true when it is the last object
CollectionLength collectionLength collectionLength collectionLength collectionLength collectionLength collectionLength collectionLength collectionLength

Local variables are passed (generated) at a higher priority, and local variables passed to the parent view are also adapted to the child view. For example, when we render a blog post with partial('blog/post', post), it will generate a post local variable, and there will be a local variable user in the view that calls this function, which will also work for blog/post. Partial is like the include method in PHP.

Note: use the widget aggregator with caution. Rendering an array of widget collections of length 100 is equivalent to processing 100 views. For simple collections, it is best to repeat the build in rather than use a part aggregator to avoid overhead.

16. View search

View lookup is performed relative to the parent View. If we have a View page called views/user/list.jade and it says partial('edit') inside, it will try to load views/user/edit.jade. /messages') will load the views/messages.jade.

When using the view index above, we refer to views/users/index.jade in partial('users') in the same directory as the view, while the view system tries to index.. /users/index instead of calling partial('users').

17. Template Engines

The following are the most commonly used template engines for Express:

1.Haml: Haml implementation
2.Jade: successor to haml.js
EJS: embedded JavaScript
4.CoffeeKup: a template based on CoffeeScript
5. The jQuery Templates

Upgrade guide


Related articles: