koa

Author Avatar
A Man Has No Name 4月 01, 2017
  • 在其它设备中阅读本文章

这是项目被证明其实行不通,但是过程还是可以记录一下。

Koa 2

这是一个极其简单的的Web框架,核心框架就几个文件。它需要的环境必须大于等于Node V7(另一种方式我觉得就不要试了),因为它使用了原生的Async/Await方法,这些都可以有效的避免回调地狱的问题。

1
2
3
4
application.js # 核心库
context.js # 上下文处理,比如toJson(), Error处理,Request和Response处理路由
request.js # Request 详细处理类
response.js # Response 详细处理类

  1. 老规矩,Hello World镇楼:
1
2
3
4
5
6
7
8
const Koa = require('koa');
const app = new Koa();
app.use(cxt => {
ctx.body = 'Hello World';
});
app.listen(3000);
  1. 当你需要写一些需要回调的方法时候,用Node V7就爽了:
1
2
3
4
5
6
7
8
9
10
11
12
const Koa = require('koa');
const app = new Koa();
# 这就是怎么写一个异步的程序,是不是爽。
app.use(async ctx => {
const start = new Date();
await next();
const ms = new Date() - start;
ctx.set('X-Response-Time', `${ms}ms`);
ctx.body = '哈哈哈';
});
  1. 处理错误以及异常
1
2
3
4
app.on('error', err =>
log.error('server error', err)
);

抛出异常

1
2
3
ctx.throw(403);
ctx.throw('name required', 400);
ctx.throw(400, 'name required');

  1. 获取Request信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    # 获取POST信息
    Post: ctx.request.body;
    # 获取问号传值的信, 比如?a=b, 那么就可以写成 ctx.request.query.a
    Get: cxt.request.query;
    ctx.header
    ctx.headers
    ctx.method
    ctx.method=
    ctx.url
    ctx.url=
    ctx.originalUrl
    ctx.origin
    ctx.href
    ctx.path
    ctx.path=
    ctx.query
    ctx.query=
    ctx.querystring
    ctx.querystring=
    ctx.host
    ctx.hostname
    ctx.fresh
    ctx.stale
    ctx.socket
    ctx.protocol
    ctx.secure
    ctx.ip
    ctx.ips
    ctx.subdomains
    ctx.is()
    ctx.accepts()
    ctx.acceptsEncodings()
    ctx.acceptsCharsets()
    ctx.acceptsLanguages()
    ctx.get()
  2. 获取Response信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ctx.body
    ctx.body=
    ctx.status
    ctx.status=
    ctx.message
    ctx.message=
    ctx.length=
    ctx.length
    ctx.type=
    ctx.type
    ctx.headerSent
    ctx.redirect()
    ctx.attachment()
    ctx.set()
    ctx.append()
    ctx.remove()
    ctx.lastModified=
    ctx.etag=

嗯,就是这么简单。

Koa Router

毕竟,这个框架太简洁,如果我们要单独处理,http method,大概大家会疯掉的,于是,偷懒一下;引入一个扩展
Koa Better Router

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 引入router
let Router = require('koa-better-router');
let router = Router().loadMthods();
# 可以使用HTTP METHODS的方法
router.get('/api/', async ctx => {
});
router.post('/api/', async ctx => {
});
router.put('/api/', async ctx => {
});
router.del('/api/', async ctx => {
});
# 如果想添加一些参数
router.get('/api/:id/:name,', async ctx => {
# 现在我们取出参数
let id = ctx.params.id;
let name = ctx.params.name;
# 是不是超级方便
});
# 加入router扩展, 如果一个警告说你,版本不对,那么直接引入
# const convert = require('koa-convert'),
# 然后引入 convert(router.middleware());
app.use(router.middleware());

Koa Body

同样,我觉得原生的对于post的处理很不好(懒),所以,我决定引入扩展(‘koa-bodyparser), 它可以更友好的处理body的解析。
如果,是传递的是Content-Type: application/json, 那么它会自动解析成JS对象。

1
2
3
4
5
6
7
8
var bodyParser = require('koa-bodyparser');
app.use(bodyParser());
app.use(async ctx => {
# ctx.request.body, 是获取的Request的JS对象.
ctx.body = ctx.request.body;
#很方便 这时候,你访问url的时候,会自动添加Response: 'Content-Type: application/json'
});

Koa Render

呃,主要是用来渲染页面方便

1
2
3
4
5
6
7
8
9
10
11
12
var views = require('koa-views');
//设置view目录
app.use(views(__dirname + '/views'));
router.get('/api/', async ctx => {
// views/user.html , 传递参数为 {user: '哈哈哈哈'}
await ctx.render('user', {
user: '哈哈哈哈'
});
});

Mongoose

MongoDB 的ORM扩展, 可以很方便的的查询数据库等等,借助于语言本身天生异步处理,所以可以实现最大化的性能优势。

  • 首先,可以创建models的文件, 数据类型如下

    • String
    • Number
    • Date
    • Boolean
    • Mixed (这个有点意思,混合类,由于mongo可以是数组,也可是Object)
    • ObjectId , MongoID类型,当然也可以生成的字符串类型的对象ID,new Mongoose.ObjectId, 就会生成的ID(其实一般也没啥用)
    • Array
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      # 创建文件App.js
      module.exports = new Schema(
      {
      app_name: {
      type: Schema.Types.String,
      index: true, // 表示它是索引
      unique: true,//唯一,不能重复
      maxlength: 20 //表示最大长度是20,如果输入超过20,数据库会报错,注意,这个错误是程序级别的,不是数据库级别的。
      },
      app_name_hash: {
      type: Schema.Types.String
      },
      app_version: Schema.Types.String, //版本
      app_content: Schema.Types.Mixed, // 内容
      project_info: {
      project_name: Schema.Types.String, //基础信息中的项目名称
      project_id: Schema.Types.Number, // 基础信息中的项目ID
      },
      status: {
      type: Schema.Types.Number,
      default: 1 //1, 正常; 2, 关闭,
      },
      preview_port: Schema.Types.Number //预览端口
      },
      {
      collection: 'app_templates'
      }
      );
  • 查询一个

    • 查询一个App
      1
      2
      3
      4
      5
      6
      7
      8
      9
      # 引入model
      let model = require('App');
      # 查询一条数据
      let app_info = App.findOne({
      app_name: params.app_name,
      app_version: params.app_version
      });
      # 查询多条数据, select表示,保留哪些fields字段
      let app_components = App.find().select({comp_id: 1, comp_name: 1, comp_desc: 1, _id:0}).exec();
  • 插入一条数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let model = require('App');
    let app = new App(
    {
    app_name: params.app_name,
    app_name_hash: app_name_hash,
    app_version: app_version,
    app_structure: {},
    app_content: {},
    project_info:{
    project_name: params.project_name,
    project_id: params.project_id
    },
    preview_port: params.preview_port
    });
    # 注意异步的事情,有可能它还没执行完,就去执行下一步了,哈哈哈哈哈,小心哟
    app.save();

    更新一条数据

    1
    2
    3
    4
    5
    6
    7
    # 先查一下, 再更新
    let app_info = App.findOne({
    app_name: params.app_name,
    app_version: params.app_version
    });
    app_info.app_name = '哈哈哈哈';
    app_info.save();

Cherrio

用来快速解析HTML

Fs-extra

用来扩展FS文件处理。

Strongloop