Koa-Router

  • Express 式路由使用app.get, app.put, app.post
  • Named URL parameters and regexp captures
  • String or regular expression route matching
  • Named Routes with URL generation
  • Responds to OPTIONS request with allowed methods
  • Support for 405 Method Not Allowed and 501 Not Implemented
  • Multiple route middleware
  • Multiple routers

安装

npm install koa-router
`</pre>

### 使用

<pre>`var koa = require("koa"),
    router = require("koa-router"),
    app = koa();

app.use(router(app))
`</pre>

After the router has been initialized you can register routes:

<pre>`app.get("/users/:id", function*(next){
  var user = yield User.findOne(this.params.id);
  this.body = user;
});
`</pre>

### 多路由

You can use multiple routers and sets of routes by omitting the `app` argument. For example, separate routes for two versions of an API:

<pre>`var koa = require("koa"),
    mount = require("mount"),
    Router = require("koa-router");

var app = koa();

var APIv1 = new Router();
var APIv2 = new Router();

APIv1.get("/sign-in", function*(){
  // ...
})
APIv2.get("/sign-in", function*(){
  // ...
})

app.use(mount("/v1", APIv1.middleware())).use(mount("/v2", APIv2.middleware()));
`</pre>

### 链

The http methods(get, post, etc) return their `Router` instance, so routes can be chained as you're used to with express:

<pre>`var api = new Router();

api.get("/foo", showFoo).get("/bar", showBar).post("/foo", createFoo)

编写 Koa 中间件

Koa middlewares are simple function which return a GeneratorFunction, and accept another (middleware). When the middleware is run by an “upstream” middleware, it must manually yield to the “downstream” middleware.

For example if you wanted to track how long it takes for a request to propagate through Koa by adding an x-Response-Time header field the middleware would look like the following:

function *responseTime(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set("X-Response-Time", ms+"ms");
}
app.use(responseTime);
`</pre>

Here is another way to write the same thing, inline:

<pre>`app.use(function *(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set("X-Response-Time", ms+"ms");
});
`</pre>

### 中间件最佳实践

Imcluding Middleware accepting options, named middleware for debugging, among others

#### 中间件选项

When creating public middleware it's useful to conform to the convention of wrapping the middleware in a function that accepts options, allowing users to extend functionality. Even if your middleware accepts no options, this is still a good idea to keep things uniform.

Here our contrived `logger` middleware accepts a `format` string for customization, and returns the middleware itself:

<pre>`function logger(format){
  format = format || ":method\":url\"";
  return function*(next){
    var str = format.replace(":method", this.method).replace(":url", this.url);
    console.log(str);
    yield next;
  }
}
`</pre>

app.use(logger());
app.use(logger(":method:url"))

<pre>`
### 命名中间件
Naming middlewares is optional, however it's useful for debugging purpose to assign a name
`</pre>

function logger(format){
  return function *logger(next){
    // ...
  }
}

<pre>`### 结合多个中间件
Sometimes you want to "compose" multiple middleware into a single middleware for easy re-use or exporting. To do so, you may chain them together with `.call(this, next)`, then return another function that yields the chain

function _random(next) {
if (‘/random’ == this.path) {
this.body = Math.floor(Math.random()_10);
} else {
yield next;
}
};

function *backwards(next) {
if (‘/backwards’ == this.path) {
this.body = ‘sdrawkcab’;
} else {
yield next;
}
}

function *pi(next) {
if (‘/pi’ == this.path) {
this.body = String(Math.PI);
} else {
yield next;
}
}

function *all(next) {
yield random.call(this, backwards.call(this, pi.call(this, next)));
}

app.use(all);
`

Koa 使用

安装

Koa 当前需要 node 0.11.x 并开启 –harmony(或– harmony-generators), 因为他依赖于 ES6的 generator 特性
node --harmony my-koa-app.js

应用

Koa 应用是一个包含中间件 generator 方法数组的对象. 当请求到来时, 这些方法会以 stack-slice 的顺序执行.

Koa 的一大设计理念是, 通过其他底层中间件层提供高级”语法糖”, 而不是 Koa, 大大提高了框架的互操作性和健壮性, 并让中间件开发变得有趣.

简单例子

var koa = require("koa");
var app = koa();
app.use(function*(){
  this.body = "Hello World";
});
app.listen(3000);
`</pre>

**注**: 与普通 function 不同, generator function 以 function* 的形式声明.

### 编写级联代码

koa 中间件以一种更加传统的方式级联.

以往的 Node 开发中, 级联是通过回调实现的, 用户友好度上有欠缺

Koa 借助 generator 实现了中间件架构

