用 express 搭建网站

2,120 阅读4分钟
原文链接: segmentfault.com

先建个简单的服务器

  • 当然你先得安装express npm install express

//使用express,如果这里的代码复制后运行不了请移步我的github下载源码,顺手star给我个小星星鼓励哈
//http://github.com/sally2015/express-project
// npm install  运行node main 后访问loaclhost:3000
var express = require('express');
var app = express();
app.set('port', process.env.PORT || 3000);

app.get('/',function(req, res){
    res.send('home');
    
});
app.use('/about',function(req, res){
    res.send('about');
    
});
app.use(function(req, res){


    res.send('404');
    
});

app.use(function(req, res, next){

    res.send('500');
});

app.listen(app.get('port'), function () {
    console.log('Express started on http:localhost'+app.get('port'));
});

  • app.use(function(req,res,next){})默认匹配的路由是‘/’,多个use要使用next()方法,但是使用了,res.end()或者res.send()就不能使用next到达下一个use了

  • app.get()是添加路由的方法,忽略大小写,反斜杠,进行匹配时不考虑查询字符串

//不使用express你可能要这么写
/*
* var http = require('http');
* var server =  http.createServer(function(req, res){
*    if(req.url === '/'){
        res.setHeader('Content-type','text-plain');
        res.write('……');&&res.end();
*   }
*}).listen(3000,'localhost');
*/
  • 对定制的404页面和500页面的处理与对普通页面的处理有所区别,用的不是app.get,而是app.use。app.use是express添加中间件的一种方法

  • express中路由和中间件的添加顺序至关重要,如果把404处理器放在所有的路由上面,普通页面的路由就不能用了

  • express能根据回调函数中的参数区分404和500处理器

使用handlebars

  • (defaultLayout:'main')意味着除非你特别指明否则所有的视图都是这个布局

var handlebars = require('express3-handlebars') //现在已经重命名为express-handlebar了,由于牵一发可能要动全身,我这里就不改了
.create({ 
    defaultLayout: 'main', // 设置默认布局为
});

app.engine('handlebars', handlebars.engine); // 将express模板引擎配置成handlebars 
app.set('view engine', 'handlebars');
  • 创建一个views/layouts/main.handlebars文件



Document


{{{body}}}


