Nodejs基础中间件Connect

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:

http://blog.fens.me/nodejs-connect/

connect

前言

“中间件”在软件领域是一个非常广的概念,除操作系统的软件都可以称为中间件,比如,消息中间件,ESB中间件,日志中间件,数据库中间件等等。

Connect被定义为Node平台的中间件框架,从定位上看Connect一定是出众的,广泛兼容的,稳定的,基础的平台性框架。如果攻克Connect,会有助于我们更了解Node的世界。Express就是基于Connect开发的。

让我们开始探索Connect中间件。

目录

  1. Connect介绍
  2. Connect安装
  3. Connect内置中间件介绍
  4. logger
  5. cookieParser
  6. session
  7. cookieSession
  8. compress
  9. basicAuth
  10. bodyParser
  11. json
  12. urlencoded
  13. multipart
  14. timeout
  15. reponseTime
  16. methodOverride
  17. csrf
  18. static
  19. staticCache
  20. directory
  21. vhost
  22. favicon
  23. limit
  24. query
  25. errorHadnler

1. Connect介绍

Connect是一个node中间件(middleware)框架。如果把一个http处理过程比作是污水处理,中间件就像是一层层的过滤网。每个中间件在http处理过程中通过改写request或(和)response的数据、状态,实现了特定的功能。这些功能非常广泛,下图列出了connect所有内置中间件和部分第三方中间件。 这里能看到完整的中间件列表

下图根据中间件在整个http处理流程的位置,将中间件大致分为3类:

  • 1. Pre-Request 通常用来改写request的原始数据
  • 2. Request/Response 大部分中间件都在这里,功能各异
  • 3. Post-Response 全局异常处理,改写response数据等

connect-middleware

关于Connect介绍部分,摘自:http://www.cnblogs.com/luics/archive/2012/11/28/2775206.html

2. Connect安装

我的系统环境

  • win7 64bit
  • Nodejs:v0.10.5
  • Npm:1.2.19

通过nodejs安装Connect


~ D:\workspace\javascript>mkdir nodejs-connect && cd nodejs-connect
~ D:\workspace\javascript\nodejs-connect> npm install connect
connect@2.9.0 node_modules\connect
├── methods@0.0.1
├── uid2@0.0.2
├── pause@0.0.1
├── cookie-signature@1.0.1
├── fresh@0.2.0
├── qs@0.6.5
├── bytes@0.2.0
├── buffer-crc32@0.2.1
├── cookie@0.1.0
├── debug@0.7.2
├── send@0.1.4 (range-parser@0.0.4, mime@1.2.11)
└── multiparty@2.1.8 (stream-counter@0.1.0, readable-stream@1.0.17)

尝试做一个最简单的web服务器

增加一个文件:app.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(function (req, res) {
        res.end('hello world\n');
    })
    .listen(3000);

启动node


~ D:\workspace\javascript\nodejs-connect>node app.js
GET / 200 5ms
GET /favicon.ico 200 0ms

打开浏览器:http://localhost:3000/

connect-web

3. Connect内置中间件介绍

22个内置中间件列表

下面将分别介绍这22个中间件。

4. logger

描述:用来输出用户请求日志。

参数:options或者format字符串

options:

  • format:参考下面的tokens
  • stream:输出流,默认是stdout
  • buffer:缓冲时间,默认是1000ms
  • immediate:立刻打印日志

tokens: format格式

  • :req[header] ex: :req[Accept]
  • :res[header] ex: :res[Content-Length]
  • :http-version
  • :response-time
  • :remote-addr
  • :date
  • :method
  • :url
  • :referrer
  • :user-agent
  • :status

Formats:缩写

  • default ‘:remote-addr – – [:date] “:method :url HTTP/:http-version” :status :res[content-length] “:referrer” “:user-agent”‘
  • short ‘:remote-addr – :method :url HTTP/:http-version :status :res[content-length] – :response-time ms’
  • tiny ‘:method :url :status :res[content-length] – :response-time ms’
  • dev concise output colored by response status for development use

