本篇文章给大家分享的是有关nodejs中connect的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

10年积累的做网站、网站设计经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站制作后付款的网站建设流程,更有察哈尔右翼中旗免费网站建设让你可以放心的选择与我们合作。
connect 解析
我们要先从 connect 的官方例子开始
var  connect = require( 'connect' ); 
 var  http = require( 'http' ); 
 var  app = connect(); 
 // gzip/deflate outgoing responses 
 var  compression = require( 'compression' ); 
 app.use(compression()); 
// store session state in browser cookie 
 var  cookieSession = require( 'cookie-session' ); 
 app.use(cookieSession({ 
    keys: [ 'secret1' ,  'secret2' ] 
 })); 
 // parse urlencoded request bodies into req.body 
 var  bodyParser = require( 'body-parser' ); 
 app.use(bodyParser.urlencoded({extended:  false })); 
 
 // respond to all requests 
 app.use( function (req, res){ 
   res.end( 'Hello from Connect!\n' ); 
 }); 
 //create node.js http server and listen on port 
 http.createServer(app).listen(3000);从示例中可以看到一个典型的 connect 的使用:
 var  app = connect() // 初始化 
 app.use( function (req, res, next) { 
    // do something 
 })
 // http 服务器,使用 
 http.createServer(app).listen(3000);先倒着看,从调用的地方更能看出来,模块怎么使用的。我们就先从 http.createServer(app) 来看看。
从 nodejs doc 的官方文档中可以知, createServer 函数的参数是一个回调函数,这个回调函数是用来响应 request 事件的。从这里看出,示例代码中 app 中函数签就是 (req, res) ,也就是说 app 的接口为 function (req, res) 。
但是从示例代码中,我们也可以看出 app 还有一个 use 方法。是不是觉得很奇怪,js 中函数实例上,还以带方法,这在 js 中就叫 函数对象,不仅能调用,还可以带实例变量。给个例子可以看得更清楚:
function  handle () { 
   function  app(req, res, next) { app.handle(req, res, next)} 
  app.handle =  function  (req, res, next) { 
    console.log( this ); 
   } 
  app.statck = []; 
   return  app; 
 } 
 var  app = handle(); 
 app()  // ==> { [Function: app] handle: [Function], stack: [] } 
 app.apply({})  // ==>{ [Function: app] handle: [Function], stack: [] }可以看出:函数中的实例函数中的 this 就是指当前的实例,不会因为你使用 apply 进行环境改变。
其他就跟对象没有什么区别。
再次回到示例代码,因该可以看懂了, connect 方法返回了一个函数,这个函数能直接调用,有 use 方法,用来响应 http 的 request 事件。
到此为此,示例代码就讲完了。 我们开始进入到 connect 模块的内部。
connect 只有一个导出方法。就是如下:
 var  merge = require( 'utils-merge' ); 
 module.exports = createServer; 
 var  proto = {}; 
 function  createServer() { 
   // 函数对象,这个对象能调用,能加属性 
   function  app(req, res, next){ app.handle(req, res, next); } 
   merge(app, proto);  // ===等于调用 Object.assign 
   merge(app, EventEmitter.prototype);  // === 等于调用 Object.assign 
   app.route =  '/' ; 
   app.stack = []; 
   return  app; 
 }从代码中可以看出,createServer 函数把 app 函数返回了,app 函数有三个参数,多了一个 next (这个后面讲),app函数把 proto 的方法合并了。还有 EventEmitter 的方法也合并了,还增加了 route 和 stack 的属性。
从前面代码来看,响应 request 的事件的函数,是 app.handle 方法。这个方法如下:
 proto.handle =  function  handle(req, res, out) { 
   var  index = 0; 
   var  protohost = getProtohost(req.url) ||  '' ;  //获得 http://www.baidu.com 
   var  removed =  '' ; 
   var  slashAdded =  false ; 
   var  stack =  this .stack; 
 
   // final function handler 
   var  done = out || finalhandler(req, res, { 
    env: env, 
    onerror: logerror 
   });  // 接口 done(err); 
 
   // store the original URL 
   req.originalUrl = req.originalUrl || req.url; 
 
   function  next(err) { 
    if  (slashAdded) { 
     req.url = req.url.substr(1);  // 除掉 / 之后的字符串 
     slashAdded =  false ;  // 已经拿掉 
    } 
 
    if  (removed.length !== 0) { 
     req.url = protohost + removed + req.url.substr(protohost.length); 
     removed =  '' ; 
    } 
 
    // next callback 
    var  layer = stack[index++]; 
 
    // all done 
    if  (!layer) { 
     defer(done, err);  // 没有中间件,调用 finalhandler 进行处理,如果 err 有值,就返回 404 进行处理 
     return ; 
    } 
 
    // route data 
    var  path = parseUrl(req).pathname ||  '/' ; 
    var  route = layer.route; 
 
    // skip this layer if the route doesn't match 
    if  (path.toLowerCase().substr(0, route.length) !== route.toLowerCase()) { 
     return  next(err);  // 执行下一个 
    } 
 
    // skip if route match does not border "/", ".", or end 
    var  c = path[route.length]; 
    if  (c !== undefined && '/ ' !== c && ' . ' !== c) { 
     return next(err); // 执行下一个 
    } 
 
    // trim off the part of the url that matches the route 
    if (route.length !== 0 && route !== ' / ') { 
     removed = route; 
     req.url = protohost + req.url.substr(protohost.length + removed.length); 
 
     // ensure leading slash 
     if (!protohost && req.url[0] !== ' / ') { 
      req.url = ' /' + req.url; 
      slashAdded =  true ; 
     } 
    } 
 
    // call the layer handle 
    call(layer.handle, route, err, req, res, next); 
   } 
 
   next(); 
 };代码中有相应的注释,可以看出,next 方法就是一个递归调用,不断的对比 route 是否匹配,如果匹配则调用 handle, 如果不匹配,则调用下一个 handle.