Koa 的执行代码的形式不再是简单的将控制权依次移交给一个又一个方法直到结束, 而是像一个回形针, 用户请求中间件, 遇到 yield next 关键字的时候, 会被传递给下游中间件(downstream), 在 yield next 捕获不到 downstream 的时候, 逆序返回执行代码(upstream)(yield next 后面的代码)

<pre>`var koa = require("koa");
var app = koa();

// x-response-time

app.use(function* (next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set("X-Response-Time", ms+"ms");
})

// logger
app.use(function* (next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  console.log("%s %s - %s", this.method, this.url, ms)
});

// response
app.use(function* (){
  this.body = "Hello World";
});

app.listen(3000);
`</pre>

### 应用配置

应用配置是 app 实例的属性, 目前支持以下配置:
- app.name 应用名
- app.env 执行环境, 默认是`NODE_ENV`或者`development`字符串
- app.proxy, 当该属性为 true 时, `proxy header` 参数会被添加到信任列表中

### app.listen(...)

一个 Koa 应用跟 HTTP Server 不是1-to-1关系, 一个或多个 Koa应用可以被加载到一块, 组成一个更大的包含一个 HTTP server 的应用

该方法创建并返回一个 http server, 并支持传递固定参数

<pre>`var koa = require("koa")
var app = koa()
app.listen(3000)
`</pre>

方法 app.listen(...)是一个语法糖, 等价于

<pre>`var http = require("http")
var koa = require("koa")
var app = koa()
http.createServer(app.callback()).listen(3000)
`</pre>

这意味着可以在多个端口使用同一个 app

<pre>`http.createServer(app.callback()).listen(3000)
http.createServer(app.callback()).listen(3001)
`</pre>

### app.callback()

返回一个回调方法能用于 http.createServer()来处理请求, 也可以将这个回调函数挂载到 Connect/Express 应用上

### app.use(function)

将给定的 function 当做中间件加载到应用中

### app.keys=

设置 Cookie 签名密钥

### 错误处理

除非应用执行环境(NODE_ENV)被配置为"test", Koa 都会将所有错误信息输出到 stderr, 如果想自定义错误处理逻辑, 可以定义一个"错误事件"来坚挺 Koa App 中的错误:

<pre>`app.on("error",function(err){
  log.error("server error", err);
})
`</pre>

当 req/res 周期中出现任何错误且无法响应客户端时, koa 会把 Context(上下文)实例作为第二个参数传递给 error 事件:

<pre>`app.on("error", function(err, ctx){
  log.error("server error", err, ctx)
})
`</pre>

### 上下文

Koa 的 Context 把 node 的 request 和 response 对象封装在一个单独对象, 并提供许多开发 web 应用和 APIs 有用的方法. 那些 HTTP Server 开发中使用非常频繁操作, 直接在 Koa 里实现, 而不是放在更高层次的框架, 这样中间件就不需要重复实现这些通用的功能.

每个请求会创建自己的 Context 实例, 在中间件中作为 receiver 引用, 或通过 this 标示引用:

<pre>`app.use(function* (){
  this; // is the Context
  this.request; // is a koa Request
  this.response; // is a koa Response
})

Context 的许多访问器和方法直接委托为他们的 ctx.request 或 ctx.response 的等价方法, 用于访问方便, 是完全相同的, 比如 ctx.type 和 ctx.length 委托与 response 对象, ctx.path 和 ctx.method 委托与 request.

请求

Koa Request 对象是 node 普通 request 对象之上的抽象, 提供了日常 Http Server 中更多有用的功能

API

  • request.header
  • request.headers: req.header 的别名
  • request.method: 请求方法
  • request.method=: 设置请求方法, 实现中间件的时候非常有用
  • request.length: 将请求的 Content-length 返回为数字, 或 undefined
  • request.url: 获取请求 URL
  • request.url=: 设置请求 URL

响应

Koa Response 对象是 node 普通 response 对象之上的抽象, 提供了日常 Http Server 中有用的功能

API

….

Node.js 之 Path 模块

path模块用于规范化路径连接和解析路径.

path的功能包括不仅限于:

  • 规范化路径
  • 连接路径
  • 路径解析
  • 查找两个绝对路径的相对关系
  • 提取路径的组成部分

规范化路径 path.normalize(p)

path 模块中的 normalize(p) 用来规范化路径, 可用于处理路径中的 //, .., .等.

var path = require('path');
path.normalize('./foo/bar//baz/asfd/que/..');
// 处理后
'foo/bar/baz/asfd'
`</pre>

### 连接路径 path.join([path1][, path2][, ...])

将任意个路径字符串连接, 同时也会对路径进行规范化

<pre>`var path = require('path');
//合法的字符串连接
path.join('./foo', 'bar', 'baz/asdf', 'quux', '..')
// 连接后
'foo/bar/baz/asfd'

// 不合法的字符串将抛出异常
path.join('foo',{}, bar) =&gt; TypeError: Arguments to path.join must be strings
`</pre>