例子:新建logger.js


var connect = require('connect');
var app = connect()
    .use(connect.logger())
    .use(function (req, res) {
        res.end('hello world\n');
    })
    .listen(3000);

connect.logger()


127.0.0.1 - - [Mon, 23 Sep 2013 05:14:18 GMT] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKi
t/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
127.0.0.1 - - [Mon, 23 Sep 2013 05:14:18 GMT] "GET /favicon.ico HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 6.1; WOW64)
 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

connect.logger(‘short’)


127.0.0.1 - GET / HTTP/1.1 200 - - 9 ms
127.0.0.1 - GET /favicon.ico HTTP/1.1 200 - - 1 ms

connect.logger(‘dev’)


GET / 200 5ms
GET /favicon.ico 200 1ms

connect.logger(function(tokens, req, res){ return ‘some format string’ })


some format string
some format string

所以在开发环境,我们日志设置成dev就好了。

5. cookieParser

描述:cookie解析中间件,解析Cookies的头通过req.cookies得到cookies。还可以通过req.secret加密cookies。

例子:新建cookieParser.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.cookieParser('secret string'))
    .use(function (req, res, next) {
        req.cookies.website="blog.fens.me";
        res.end(JSON.stringify(req.cookies));
    })
    .listen(3000);

connect-cookiesParser

6. session

描述:会话管理中间件

依赖:cookieParser

参数:options

options:

  • key:Cookies名,默认值为connect.sid
  • store: session存储实例
  • secret: session的cookie加密
  • cookie: session的cookie配置,默认值为{path: ‘/’, httpOnly: true, maxAge: null}
  • proxy:安全cookie的反向代理,通过x-forwarded-proto实现

Cookie option:

cookie.maxAge: 默认值null,表示当浏览器关闭后cookie被删除。

例子:新建session.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.cookieParser())
    .use(connect.session({secret: '123', cookie: { maxAge: 60000 }}))
    .use(function (req, res, next) {
        if(req.session.pv){
            res.setHeader('Content-Type', 'text/html');
            res.write('views: ' + req.session.pv);
            req.session.pv++;
            res.end();
        }else{
            req.session.pv = 1;
            res.end('Refresh');
        }

    })
    .listen(3000);

connect-session

7. cookieSession

描述:基于cookies的会话中间件

参数:options:

options:

  • key:Cookies名,默认值为connect.sess
  • secret: 防止cookie窃取
  • cookie: session的cookie配置,默认值为{path: ‘/’, httpOnly: true, maxAge: null}
  • proxy:安全cookie的反向代理,通过x-forwarded-proto实现

Clearing sessions:

req.session = null;

例子:新建cookieSession.js


var connect = require('connect');
var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.cookieParser())
    .use(connect.cookieSession({ secret: 'adddaa!', cookie: { maxAge: 60 * 60 * 1000 }}))
    .use(function (req, res, next) {
        if(req.session.pv){
            res.setHeader('Content-Type', 'text/html');
            res.write('views: ' + req.session.pv );
            req.session.pv++;
            console.log(req.session.pv);
            res.end();
        }else{
            req.session.pv = 1;
            res.end('Refresh');
        }

    })
    .listen(3000);

connect-cookieSession

我们发现,这次不管刷新多少次页面,req.session.pv始终是1.

8. compress

描述:gzip压缩中间件,通过filter函数设置,需要压缩的文件类型。压缩算法为gzip/deflate。

filter函数


exports.filter = function(req, res){
  return /json|text|javascript|dart|image\/svg\+xml|application\/x-font-ttf|application\/vnd\.ms-opentype|application\/vnd\.ms-fontobject/.test(res.getHeader('Content-Type'));
};

Threshold压缩阈值:当响应请求大于阈值,则压缩响应请求。

