session

session需要创建keys,所以在调用session之前我们需要创建一个keys生成器

创建utils目录

在该目录下创建一个genkey.js文件

const {
    v4: uuid
} = require("uuid");
const config = require("../config");
const fs = require("fs");

//循环生成keys
let keys = [];
for (let i = 0; i < config.keys_count; i++) {
    let key = "";
    while (key.length < config.keys_len) {
        key += uuid().replace(/\-/g, "");
    };
    key = key.substring(0, config.keys_len);
    keys.push(key);
};

//保存到本地
fs.writeFileSync(config.keys_path, JSON.stringify(keys));

console.log(`create keys ${config.keys_count}`);

for循环生成keys后保存到本地,config.js里面增加三个配置

config.js

const path = require("path");

module.exports = {
    //服务器
    port: 8081,

    //数据库
    sql: {
        host: "localhost",
        prot: 3306,
        user: "root",
        password: "123456",
        database: "koa"
    },

    //redis
    radsi: {
        host: "localhost",
        port: 6379,
        pass: undefined, //redis密码为空用undefined表示
    },

    //upload
    up_path: path.resolve(__dirname, "upload"), //默认上传路径
    up_size: 20 * 1024 * 1024, //默认文件大小

    //keys
    keys_count: 1024,
    keys_path: path.resolve(__dirname, ".keys"),
    keys_len: 1024
}

keys生成完毕后我们需要引入

libs/session.js

const session = require("koa-session");
const client = require("./redis");
const config = require("../config");
const fs = require("promise-fs");

module.exports = async function (server) {
  //读取本地的keys文件
  try {
    let buffer = await fs.readFile(config.keys_path);
    server.keys = JSON.parse(buffer.toString());
  } catch (e) {
    console.error("读取key文件失败,请重新生成", e);
    return;
  };

  //激活session
  server.use(session({
    maxAge: config.session_maxAge,
    renew: true,
    store: {
      async get(key, maxAge) {
        const data = await client.getAsync(key);

        if (!data) return {};

        try {
          return JSON.parse(data);
        } catch (e) {
          return {};
        }
      },
      async set(key, session, maxAge) {
        await client.psetexAsync(key, maxAge, JSON.stringify(session));
      },
      async destroy(key) {
        await client.delAsync(key);
      }
    }
  }, server));
}

server.js

const Koa = require("koa");
const config = require("./config");
const opn = require("opn");
const network = require("./libs/network");
const { post, upload } = require("./libs/post-body");
const Router = require("koa-router");


//server
let server = new Koa();


(async () => {
  //数据库
  server.context.db = await require("./libs/mysql");
  //Redis
  let client = await require("./libs/redis");
  server.context.redis = client;
  //全局错误处理
  server.use(async (ctx, next) => {
    try {
      await next();
    } catch (e) {
      ctx.status = 500;
      ctx.body = 'internal server error';
    }
  });

  //session
  await require("./libs/session")(server);

  //router
  let router = new Router();

  //post
  // router.post("/post", post(), async ctx => {
  //   console.log(ctx.request.fields);
  // });

  //upload
  // router.post("/upload", ...upload({
  //   path: undefined,
  //   size: undefined,
  //   error: (ctx, e) => { }, //错误回调
  //   sizeError: (ctx, e) => { } //文件过大的错误回调
  // }), async ctx => {
  //   console.log(ctx.request.fields);
  //   ctx.body = '上传成功';
  // });

  router.get("/", async ctx => {
    if (!ctx.session.view) {
      ctx.session.view = 1;
    } else {
      ctx.session.view++;
    }

    ctx.body = `第${ctx.session.view}次`;
  })


  //激活router
  server.use(router.routes());
  //监听
  server.listen(config.port);
  //输出运行地址
  network(config.port);


  opn(`http://localhost:${config.port}`, { app: 'chrome' });
})();

我们只需要传入server对象就行了,而redis对象,在node里面只要有一个地方先引入并使用了,第二次引入这个文件并不会再创建一个redis对象,而是对上一个redis对象的引用,所以我们requery同一个js文件,不会创建多个。

这样的话,其他的东西都是独立的,不需要再传什么参数了。

路由

路由有一个专门存放的文件夹:router,一般我们会在下面创建不同的文件夹作为区分,再通过index.js来着作为入口文件。

router
|
—— admin
| |
| —— index.js
—— web
| |
| —— index.js
|
—— index.js

大概是这么一个结构,可以自己进行嵌套。

router/index.js

const Router = require("koa-router");


let router = new Router();

//admin
router.use("/admin", require("./admin"));
//web
router.use("", require("./web"));


module.exports = router.routes();

admin&wen下的index

这两个目前没啥东西,内容都一样的.

const Router = require("koa-router");