### 路径解析 path.resolve([from...], to)

path.resolve 方法可以将多个路径解析为一个规范化的绝对路径, 其处理方法类似于对这些路径逐一进行 cd 操作, 与 cd 操作不同的是, 这引起路径可以是文件, 而且可不必实际存在, 仅是字符串操作

<pre>`path.resolve('foo/bar','/tmp/file/','..','a/../subfile')
`</pre>

相当于

<pre>`cd foo/bar
cd /temp/file/
cd ..
cd a/../subfile
`</pre>

如果解析的不是绝对路径, path.resolve() 会将当前工作目录加到解析结果前

<pre>`path.resolve('wooroot','bar','./baz')
// 当前工作路径是/home/node, 则输出结果是
'/home/node/wooroot/bar/baz'
`</pre>

### 查找两个绝对路径之间的相对关系 path.relative(from, to)

<pre>`path.relative('/Users/node/demo', '/Users/node') =&gt; '..'

提取路径的组成部分 path.dirname(p), path.basename(p[,ext]), path.extname(p)

path.dirname => 文件路径中的目录部分
path.basename => 文件路径中的文件部分
path.extname => 文件路径中的文件扩展名

Node

A Node is an interface from which a number of DOM types, and allows these various types to be treated similarly.

Properties

  • Node.baseURI: return a DOMStirng representing the base URL
  • Node.childNodes: return a live NodeList containing all the children of this node. NodeList being live means that if the children of the Node change, the NodeList will update automatically.
  • Node.firstChild: return a Node representing the first direct child Node of this Node, or Null if the node has no child.
  • Node.lastChild: Return a Node representing the last direct child Node of this Node, or Null if the node has no child.
  • Node.nextSibling: return a Node representing the next Node in the tree, or null if there is no one.
  • Node.previousSibling
  • Node.nodeName: return a DOMString containing the name of the node. The structure of the name will differ with the name type. E.g. An HTMLElement will contain the name of the corresponding tag, like “audio”, for an HTMLAudioElement, a Text node will have the “#text” string, or a Document node will have the “#document” string.
  • Node.nodeType: return an unsigned short representing the type of the node. Possible values are:





































Name Value
Element_Node 1
Attribute_Node 2
Text_Node 3
Document_Node 9
Document_Type_Node 10
Notation_Node 12
  • Node.nodeValue: return a DOMString representing the value of an object. For most node types, this returns null, and any set operation is ignored.
    For Nodes of type TEXT_NODE(Text objects), COMMENT_NODE(Comment objects), and PROGRESSING_INSTRUCTION_NODE(ProgressingInstruction objects), the value corresponds to the text data contained in the obejct.
  • Node.parentNode: return a Node that is the parent of this node, if there is no such node, like if this node is the top of the tree or if doesn’t participate in a tree, this property returns Null.
  • Node.parentElement: returns an Element that is the parent of this node. If the node has no parent, or if that parent is not an Element, this property returns Null.
  • Node.rootNode: return a Node representing the topmost Node in this tree or the current node if it’s the topmost node in the tree.
  • Node.textContent: is a DOMString representing the textual content of an element and all its descendants.

Methods

  • Node.appendChild()
  • Node.cloneNode(): Clone a Node and optionally all of its contents. By default, it clones the content of the node.
  • Node.hasChildNodes(): return a boolean indicating if the element has any child nodes, or not.
  • Node.insertBefore(newNode, beforeItsChild)
  • Node.isEqualNode(): return a boolean which indicating whether or not two nodes are of the same type and all their defining data points match.
  • Node.isSameNode(): return a boolean value indicating whether or not the two nodes are the same(that is they reference the same object).
  • Node.removeChild()
  • Node.replace(newNode, replaceItsChild)

    *   Note: replaceNode will not generate new one.</p>
    
    • E.g.

      ul&gt;li*3

      ul.replace(li[2],li[0])

      it will act as:
      remove li[2], put it li[0], remove li[0], so the result looks like

      ul
      –li[2]
      –li[1]
      `

    Examples

    Browser All Child Nodes

    The following function recursively cycles all child nodes of a node and executes a callback function upon them(and upon the parent node itself).

    `function DOMComb(oParent, oCallBack){
      if(oParent.hasChildNodes()){
        for(var oNode = oParent.firstChild; oNode; oNode = oNode.nextSibling){
          DOMComb(oNode, oCallBack);
        }
      }
      oCallBack.call(oParent);
    }
    `

    Remove all children nested within a node

    `Element.prototype.removeAll = function(){
    while(this.firstChild){

    this.removeAll(this.firstChild);
    

    }
    return this;
    };

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×