参数:options

  • chunkSize (default: 16*1024)
  • windowBits
  • level: 0-9 where 0 is no compression, and 9 is slow but best compression
  • memLevel: 1-9 low is slower but uses less memory, high is fast but uses more
  • strategy: compression strategy

例子:新建compress.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.compress({level:9}))
    .use(function (req, res) {
        res.setHeader('Content-Type', 'text/html');
        res.write(res);
        res.end('hello world\n');
    })
    .listen(3000);

connect-compress

9. basicAuth

描述:basic认证中间件,实现简单的用户密码登陆,当用户和密码验证通过后,通过一个callback方法继续执行。

同步验证:


connect()
  .use(connect.basicAuth(function(user, pass){
    return 'tj' == user && 'wahoo' == pass;
  }))

异步验证:


connect()
  .use(connect.basicAuth(function(user, pass, fn){
    User.authenticate({ user: user, pass: pass }, fn);
  }))

例子:新建basicAuth.js


var connect = require('connect');
var app = connect();
app.use(connect.logger('dev'));

//  基本用法
//  app.use(connect.basicAuth('fens','fens'))

//  同步验证
app.use(connect.basicAuth(function (user, pass) {
    var isLogin = 'fens' == user && 'fens' == pass;
    console.log("Login:" + isLogin);
    return isLogin;
}))
app.use(function (req, res) {
    res.end('hello world\n');
})
app.listen(3000);

验证弹出框

connect-basicAuth1

正确输入用户和密码后,访问页面

connect-basicAuth2

10. bodyParser

描述:请求内容解析中间件,支持多种类型application/json,

application/x-www-form-urlencoded, multipart/form-data.

与其他的3个中间件相同:


app.use(connect.json());
app.use(connect.urlencoded());
app.use(connect.multipart());

例子:新建bodyParser.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.bodyParser())
    .use(function(req, res) {
        res.end('req.body=>' + JSON.stringify(req.body));
    })
    .listen(3000);

POST方法:


~ curl -d 'user[name]=tj' http://localhost:3000/
req.body=>{"'user":{"name":"tj'"}}

GET方法:


~ curl http://localhost:3000/?user=123
req.body=>{}

11. json

描述:JSON解析中间件,req.body传值

参数:options

  • strict: when false anything JSON.parse() accepts will be parsed
  • reviver: used as the second “reviver” argument for JSON.parse
  • limit: byte limit [1mb]

同bodyParser。

12. urlencoded

描述:application/x-www-form-urlencode请求解析中间件

参数:options

  • limit: byte limit [1mb]

同bodyParser。

13. multipart

描述:multipart/form-data请求解析中间件,解析req.body和req.files.

上传文件:uploadDir


app.use(connect.multipart({ uploadDir: path }))

参数:options

  • limit: byte limit defaulting to [100mb]
  • defer: 在不等待“结束”事件,通过调用req.form.next()函数,可以缓冲并处理多个表单对象,还可以绑定到“progress”或“events”的事件。

Temporary Files:临时文件

默认情况下,临时文件会被保存在os.tmpDir()目录,但不会自动回归,我们必须手动处理。如果没有使用defer选项时,你可以通过req.files来获得对象的使用。


req.files.images.forEach(function(file){
  console.log('  uploaded : %s %skb : %s', file.originalFilename, file.size / 1024 | 0, file.path);
});

Streaming:流式处理

当使用defer选项时,文件在上传过程中,你可以通过”part”事件和流控制访问文件。


req.form.on('part', function(part){
  // transfer to s3 etc
  console.log('upload %s %s', part.name, part.filename);
  var out = fs.createWriteStream('/tmp/' + part.filename);
  part.pipe(out);
});

req.form.on('close', function(){
  res.end('uploaded!');
});

例子:新建multipart.js