let router = new Router();



module.exports = router.routes();

server.js

const Koa = require("koa");
const config = require("./config");
const opn = require("opn");
const network = require("./libs/network");
const { post, upload } = require("./libs/post-body");



//server
let server = new Koa();


(async () => {
  //数据库
  server.context.db = await require("./libs/mysql");
  //Redis
  server.context.redis = await require("./libs/redis");;
  //全局错误处理
  server.use(async (ctx, next) => {
    try {
      await next();
    } catch (e) {
      ctx.status = 500;
      ctx.body = 'internal server error';
    }
  });

  //session
  await require("./libs/session")(server);

  //router
  server.use(require("./router"));

  //监听
  server.listen(config.port);
  //输出运行地址
  network(config.port);


  opn(`http://localhost:${config.port}`, { app: 'chrome' });
})();

server里面直接引入router文件夹下的index就行了。

静态资源

也就是koa-static的使用,我们之前讲过,针对不同类型的资源,自定义缓存周期。

libs/static.js

const static = require("koa-static");
const { static_path } = require("../config");



module.exports = function (router) {
  //图片
  router.all(/\.(jpg|png|gif|tiff|ico)$/i, static(static_path, {
    maxage: 20 * 86400 * 1000
  }));
  //js
  router.all(/\.jsx?$/i, static(static_path, {
    maxage: 3 * 86400 * 1000
  }));
  //css
  router.all(/\.css$/i, static(static_path, {
    maxage: 7 * 86400 * 1000
  }));
  //网页
  router.all(/\.(html|htm|shtml)$/i, static(static_path, {
    maxage: 1 * 86400 * 1000
  }));

  router.all('/(.*)', static(static_path, {
    maxage: 20 * 86400 * 1000
  }));

};

config里面保存一个默认静态文件的路径

config.js

const path = require("path");

module.exports = {
  //服务器
  port: 8081,

  //数据库
  sql: {
    host: "localhost",
    prot: 3306,
    user: "root",
    password: "123456",
    database: "koa"
  },

  //redis
  radsi: {
    host: "localhost",
    port: 6379,
    pass: undefined,  //redis密码为空用undefined表示
  },

  //upload
  up_path: path.resolve(__dirname, "upload"),  //默认上传路径
  up_size: 20 * 1024 * 1024,  //默认文件大小

  //keys
  keys_count: 1024,
  keys_path: path.resolve(__dirname, ".keys"),
  keys_len: 1024,

  //session
  session_maxAge: 20 * 60 * 1000,

  //static
  static_path: path.resolve(__dirname, "static"),
}

router/index.js

因为static需要配合路由,所以我们在主路由引入

const Router = require("koa-router");
const staric = require("../libs/static");


let router = new Router();

//admin
router.use("/admin", require("./admin"));
//web
router.use("", require("./web"));

//static
staric(router);


module.exports = router.routes();

全局错误处理

也就是对404错误,和500错误优化一下。

原来我们写的全局,只有服务器报错才输出错误信息,给网页发送了一个简短的文字,但是如果ctx.body里面没有东西,有可能是没有这个路由,那么就应该返回404的,我们要针对这些做一个优化。

美化404和500一般就是通过返回一个html文件。

创建一个error目录,里面存放404.html,500.html文件

server.js

const Koa = require("koa");
const config = require("./config");
const opn = require("opn");
const network = require("./libs/network");
const { post, upload } = require("./libs/post-body");
const fs = require("promise-fs");



//server
let server = new Koa();


(async () => {
  //数据库
  server.context.db = await require("./libs/mysql");
  //Redis
  server.context.redis = await require("./libs/redis");;
  //全局错误处理
  let error_404 = "";
  try {
    error_404 = await fs.readFile(config.error_404_path);
    error_404 = error_404.toString();
  } catch (e) {
    console.error("read 404 file error");
  };

  let error_500 = "";
  try {
    error_500 = await fs.readFile(config.error_500_path);
    error_500 = error_500.toString();
  } catch (e) {
    console.error("read 500 file error");
  };

  server.use(async (ctx, next) => {
    try {
      await next();

      if (!ctx.body) {
        ctx.status = 404;
        ctx.body = error_404 || "404 Error";
      }
    } catch (e) {
      ctx.status = 500;
      ctx.body = error_500 || 'internal server error';
    }
  });

  //session
  await require("./libs/session")(server);

  //router
  server.use(require("./router"));

  //监听
  server.listen(config.port);
  //输出运行地址
  network(config.port);


  opn(`http://localhost:${config.port}`, { app: 'chrome' });
})();

ctx.body没有东西,就说明没有获取到内容,那就可以返回404了

分类: Node 标签: nodekoa

评论

暂无评论数据

暂无评论数据

目录