解读app.js
express 生成的web程序主文件是app.js,所以我们从这个文件入手,了解如何用express构建web程序,并顺手把它拆了,做成适合更大应用的结构。到处都有的require
就不提了。
创建
require之后创建一个express应用程序:
var app = express();
这个可以留在app.js中。
配置
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.set
用来设置环境变量,第一个参数是环境变量的name,第二个参数是值;在其他需要访问环境变量的地方,可以用app.get
获取,比如上面的app.get('env')
。下面是一些内建Express环境变量:
env
运行时环境,默认为 process.env.NODE_ENV 或者 "development"trust proxy
激活反向代理,默认未激活状态jsonp callback name
修改默认?callback=的jsonp回调的名字json replacer
JSON replacer 替换时的回调, 默认为nulljson spaces
JSON 响应的空格数量,开发环境下是2 , 生产环境是0case sensitive routing
路由的大小写敏感, 默认是关闭状态, "/Foo" 和"/foo" 是一样的strict routing
路由的严格格式, 默认情况下 "/foo" 和 "/foo/" 是被同样对待的view cache
模板缓存,在生产环境中是默认开启的view engine
模板引擎views
模板的目录
我们用到了最后两个,设置了页面显示的模板引擎和保存模板的目录。
设置app.use([path], function)是指在访问前缀为path
的路径执行时中间函数function
,上面的代码中没有指定path
,则表示在访问默认前缀/
的路径时执行中间函数function
。比如上面代码中的
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
在访问请求静态文件/stylesheets/style.css
时,就会先执行less-middleware,再执行express.static
,返回public/stylesheets/style.css
给浏览器端。
app.use()
的出场顺序非常重要,use的先后顺序决定了中间函数的优先级。 比如express.logger()
通常是第一个,可以记录全部请求。如果不想记录静态文件的请求,可以把less-middleware和 app.use(express.static)
放到logger
前面。
在express以前的版本中有个app.configure()方法,该方法虽然仍得以保留,但推荐使用if
代替:
if ('development' == app.get('env'))
因为以后还会有很多配置,所以我们要把这部分内容提取出来放到单独的文件中,创建/config/express.coffee
做这些配置,而在app.js中用require代替这部分代码:
require('./config/express')(app);
至于express.coffee的内容,以及如何支持coffeescript,后面再讲。
路由
express的路由是用方法app.VERB(path, [callback...], callback)
设置的,在上面的代码中体现就是:
app.get('/', routes.index);
app.get('/users', user.list);
app.VERB()
中的 VERB 是指某一个HTTP 动作, 比如 app.get()
、app.post()
。 每个path都可以对应多个callbacks,这些callbacks跟中间函数一样,按顺序逐一执行,但也有例外,如果某个callback执行了next('route')
,它后面的callback就被忽略。
前面的路径字符串path是当做正则表达式处理的,在遇到符合规则的http请求时执行callbacks。 path中不考虑请求参数,比如 "GET /" 会匹配下面的这个路由, 而"GET /?name=tobi"也会匹配。
app.get('/', routes.index);
因为程序要处理的路径肯定不止这两条,所以这些也要从app.js里拿出来,放到另外的文件里。在app.js中用
require('./config/routes')(app);
代替。/config/routes.coffee文件也要在下一节给出了。
启动
文件最后的代码是启动服务器,并输出一段日志:
http.createServer(app).listen(app.get('port'), function(){
console.log('NodeCoffee server listening on port ' + app.get('port'));
});
这个也要保留在app.js中
拆分app.js
因为express生成的app.js不适用比较大的程序,所以我们要把它拆开,最终的文件如下所示:
var express = require('express');
var http = require('http');
var path = require('path');
var app = express();
require('./config/express')(app);
require('./config/routes')(app);
http.createServer(app).listen(app.get('port'), function(){
console.log('NodeCoffee server listening on port ' + app.get('port'));
});
从上面的代码可以看出来,我们把配置信息都放到了config目录下,又创建了两个文件。此外,原来routes下的文件也被挪走了,因为它们其实不是routes,是controller来的。
所以我们又遵循MVC模式新建了三个目录app/controllers、app/models、app/views,原来routes目录下的两个文件挪到controllers,views目录也挪到了app下。
因为我们以后要用coffeescript写代码,所以要先把coffeescript引入项目,在package.json中的dependencies里加一条:
"coffee-script": "1.6.3"
此外还要在app.js里引入 require('coffee-script');
,然后就可以开始用coffeescript改代码了。上两段代码: config/express.coffee:
express = require 'express'
path = require 'path'
module.exports = (app,config) ->
#all environments
app.set "port", process.env.PORT or 3000
app.set('showStackError', true)
app.set('views', config.root + '/app/views')
app.set "view engine", "jade"
app.use express.favicon()
app.use express.logger("dev")
app.use express.bodyParser()
app.use express.methodOverride()
app.use express.cookieParser("p8zztgch48rehu79jskhm6aj3")
app.use express.session()
app.use app.router
app.use require("less-middleware")(src: __dirname + "/public")
app.use express.static(path.join(__dirname, "public"))
# development only
app.use express.errorHandler() if "development" is app.get("env")
config/routes.coffee:
module.exports = (app) ->
home = require '../app/controllers/home'
app.get '/', home.index
user = require '../app/controllers/user'
app.get '/users', user.list
原来routes目录下的index.js改成了/app/controllers/home.coffee,user.js改成了user.coffee。