var connect = require('connect');
var app = connect()
.use(connect.logger('dev'))
.use(connect.multipart({ uploadDir: 'd:\\tmp' }))
.use(function (req, res) {
if(req.method=='POST'){
console.log(req.files);
res.end('Upload ==>'+ req.files.file.path);
}
res.setHeader('Content-Type', 'text/html');
res.write('<form enctype="multipart/form-data" method="POST"><input type="file" name="file">');
res.write('<input type="submit" value="submit"/>');
res.write('</form>');
res.end('hello world\n');
})
.listen(3000);

通过form表单选择文件

connect-multipart1

POST请求解析

connect-multipart2

14. timeout

描述:请求超时中间件,默认超时时间是5000ms,可以清除这个时间通过req.clearTimeout()函数。超时的错误,可以通过next()函数传递。我们也可以设置超时的响应错误状态码:.timeout=503

例子:新建timeout.js,模拟超时


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.timeout(1000))
    .use(function (req, res) {
        setTimeout(function(){
            res.end('hello world\n');
        },5000)
    })
    .listen(3000);

控制台输出:


Error: Response timeout
    at IncomingMessage. (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\timeout.j
s:39:17)
    at IncomingMessage.EventEmitter.emit (events.js:95:17)
    at null._onTimeout (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\timeout.js:34:11)
    at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
GET / 503 1030ms - 389b
Error: Response timeout
    at IncomingMessage. (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\timeout.j
s:39:17)
    at IncomingMessage.EventEmitter.emit (events.js:95:17)
    at null._onTimeout (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\timeout.js:34:11)
    at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
GET /favicon.ico 503 1006ms - 389b

15. reponseTime

描述:计算响应时间中间件,在response的header增加X-Response-Time,计算响应时间。

例子:新建reponseTime.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.responseTime())
    .use(function (req, res) {
        res.end('hello world\n');
    })
    .listen(3000);

connect-responseTime

16. methodOverride

无法模拟出效果,暂时先跳过

描述: 提供伪造HTTP中间件,检查一个method是否被重写,通过传递一个key,得到_method,原始的方法通过req.originalMethod获得。

例子:新建methodOverride.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.methodOverride('KEY'))
    .use(function (req, res) {
        res.end(JSON.stringify(req.headers));
    })
    .listen(3000);

17. csrf

描述:跨域请求csrf保护中间件,通过req.csrfToken()令牌函数绑定到请求的表单字段。这个令牌会对访客会话进行验证。

默认情况会检查通过bodyParser()产生的req.body,query()函数产生的req.query,和X-CSRF-Token的header。

依赖:session(), cookieParser()

参数:options:

  • value: 一个函数接受请求,返回的令牌

例子:新建csrf.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.cookieParser())
    .use(connect.session({secret: '123', cookie: { maxAge: 60000 }}))
    .use(connect.csrf({value:'admin'}))
    .use(function (req, res) {
        res.setHeader('Content-Type', 'text/html');
        res.end('hello world\n');
        console.log(req.csrfToken());
    })
    .listen(3000);

生成的csrf Token:


1YZ72JuGRTOh/mzqByktPoyz2C+Dk1E5wXyj0=
GET / 200 356ms
bItSjAAXydK4jkYYLDnc1c0+7AGDFwGX6r8ns=
GET /favicon.ico 200 3ms

18. static

描述: 静态文件处理中间件,设置root路径作为静态文件服务器

参数:options:

options:

  • maxAge:浏览器缓存存活时间(毫秒),默认值0
  • hidden:是否允许传递隐藏类型的文件,默认值false
  • redirect:是否允许当访问名是一个目录,结尾增加”/”,默认值true
  • index:设置默认的文件名,默认值index.html

例子:新建static.js


var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.static(__dirname+'/static',{maxAge:60*60*1000,hidden:false}))
    .use(function (req, res) {
        res.setHeader('Content-Type', 'text/html');
        res.write('static:');
        res.write('');
        res.write('hidden:');
        res.end('');
    })
    .listen(3000);