call 函数的代码如下:
 function  call(handle, route, err, req, res, next) { 
   var  arity = handle.length; 
   var  error = err; 
   var  hasError = Boolean(err); 
 
   debug( '%s %s : %s' , handle.name ||  '' , route, req.originalUrl); 
 
   try  { 
    if  (hasError && arity === 4) { 
     // error-handling middleware 
     handle(err, req, res, next); 
     return ; 
    }  else  if  (!hasError && arity < 4) { 
     // request-handling middleware 
     handle(req, res, next); 
     return ; 
    } 
   }  catch  (e) { 
    // replace the error 
    error = e; 
   } 
 
   // continue 
   next(error); 
 } 可以看出一个重点:对错误处理,connect 的要求 是函数必须是 四个参数,而 express 也是如此。如果有错误, 中间件没有一个参数的个数是 4, 就会错误一直传下去,直到后面的 defer(done, err); 进行处理。
还有 app.use 添加中间件:
 proto.use =  function  use(route, fn) { 
   var  handle = fn;  // fn 只是一个函数的话 三种接口 // 1. err, req, res, next 2. req, res, 3, req, res, next 
   var  path = route; 
 
   // default route to '/' 
   if  ( typeof  route !==  'string' ) { 
    handle = route; 
    path =  '/' ; 
   } 
 
   // wrap sub-apps 
   if  ( typeof  handle.handle ===  'function' ) {  // 自定义中的函数对象 
    var  server = handle; 
    server.route = path; 
    handle =  function  (req, res, next) {  // req, res, next 中间件 
     server.handle(req, res, next); 
    }; 
   } 
 
   // wrap vanilla http.Servers 
   if  (handle  instanceof  http.Server) { 
    handle = handle.listeners( 'request' )[0];  // (req, res) // 最后的函数 
   } 
 
   // strip trailing slash 
   if  (path[path.length - 1] ===  '/' ) { 
    path = path.slice(0, -1); 
   } 
 
   // add the middleware 
   debug( 'use %s %s' , path ||  '/' , handle.name ||  'anonymous' ); 
   this .stack.push({ route: path, handle: handle }); 
 
   return  this ; 
 };从代码中,可以看出,use 方法添加中间件到 this.stack 中,其中 fn 中间件的形式有两种: function (req, res, next) 和 handle.handle(req, res, next) 这两种都可以。还有对 fn 情况进行特殊处理。
总的处理流程就是这样,用 use 方法添加中间件,用 next 编历中间件,用 finalHandle 进行最后的处理工作。
在代码中还有一个函数非常奇怪:
 /* istanbul ignore next */ 
 var  defer =  typeof  setImmediate ===  'function' 
   ? setImmediate 
   :  function (fn){ process.nextTick(fn.bind.apply(fn, arguments)) }defer 函数中的 fn.bind.apply(fn, arguments) ,这个方法主要解决了,一个问题,不定参的情况下,第一个参数函数,怎样拿到的问题,为什么这样说呢?如果中我们要达到以上的效果,需要多多少行代码?
 function  () { 
    var  cb = Array.from(arguments)[0]; 
    var  args = Array.from(arguments).splice(1); 
    process.nextTick( function () { 
      cb.apply( null ,args); 
    }) 
 }这还是 connect 兼容以前的 es5 之类的方法。如果在 es6 下面,方法可以再次简化
 function (..args){ process.nextTick(fn.bind(...args)) }总结
connect 做为 http 中间件模块,很好地解决对 http 请求的插件化处理的需求,把中间件组织成请求上的一个处理器,挨个调用中间件对 http 请求进行处理。
其中 connect 的递归调用,和对 js 的函数对象的使用,让值得学习,如果让我来写,就第一个调个的地方,就想不到使用 函数对象 来进行处理。
以上就是nodejs中connect的作用是什么,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注创新互联行业资讯频道。
本文标题:nodejs中connect的作用是什么
文章源于:http://www.scyingshan.cn/article/jgsjps.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 