- {{{body}}}注意这里是三个大括号,这个表达式会被每个视图自己的html取代
- 分别创建首页、关于、404、500页面,后缀名都是handlebars
  - ```html
views/home.handlebars
=> 

welcome to home

views/about.handlebars =>

welcome to about

views/404.handlebars =>

not found - 404

views/500.handlebars =>

500 server error

视图和静态文件

  • express靠中间件处理静态文件和视图,中间件是一种模块化手段,使请求处理更加容易

  • static中间件可以将一个或多个目录指派为包含静态资源的目录,其中的资源不经过特殊处理直接发送到客户端

app.use(express.static(__dirname+'/public'));
//现在所有文件都可以相对public直接进行访问,例如public下面有一个img文
//件夹,那么在handlebars中(不需要理会在handlebars的目录结构)直接访问
//路径/img/logo.png
  • 视图和静态资源的区别是它不一定是静态的,html可以动态构建

  • 在项目下建一个public的子目录,应该把static中间件加载所有路由之前

向handlebars里传递参数

var args = 'its a arguments';//虚拟一个参数
//修改此时的about路由
app.get('/about', function(req,res){
    
    res.render('about', {args:args});
});

以上代码在github.com/sally2015/.… ch1
---------------------------------------------分割线----------------------------------------------

ch2讲讲怎么快速、可维护的开发

使用自定义模块

  • ch1为了传递参数在main.js里面定义了一个虚拟数据,为了将数据分离出来,在根目录下定义一个lib目录,放置一个数据模块m_data.js

var args = 'its a arguments';//虚拟一个参数

exports.getData = function(){
    return args;
}
var m_data = require('./lib/m_data.js');
app.get('/about', function(req,res){
    
    res.render('about', {args:m_data.getData()});
});

使用nodemon自动重启服务器

  • 每次修改main文件都要ctrl+c停止再运行很累,使用nodeman每次修改都会帮我们重启服务器

  • 使用也非常简单,npm install nodemon -g,运行nodemon main

页面测试

  • 需要一个测试框架Mocha ---- npm install mocha --save-dev 这里dev的意思是只在开发时依赖

  • mocha是要运行在客户端的所以把mocha资源放在public目录下

    • public/vendor

    • => node_modules/mocha/mocha.js

    • => node_modules/mocha/mocha.css

  • 测试通常需要一个assert函数

    • npm install chai --save-dev

    • node_modules/chai/chai.js => public/vendor

  • 不让测试一直运行

    • 因为拖慢网站的速度,用户也不需要看到测试结果

    • 期望的情况是在url后面加上?test=1才加载测试页面

  • 定义中间件来检测查询字符串中的test=1,放在所有路由之前

  • 如果test=1出现在任何页面的字符串查询中,属性res.locals.showTests就会被设为true

  • res.locals对象是要传给视图上下文的一部分

app.use(function(req, res, next){
    res.locals.showTests = app.get('env') !== 'production' 
          && req.query.test === '1';
    next();
});

引入测试框架

  • 修改main.handlebars(以后简写main),修改head


    Meadowlark Travel
    {{#if showTests}}
        
    {{/if}}
    

  • 这里在head引入jquery是为了方便测试

  • 在之前引入mocha和chai,还需引入一个qa/global-test.js脚本

{{#if showTests}}
        
{{#if pageTestScript}} {{/if}} {{/if}}
  • 创建public/qa/tests-global.js全局测试脚本

suite('Global Tests', function(){
    test('page has a valid title', function(){
        assert(document.title && document.title.match(/\S/) && 
          document.title.toUpperCase() !== 'TODO');
    });
});
  • 访问localhost:3000没有任何变化,但是访问localhost:3000?test=1,你会发现加载了测试的文件帮你做的这些东西

  • 针对about页面进行测试

    • 这里假设测试确保有总有一个指向联系我们页面的链接,创建一个public/qa/tests-about.js

suite('"About" Page Tests', function(){
  test('page should contain link to contact page', function(){
      assert($('a[href="/contact"]').length);
  });
});
  • 在main.js上改变路由/about的参数

    app.get('/about', function(req,res){
      
      res.render('about', {
          args:m_data.getData(),
          pageTestScript:'/qa/tests-about.js'
      });
    });
  • 现在刷新页面about会有一个错误的断言

  • 只要about模板中有一个链接,这个错误测试断言就会消失

  • 例如contact us

使用局部组件

  • 场景定义一个天气组件,在任何页面都可以调用,这样的需要重复调用的可以用局部文件实现

    • 新建一个views/partials/weather.handlebard

{{#each weather.locations}} {{/each}}
function getWeatherData(){

    return {
        locations:[
            {
                name:'广州',
                forecastUrl:'https://github.com/sally2015',
                weather:'广州的温度情况',
                temp:'温度'
            },
            {
                name:'深圳',
                forecastUrl:'https://github.com/sally2015',
                weather:'深圳的温度情况',
                temp:'温度'
            },
            {
                name:'珠海',
                forecastUrl:'https://github.com/sally2015',
                weather:'珠海的温度情况',
                temp:'温度'
            }
        ]
    }
}
exports.getWeatherData = getWeatherData
  • 创建一个中间件给res.locals.weather添加数据


//给res.locals.weather添加数据
app.use(function(req, res, next){
    if(!res.locals.weather){
        res.locals.weather = {};

    }
    res.locals.weather = m_weatherData.getWeatherData();
    next();
});

welcome to home

{{>weather}}
  • 语法{> partialname}可以让你在视图中包含一个局部文件,express-handlebars会在views/partials寻找

  • 你可以将这个语法放在任何你需要的页面上

客户端使用模板和动态获取数据

  • 客户端使用handlebars需要加载handlebars文件,你可以从node_moudles里面找,像正常文件一样引入即可

  • 定义一个view/partials/ajaxtest.handlebars文件


动态获取数据
app.get('/data/ajaxtest', function(req, res) {
    res.json({
            animal:'dog',
            bodyPart:'tail',
            adjective : 'sharp',
            noun : 'run'
        });
});
  • 在你想要的视图里面加入{{>ajaxtest}}

  • 这时候当你点击按钮就会请求到数据,注意接口使用的方法是json


--------------------分割线------------------------------------ch2 github.com/sally2015/.…