隐藏类型的文件,没有被显示出来。

connect-static

19. staticCache

描述: 静态文件缓存中间件,最大可以缓存128个对象,每个对象最大256K,总加起来32mb。

缓存算法采用LRU(最近最少使用)算法,让最活跃的对象保存在缓存中,从而增加命中。

Benchmarks:性能测试

  • static(): 2700 rps
  • node-static: 5300 rps
  • static() + staticCache(): 7500 rps

依赖:static()

参数:options:

  • maxObjects:最多能缓存的对象,默认值128个
  • maxLength:最大缓存的对象,默认值256kb

例子:新建staticCache.js


var connect = require('connect');
var app = connect()
.use(connect.logger('dev'))
.use(connect.static(__dirname+'/static',{maxAge:60*60*1000,hidden:false}))
.use(connect.staticCache())
.use(function (req, res) {
res.setHeader('Content-Type', 'text/html');
res.write('static:');
res.write('<img src="static.png" width="100px"/>');
res.write('hidden:');
res.end('<img src=".png" width="100px"/>');
})
.listen(3000);

控制台日志:


connect.staticCache() is deprecated and will be removed in 3.0
use varnish or similar reverse proxy caches.
GET / 200 11ms
GET /.png 200 0ms

建议用varnish或专门的缓存工具,来代替staticCache()。

20. directory

描述: 目录列表中间件,列出指定目录下的文件

参数:options:

  • hidden:是否显示隐藏文件,默认值false.
  • icons:是否显示网站图标,默认值false.
  • filter:是否过滤文件,默认值false.

例子:新建directory.js

var connect = require('connect');
var app = connect()
    .use(connect.logger('dev'))
    .use(connect.directory(__dirname+'/static',{hidden:true}))
    .use(function (req, res) {
        res.end();
    })
    .listen(3000);

connect-directory

21. vhost

无法模拟出效果,暂时先跳过

描述: 虚拟二级域名映射中间件,设置hostname和server。

例子:新建vhost.js


var connect = require('connect');
var app = connect();
app.use(connect.logger('dev'));
app.use(function (req, res) {
    res.end(JSON.stringify(req.headers.host));
});

var fooApp = connect();
fooApp.use(connect.logger('dev'));
fooApp.use(function (req, res) {
    res.end('hello fooApp\n');
});

var barApp = connect();
barApp.use(connect.logger('dev'));
barApp.use(function (req, res) {
    res.end('hello barApp\n');
});

app.use(connect.vhost('foo.com', fooApp));
app.use(connect.vhost('bar.com', barApp));

app.listen(3000);

22. favicon

描述:网页图标中间件,指定favicon的路径

参数:options:

  • maxAge:缓存存活时间(毫秒),默认值1天

例子:新建favicon.js


var connect = require('connect');
var app = connect()
    .use(connect.favicon('static/favicon.ico'))
    .use(connect.logger('dev'))
    .use(function (req, res) {
        res.end('hello world\n');
    })
    .listen(3000);

网站图标

connect-favicon

23. limit

描述: 请求内容大小限制中间件,可以用mb,kb,gb表示单位。

例子:新建limit.js


var connect = require('connect');
var app = connect()
.use(connect.logger('dev'))
.use(connect.limit('1mb'))
.use(connect.multipart({ uploadDir: 'd:\\tmp' }))
.use(function (req, res) {
if(req.method=='POST'){
console.log(req.files);
res.end('Upload ==>'+ req.files.file.path);
}
res.setHeader('Content-Type', 'text/html');
res.write('<form enctype="multipart/form-data" method="POST"><input type="file" name="file">');
res.write('<input type="submit" value="submit"/>');
res.write('</form>');
res.end('hello world\n');
})
.listen(3000);

控制台日志,上传大于1mb的文件。


