expressjs 源码研究

我们要想真正用好ExpressJS开发框架,应该对其源代码有所研究,才能真正掌握灵活而深入的使用方法。

 

可以进入 http://github.com/visionmedia/express/tree/master/lib/   查看相关源代码,源代码会不断更新,我会逐行讲解各种用法。

 

index.js 源代码讲解


 

 

/*
    自动装配器,可以用 express.logger() 代替 require('connect').logger()   
 */

var exports = module.exports = require('connect').middleware;

/**
     版本信息
 */

exports.version = '1.0.0rc4';

/**
 * 导入服务器模块依赖
 */

var Server = exports.Server = require('./server');

/**
 *  替代 new Server(...) 方式的捷径方法。
 */

exports.createServer = function(){
  //把参数返回数组形式并加入到 new Server 构造器中。
  return new Server(Array.prototype.slice.call(arguments));
};

//导入 View / response / request 的扩展模块。
require('./view');
require('./response');
require('./request');

// 后续: 基本做了3个事情
// 1 . 标准化扩展件导入方式 用 express.xxx 来代替  connect.xxx
// 2 . 简化new Server()创建方式。
// 3 . 导入了 view / request / response 模块


/*
  express基本使用方法也是从这个文件开始的

  var express = require('express');   // 导入express 模块
  var server = express.createServer();   // 创建 服务器对象
  server.listen(3000);  // 监听3000端口并启动服务器

*/

 

request.js 源代码讲解


 

/*

 

/**
 * 导入依赖模块
 */

var http = require('http')
  , utils = require('./utils')
  , mime = require('connect/utils').mime;

/**
 * 默认闪光灯格式
 */
var flashFormatters = exports.flashFormatters = {
  s: function(val){
    return String(val);
  }
};

/**
 * 返回请求头或默认选项。
 *
 * 例如 :
 *
 *     req.header('Content-Type');
 *     // => "text/plain"
 *    
 *     req.header('content-type');
 *     // => "text/plain"
 *    
 *     req.header('Accept');
 *     // => undefined
 *    
 *     req.header('Accept', 'text/html');
 *     // => "text/html"
 ×
 */

http.IncomingMessage.prototype.header = function(name, defaultValue){
  return this.headers[name.toLowerCase()] || defaultValue;
};

/**
   判断请求头是否有相关类型
 *
 * 例子 :
 *
 *     // Accept: text/html
 *     req.accepts('html');
 *     // => true
 *
 *     // Accept: text/*; application/json
 *     req.accepts('html');
 *     req.accepts('text/html');
 *     req.accepts('text/plain');
 *     req.accepts('application/json');
 *     // => true
 *
 *     req.accepts('image/png');
 *     req.accepts('png');
 *     // => false
 *
 */

http.IncomingMessage.prototype.accepts = function(type){
  var accept = this.header('Accept');
  if (!accept || accept === '*/*') {
    return true;
  } else if (type) {
    // Allow "html" vs "text/html" etc
    if (type.indexOf('/') < 0) {
      type = mime.types['.' + type];
    }
    // Check if we have a direct match
    if (accept.indexOf(type) >= 0) {
      return true;
    // Check if we have type/*
    } else {
      type = type.split('/')[0] + '/*';
      return accept.indexOf(type) >= 0;
    }
  } else {
    return false;
  }
};

/**
 * 根据请求参数返回请求内容
 */

http.IncomingMessage.prototype.param = function(name){
  // 路由参数就像 /user/:id
  if (this.params[name] !== undefined) {
    return this.params[name];
  }
  // 请求字符串参数
  if (this.query[name] !== undefined) {
    return this.query[name];
  }
  // 当加载connect.bodyDecoder后,可以查询post请求参数对应的内容。
  if (this.body && this.body[name] !== undefined) {
    return this.body[name];
  }
};

/**
 * 闪存功能 ,前提应该加载 session 模块。
 *
 * 例如:
 *
 *      req.flash('info', 'email sent');
 *      req.flash('error', 'email delivery failed');
 *      req.flash('info', 'email re-sent');
 *      // => 2
 *
 *      req.flash('info');
 *      // => ['email sent', 'email re-sent']
 *
 *      req.flash('info');
 *      // => []
 *
 *      req.flash();
 *      // => { error: ['email delivery failed'], info: [] }
 *
 *     也可以使用如下方式
 *     req.flash('info', 'email has been sent to %s.', userName);
 *
 */

http.IncomingMessage.prototype.flash = function(type, msg){
  var msgs = this.session.flash = this.session.flash || {};
  if (type && msg) {
    var i = 2
      , args = arguments
      , formatters = this.app.flashFormatters || {};
    formatters.__proto__ = flashFormatters;
    msg = utils.miniMarkdown(utils.htmlEscape(msg));
    msg = msg.replace(/%([a-zA-Z])/g, function(_, format){
      var formatter = formatters[format];
      if (formatter) return formatter(args[i++]);
    });
    return (msgs[type] = msgs[type] || []).push(msg);
  } else if (type) {
    var arr = msgs[type];
    delete msgs[type];
    return arr || [];
  } else {
    this.session.flash = {};
    return msgs;
  }
};

// 判断是否是 XHR 请求方式。
function isxhr() {
  return this.header('X-Requested-With', '').toLowerCase() === 'xmlhttprequest';
}

/**
  检查请求是一个 _XMLHttpRequest_
 */

http.IncomingMessage.prototype.__defineGetter__('isXMLHttpRequest', isxhr);
http.IncomingMessage.prototype.__defineGetter__('xhr', isxhr);

 

request相关后续: 其实这个源代码就是对原始的nodejs的http.IncomingMessage 的扩展。 IncomingMessage就是request的原始类型,可以这么理解。

 

(待续)

 


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值