`
witcheryne
  • 浏览: 1093184 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

用node.js建博客(四) - express中的404处理

    博客分类:
  • node
阅读更多

上一篇中,我已经实现了如下管理功能,

 

  • 将所有markdown文件(即:*.md文件),统一放到views/blogs目录下
  • 将/blogs/*.html的url, 映射到markdown文件
  • 在首页index.jade中,添加文章的链接

  • 注意:

    本片内容不太适合Express3.x, 建议参考附件中的 nodeblog_express3.x.zip Demo来看

     

     

     

    本片介绍如何使用express为nodeblog带来404错误处理

    实现功能

    1. 访问的链接存在的时候,显示页面
    2. 不存在,则显示404页面, 当然,这里的404是统一处理

     

    技术准备:(2个)

    1. Node.js中path模块的使用:

    path模块提供一些处理文件路径的功能,采用require('path')来使用。这里我只使用到两个方法:

     

    1). path.normalize(strPath)

    将路径标准化, 如'/etc//hosts', 会被标准化成'/etc/hosts'

    '/' 分隔符,如果在windows环境中会转换成'\'

     

    2). path.exists(filePath, function(exists))

    判断路径是否存在,true: 存在, false: 不存在,该方法还有个同步版: path.existsSync(filePath):boolean

    2. Express中的路由控制:

    1). 什么是路由?

    例如下面代码可以截获 '/users/:id' url, 其中id是url参数 (REST-ful url! You are right!)

     

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

    用 curl 看一下效果:

     

     

      2). 使用next做路由控制:

    当一个url可以被多个路由匹配,则在response关闭前,调用next()进行路由跳转

     

    app.get('/users/:id', function  (req, res, next) {
        console.log('id: ' + req.params.id);
        next();
    })
    
    app.get('/users/*', function  (req, res, next) {
        console.log('list all user');
        res.send('list all users \n');
    })

      调用next()做路由跳转, 跳转规则按照app.get声明顺序执行。


     

    开始为nodeblog添加404处理:(4步)

    1. 调整app.js中的express配置

    提高对 public/* 资源路由的优先级:

     

    var express = require('express');
    
    var app = module.exports = express.createServer();
    
    // Configuration
    
    app.configure(function(){
      app.set('views', __dirname + '/views');
      app.set('view engine', 'jade');
      app.use(express.bodyParser());
      app.use(express.methodOverride());
      
      // 将public提前
      app.use(express.static(__dirname + '/public'));
      app.use(app.router);
      // 以前在这里
      // app.use(express.static(__dirname + '/public'));
    });

    2. 修改对 '/blogs/:title.html' 的路由代码,

    添加对文件是否存在的判断,这里需要先引入path模块: var path = require('path');

     

    app.get('/blogs/:title.html', function(req, res, next) {
        
        var urlPath = [
            'blogs/',
            req.params.title, '.md'
        ].join('');
        
        var filePath = path.normalize('./' + urlPath);
        path.exists(filePath, function  (exists) {
            if(!exists) {
                next();
            } else {
                res.render(urlPath, {layout: false});
            }
        });
    
    })

    3. 添加404的处理:

    app.get('*', function(req, res) {
        console.log('404 handler..')
        res.render('404', {
            status: 404,
            title: 'NodeBlog',
        });
    })

       由于 '*' 也可以匹配 '/blogs/:title.html', 所以在 2 步骤中的next, 会将处理路由到这里。

     

    4. 在views/ 下添加 404.jade 页面:

     

    h1= title
    
    img(src="/images/404.jpg")

     

    5. app.js全部代码

     

    require.paths.unshift('./mode_modules'); 
    var express = require('express');
    var markdown = require('markdown-js');
    var path = require('path');
    
    var app = module.exports = express.createServer();
    
    
    // Configuration
    
    app.configure(function(){
      app.set('views', __dirname + '/views');
      app.set('view engine', 'jade');
      
      // pase form data to key-value paire
      app.use(express.bodyParser());
      // support put and delete HTTP Standar Method
      app.use(express.methodOverride());
      
      app.use(express.static(__dirname + '/public'));
      app.use(app.router);
    });
    
    app.configure('development', function(){
      app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 
    });
    
    app.configure('production', function(){
      app.use(express.errorHandler()); 
    });
    
    app.register('.md', {
      compile: function(str, options) {
        var html = markdown.makeHtml(str);
        return function(locals){
          return html.replace(/\{([^}]+)\}/g, function(_, name){
            return locals[name];
          });
        };
      }
    });
    
    var config = {
        title: 'NodeBlog',
        author: 'lvjian'
    }
    
    // Routes
    
    app.get('/', function(req, res){
      res.render('index', {
        title: config.title + ' - ' + config.author
      });
    });
    
    app.get('/markdown', function(req, res) {
        res.render('index.md', {layout: false});
    })
    
    app.get('/blogs/:title.html', function(req, res, next) {
        
        var urlPath = [
            'blogs/',
            req.params.title, '.md'
        ].join('');
        
        var filePath = path.normalize('./' + urlPath);
        path.exists(filePath, function  (exists) {
            if(!exists) {
                next();
            } else {
                res.render(urlPath, {layout: false});
            }
        });
    
    })
    
    app.get('*', function(req, res) {
        console.log('404 handler..')
        res.render('404', {
            status: 404,
            title: 'NodeBlog',
        });
    })
    
    
    app.listen(process.env.VMC_APP_PORT || 3000);  
    console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

     

    参考资料:

    What next??

    为程序引入单元测试,摆脱修改+刷新的工作方式.

    • 大小: 260.5 KB
    • 大小: 11.1 KB
    • 大小: 12.1 KB
    0
    6
    分享到:
    评论
    6 楼 richmond.petbug 2015-02-06  
    在每一个路由请求回调中都要写一段判断文件是否存在,是否有更好的解决方案呢?
    5 楼 leo_luck 2014-06-10  
    请问一下
    访问的时候
    path.exists,一直返回不存在呢
    我log了一下filePath=blogs/first.md
    这是为什么呢
    4 楼 sqfasd 2012-10-20  
    flovex 写道
    我发现404 error中的图片是不能正常显示的,原因是没有添加图片解析的路由,后来在app.js中间加上这一段处理就好了:

    app.get('/images/:title.jpg',function(req,res) {
      console.log("Request image was called.");

      var urlPath = [
      // 获取相对路径, 我的应该是:  
      process.cwd(), 
      '/images/', 
      req.params.title, '.jpg' 
      ].join('');

      fs.readFile(urlPath, "binary", function(error, file) {
        if(error) {
          res.writeHead(500, {"Content-Type": "text/plain"});
          res.write(error + "\n");
          res.end();
        } else {
          res.writeHead(200, {"Content-Type": "image/jpg"});
          res.write(file, "binary");
          res.end();
        }
      });
    })

    不知道这样做是否规范?


    这段代码在windows下不能工作,
    首先文件分隔符需要转化下,用path.normalize
    其次,images的目录如果是放在public下,使用render函数会自动帮你查找到
    如果使用readFile或者sendfile,你要自己加上完整的路径,就是/public/images/
    3 楼 witcheryne 2012-09-12  
    flovex 写道
    我发现404 error中的图片是不能正常显示的,原因是没有添加图片解析的路由,后来在app.js中间加上这一段处理就好了:

    app.get('/images/:title.jpg',function(req,res) {
      console.log("Request image was called.");

      var urlPath = [
      // 获取相对路径, 我的应该是:  
      process.cwd(), 
      '/images/', 
      req.params.title, '.jpg' 
      ].join('');

      fs.readFile(urlPath, "binary", function(error, file) {
        if(error) {
          res.writeHead(500, {"Content-Type": "text/plain"});
          res.write(error + "\n");
          res.end();
        } else {
          res.writeHead(200, {"Content-Type": "image/jpg"});
          res.write(file, "binary");
          res.end();
        }
      });
    })

    不知道这样做是否规范?


    Express 3.x 变化挺大的,  这篇教程估计要重写了...
    静态数据加载的问题我检查了一下.  现在Express默认采用router的方式, 资源定为估计是按照router路径进行的, 在app.js的configure中去掉router部分代码即可:

    // Configuration
    
    app.configure(function(){
      app.set('port', process.env.VMC_APP_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(app.router);
      app.use(express.static(path.join(__dirname, 'public')));
    });
    


    新代码我已上传, module 我删掉了, 运行需要重新 npm install
    2 楼 flovex 2012-09-08  
    改进:后面显示图像部分应该用下面的一句话就可以了
    res.sendfile(urlPath);
    1 楼 flovex 2012-09-08  
    我发现404 error中的图片是不能正常显示的,原因是没有添加图片解析的路由,后来在app.js中间加上这一段处理就好了:

    app.get('/images/:title.jpg',function(req,res) {
      console.log("Request image was called.");

      var urlPath = [
      // 获取相对路径, 我的应该是:  
      process.cwd(), 
      '/images/', 
      req.params.title, '.jpg' 
      ].join('');

      fs.readFile(urlPath, "binary", function(error, file) {
        if(error) {
          res.writeHead(500, {"Content-Type": "text/plain"});
          res.write(error + "\n");
          res.end();
        } else {
          res.writeHead(200, {"Content-Type": "image/jpg"});
          res.write(file, "binary");
          res.end();
        }
      });
    })

    不知道这样做是否规范?

    相关推荐

    Global site tag (gtag.js) - Google Analytics