GET / 200 8ms
Error: Request Entity Too Large
    at Object.exports.error (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\utils.js:62:13)
    at Object.limit [as handle] (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\limit.js:46:
47)
    at next (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:190:15)
    at Object.logger (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\logger.js:156:5)
    at next (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:190:15)
    at Function.app.handle (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:198:3)
    at Server.app (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\connect.js:65:37)
    at Server.EventEmitter.emit (events.js:98:17)
    at HTTPParser.parser.onIncoming (http.js:2027:12)
    at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:119:23)
POST / 413 8ms - 961b

24. query

描述:URL解析中间件,自动解析URL查询参数req.query

参数:options,qs.parse函数

例子:新建query.js


var connect = require('connect');
var app = connect()
    .use(connect.query())
    .use(connect.logger('dev'))
    .use(function (req, res) {
        res.end(JSON.stringify(req.query));
    })
    .listen(3000);

通过CURL测试:


curl -d '{name:'aad'}' http://localhost:3000?pass=did
{"pass":"did"}

req.query会自动解析URL的查询参数,不解析POST的数据。

25. errorHadnler

无法模拟出效果,暂时先跳过

描述:错误处理中间件,对于开发过程中的错误,提供栈跟踪和错误响应,接受3种类型text,html,json。

Text: text/plain是默认类型,返回一个简单的栈跟踪和错误消息

JSON:application/json,返回{‘error’:error}对象

HTML: 返回一个HTML错误页面

参数:options:

  • showStack:返回错误信息和错误栈.默认值false
  • showMessage,只返回错误信息,默认值false
  • dumpExceptions, 输出异常日志,默认值false
  • logErrors,输出错误日志到文件,默认值false

例子:新建errorHadnler.js


var connect = require('connect');
var app = connect()
    .use(connect.logger())
    .use(connect.errorHandler({ dumpExceptions: true, showStack: true }))
    .use(function (req, res) {
        req.headers.accept='html';
        res.write(JSON.stringify(req.headers.accept));
        throw new Error('my errorHandler!!!');
        res.end('Hello');
    })
    .listen(3000);

控制台输出


Error: my errorHandler!!!
    at Object.handle (D:\workspace\javascript\nodejs-connect\errorHadnler.js:8:15)
    at next (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:190:15)
    at next (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:192:9)
    at Object.logger (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\middleware\logger.js:156:5)
    at next (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:190:15)
    at Function.app.handle (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\proto.js:198:3)
    at Server.app (D:\workspace\javascript\nodejs-connect\node_modules\connect\lib\connect.js:65:37)
    at Server.EventEmitter.emit (events.js:98:17)
    at HTTPParser.parser.onIncoming (http.js:2027:12)
    at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:119:23)

转载请注明出处:
http://blog.fens.me/nodejs-connect/

打赏作者

This entry was posted in Javascript语言实践, 架构设计

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

29 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
ijse

挺全,多谢分享~

hades

+1

xiumu

第6第7的代码好像一样?两个session相关的中间件

Conan Zhang

已经修改了,写文章时的笔误吧。第7改成cookieSession。

多谢提醒!

ljcqx

希望大神能够把node.js的文章全部更新一下,express和connect现在都是最新的,你的文章有些代码不能运行了

Conan Zhang

等有时间我更新一下,最近在忙别的事情。

aballam

对了 我看了一下connect提供的中间件 发现express 大部分都有,是不是直选其中一个模块就好?

Conan Zhang

express完全构建在connect上层的,选择对应模块配置就行了。

cckowin

vhost这样就有效果
var connect = require(‘connect’);
var app = connect();
app.use(connect.logger(‘dev’));

var fooApp = connect();
fooApp.use(connect.logger(‘dev’));
fooApp.use(function (req, res) {
res.end(‘hello fooAppn’);
});

var barApp = connect();
barApp.use(connect.logger(‘dev’));
barApp.use(function (req, res) {
res.end(‘hello barAppn’);
});

