Node.js Note #1: Creating a basic site with Node.js and Express

基于 Node.js 的 web 应用

一个基本的 node.js web application 需要:

  • 我们需要提供 Web 页面,因此需要一个 HTTP 服务器
  • 对于不同的请求,根据请求的 URL,我们的服务器需要给予不同的响应,因此我们需要一个路由,用于把请求对应到请求处理程序(request handler)
  • 当请求被服务器接收并通过路由传递之后,需要可以对其进行处理,因此我们需要最终的请求处理程序
  • 路由还应该能处理 POST 数据,并且把数据封装成更友好的格式传递给请求处理入程序,因此需要请求数据处理功能
  • 我们不仅仅要处理 URL 对应的请求,还要把内容显示出来,这意味着我们需要一些视图逻辑供请求处理程序使用,以便将内容发送给用户的浏览器 - The Node Beginner Book

Why express ?

Express is a minimal and flexible node.js web application framework, providing a robust set of features for building single and multi-page, and hybrid web applications. - http://expressjs.com/

Express 是一个 MVC 框架,基于 Node.js 对原有进行了很多 Web 开发所需的功能封装。下图是 express 架构的简要分解:

Why express? 总而言之,其实就是自己想偷点懒,不想从零开始写 _(:3 」∠ )_。

快速生成 express app

    $ npm install -g express-generator

参数:

Usage: express [options]

Options:

-h, --help          output usage information
-V, --version       output the version number
-e, --ejs           add ejs engine support (defaults to jade)
-H, --hogan         add hogan.js engine support
-c, --css           add stylesheet  support (less|stylus|compass) (defaults to plain css)
-f, --force         force on non-empty directory

选择 style & jade:

$ express -c stylus myapp

快速生成以下文件:

create : myapp
create : myapp/package.json | myapp 的配置信息,包括依赖和定义 start 脚本
create : myapp/app.js | 程序启动文件
create : myapp/public | 所有静态文件
create : myapp/public/javascripts
create : myapp/public/images
create : myapp/public/stylesheets
create : myapp/public/stylesheets/style.styl
create : myapp/routes | 路由文件(MVC 中的 C ,controller)
create : myapp/routes/index.js.bak2 | 定义应用程序应该响应的页面
create : myapp/views | 页面文件(使用 Jade),MVC 中的V(View)
create : myapp/views/index.jade | 主页面
create : myapp/views/layout.jade | 页面 layout

Node.js Middleware

简单来说,如果把一个 http 处理过程比作是污水处理,中间件就像是一层层的过滤网。每个中间件在 http 处理过程中通过改写 request 或(和)response 的数据、状态,实现了特定的功能。

快速生成的 app.js 中都做了写什么?

以下 // 注释部分是自己的理解

…… // 一些依赖设置

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views')); // 设置 view 文件夹路径
app.set('view engine', 'jade'); // 模板引擎设置为 jade

/* app.use 来加载处理请求的路由模块的参数,
 一个请求过来,被 .use 写好的各个函数依次处理 */
app.use(favicon()); // 括号中设置 icon 文件路径
app.use(logger('dev')); // 使用 logger 并以 dev 模式记录请求,见 [Express - Logging](https://gist.github.com/leommoore/7524073)
app.use(bodyParser.json()); // 解析 application/json
app.use(bodyParser.urlencoded());   // 解析 application/x-www-form-urlencoded
app.use(cookieParser());    // 解析 Cookie 头
app.use(require('stylus').middleware(path.join(__dirname, 'public')));  // 设置需要自动编译 stylus 的文件夹路径
app.use(express.static(path.join(__dirname, 'public')));    // 设置静态资源文件夹路径


/* express 实现的一些特殊的 connect 中间件 */
app.use('/', routes);   // 实现路由
app.use('/users', users);   //设置路由,可以通过 http://localhost:3000/users 来访问 user.js

/// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);  // It passes control to the next matching route
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

一些简单的 express app 小案例


问题

  • Q: 通过 node 启动程序,每次代码修改都需要重新启动,肿么办? A(自问自答): 有一个工具 supervisor,每次修改代码后会自动重启,可以节省很多开发时间。

  • Q: 还不十分明确页面需要长成什么样?还有使用什么前端框架比较好?自己脑子里还没有清晰的概念,目前准备先参考 Travis CI