app.use(connect.vhost(‘foo.com’, fooApp));
app.use(connect.vhost(‘bar.com’, barApp));
app.use(function (req, res) {
res.end(JSON.stringify(req.headers.host));
});

app.listen(3000);
通过CURL测试
curl localhost:3000
“localhost:3000”
curl localhost:3000 -H “Host:foo.com”
“foo.com”
curl localhost:3000 -H “Host:bar.com”
hello barApp
errorHandler这样就有效果
var connect = require(‘connect’);
var app = connect()
.use(connect.logger())
.use(function (req, res, next) {
error = new Error(‘my errorHandler!!!’);
next(error);
return;
req.headers.accept=’html’;
res.write(JSON.stringify(req.headers.accept));
//throw new Error(‘my errorHandler!!!’);
res.end(‘Hello’);
})
.use(connect.errorHandler({ dumpExceptions: true, showStack: true }))

Conan Zhang

谢谢补充,我稍后测试一下! 🙂

Guest

我安装了最新的 connect3.0.1 插件,总是提示下面的问题,这个connect 的版本问题么?

Guest

我运行

seasonxin

我安装了最新的 connect3.0.1 插件,总是提示下面的问题,这个connect 的版本问题么?总提示 has no method ‘logger’

Conan Zhang

我查了一下,connect3.1,把logger改名成morgan了。
你可以参考morgan的配置:https://github.com/expressjs/morgan

mokingone

basicAuth 现在connect没有这样中间件了。 express 3.x版本里面有,4.x也没有了。 我想问一下楼主想用basicAuth,有其他的项目有?

Conan Zhang

你可以自己在express中引用connect包,实现basicAuth 效果。

[…] 工具包:underscore,moment,connet,later,log4js,passport,passport(oAuth),domain,require,reap, commander,retry […]

jiangli

Hi,博主你好,有个问题请教下,上面文章中关于session的例子,我按照你写法,每次刷新页面,页面出来的数字都是1,我想问下是不是 res.end();完了以后,req.seesion.pv++就不再起作用了

Conan Zhang

1. 如果你每次都是1, 那么 条件判断的时候 if(req.session.pv) 就已经进入else分支了。

2. res.end(); 只代表输出到html完成,服务器端的程序,还会继续运行。

Jacon Cheung

我试了也是这样的,但是把req.session.pv++放在res.end()之前就是正常的pv数,res.end()之后代码是会执行的,我的理解是end之后被认为是一次请求结束了,不能再对请求对象req和相应对象res 做操作了,所以操作req对象就没起作用,如果我们用普通的变量来代替也是正常的自加。不知道我的理解是否正确

Conan Zhang

1. res.end()函数执行后,要看express框架的生命周期是如何继续运行的。

2. 通常都会使用 return res.end()的语法, 不要尝试在res.end()后还要执行什么动作,是违反框架的约定的。

Jacon Cheung

所以前面那人就是指出你的session上的例子的问题,原文中把req.session.pv++放在了res.end()之后执行,这是不对的。那么可以请教res.end()执行之后express框架的生命周期是如何运行的呢

Conan Zhang

原来错误出自我的文章,已经修改。

Wyatt

connect中间件4.xx去除之后,单独配置中间件感觉好麻烦,求解。

Conan Zhang

模块独立化以后,都需要自己手动配置了。
自己制定一个模块模板,把代码保存一下,每次都用自己的就行了。

Wyatt

原来如此,十分感谢。

Jade Chen

connect最新的版本好像把很多内置的组建都剥离出去了,要引用得额外加载模块。

Conan Zhang

我记得是express4去掉了connect的依赖,connect的模块在还connect里。

[…] 最后,列举一下3.x的内置模块和4.x模块的对照表,我们可以发现大部分都是connect部分的替换。关于connect库的详细介绍,可以参考文章,Nodejs基础中间件Connect […]

29
0
Would love your thoughts, please comment.x
()
x