Koa2 —(2)

1、数据获取

1.1、Get 请求数据获取

  在 Koa 中,获取 Get 请求数据是通过 Koa 的 request 对象中 query 方法或者 querystring 方法,query 返回的是格式化好的参数对象,querystring 返回的是请求字符串。由于 ctx 对 request 的 API 有直接引用的方式,所以获取 Get 请求数据有两个途径。

  • 从上下文中直接获取
    • 请求对象 ctx.query, 返回如 {a: 1, b: 2}
    • 请求字符串 ctx.querystring,返回如 a=1&b=2
  • 从上下文的 request 对象中获取

    • 请求对象 ctx.request.query,返回{a:1,b:2}
    • 请求字符串 ctx.querystring, 返回 a=1&b=2

      const Koa = require('koa');
      const app = new Koa();  
      app.use(async (ctx) => {
        let url = ctx.url;
        // 从上下文中直接获取
        let ctx_query = ctx.query;
        let ctx_querystring = ctx.querystring;
      
        // 从ctx.request中获取
        let request = ctx.request;
        let req_query = request.query;
        let req_querystring = request.querystring;
      
        ctx.body = {
          url,
          ctx_query,
          ctx_querystring,
          req_query,
          req_querystring
        }
      });
      
      app.listen(3000, () => {
        console.log("request get is starting at port 3000");
      });
      
      输出结果:
      {
          "url": "/?id=1&name=%27s%27",
          "ctx_query": {
              "id": "1",
              "name": "'s'"
          },
          "ctx_querystring": "id=1&name=%27s%27",
          "req_query": {
              "id": "1",
              "name": "'s'"
          },
          "req_querystring": "id=1&name=%27s%27"
      }
      
1.2、POST 请求数据获取

  对于 POST 请求的处理,Koa2 并没有封装获取参数的方法,需要通过解析上下文 context 中原生 node.js 请求对象 req ,将POST 表单数据解析成 query string,再将 query string 解析成 JSON 格式。

注意:ctx.request 是 context 经过封装的请求对象,ctx.req 是 context 提供的 node.js 原生 HTTP 请求对象;ctx.response 是 context 经过封装的响应对象,ctx.res 是 context 提供的 node.js 原生 HTTP 响应对象。

const Koa = require('koa');
const app = new Koa();
app.use(async (ctx) => {
  if(ctx.url === '/' && ctx.method === 'GET'){
    // 当 GET 请求时返回表单页面
    let html = `
            <h1>Koa2 request post demo</h1>
            <form method="POST" action="/">
              <label>name</label>
              <input name="name" type="text" /><br/>
              <label>age</label>
              <input name="age" type="text" />
              <button type="submit">submit</button>
            </form>
    `;
    ctx.body = html;
  } else if(ctx.url === '/' && ctx.method === "POST"){
    // 当 POST 请求时,解析 POST 表单里的数据,并显示出来          
    let postData = await parsePostData(ctx);
    ctx.body = postData;
  } else {
    // 其他请求显示 404 
    ctx.body = '<h1>404 <h1>';
  }
})
// 解析上下文里 node 原生请求的 POST 参数
function parsePostData(ctx){
  return new Promise((resovle, reject) => {
    try{
      let postData = "";
      ctx.req.on("data", (data) => {
        postData += data;
      });
      ctx.req.on("end", () => {
        let parseData = parseQueryStr(postData);
        resovle(parseData);
      })
    } catch (err) {
      reject(err);
    }
  });
}
// 将 POST 请求参数字符串解析成 JSON
function parseQueryStr(queryStr){
  let queryData = {};
  let queryStrList = queryStr.split('&');
  console.log(queryStrList);
  for(let str of queryStrList){
    let itemList = str.split('=');
    queryData[itemList[0]] = decodeURIComponent(itemList[1]);
  }
  return queryData;
}

app.listen(3000, () => {
  console.log("request post is starting at port 3000");
})
1.3、koa-bodyparser 中间件

  对于 POST 请求的处理,koa-bodyparser 中间件可以把 Koa2 上下文的 formData 数据解析到 ctx.request.body 中。
安装 Koa2 版本的 koa-bodyparser@3 中间件

npm install --save koa-bodyparser@3

const Koa = require('koa');
const app = new Koa();
const bodyParser = require('koa-bodyparser');
// 使用中间件将结果解析到 ctx.request.body
app.use(bodyParser());
app.use(async (ctx) => {
  if(ctx.url === '/' && ctx.method === 'GET'){
    let html = `
          <h1>koa-bodyparser demo</h1>
          <form method="POST" action="/">
            <label>name</label>
            <input type="text" name="name" /><br/>
            <label> age</label>
            <input type="text" name="age" /><br/>
            <button type="submit">submit</button>
          </form>
    `;
    ctx.body = html;
  } else if(ctx.url === '/' && ctx.method === "POST"){
    let postData = ctx.request.body;
    ctx.body = postData;
  } else {
    ctx.body = '<h1>404</h1>';
  }
});
app.listen(3000, () => {
  console.log("koa-bodyparser demo at port 3000");
});

2、路由

2.1、原生路由

  通过 ctx.request.path 或者 ctx.request.url 可以获得用户请求的路径,由此实现简单的路由。

app.use(ctx => {
    if(ctx.request.path === '/'){
        ctx.response.body = "hello world";
    } else {
        ctx.response.type = "html";
        ctx.response.body = '<a href="/"> 首页 </a>';
    }
});
2.2、koa-route 模块

  当路由过多时,原生路由写法将要处理很多代码,这时就需要对应的路由中间件对路由进行控制。

const Router = require('koa-router');
// 子路由1
let home = new Router();
home.get('/', async (ctx) => {  });
// 子路由2 
let page = new Router();
page.get('/404', async (ctx) => { });
// 装载所有的路由
let router = new Router();
router.use('/', home.routes(), home.allowedMethods());
router.use('/page', page.routes(), page.allowedMethods());
// 加载路由中间件
app.use(router.routes()).use(router.allowedMethods());

  Koa-router 实例提供一系列动词方法,即一种 HTTP 动词对应一种方法。

  • router.get()
  • router.post()
  • router.put()
  • router.del()
  • router.patch()

这些动词方法可以接受两个参数,第一个是路径模式,第二个是对应的控制器方法(中间件),定义用户请求该路径时服务器行为。

注意:
  (1)路径匹配时,不会把查询字符串考率在内。即 /index?param=xyz 匹配路径 /index
  (2)有些路径模式较复杂时,Koa-router 允许为路径模式起别名。起名时,别名要添加为动词方法的第一个参数,这时动词方法变成接受三个参数。

router.get('user','/users/:id', callback);

上面代码中,路径模式 /users/:id 的名字就是 user。路径的名称,可以用来引用对应的具体路径,比如 url 方法可以根据路径名称,结合给定的参数,生成具体的路径。

router.url('user',3); => /users/3
router.url('user',{id:3});

上面代码中,user 就是路径模式的名称,对应具体路径 /users/:id。url 方法的第二个参数 3 ,表示给定 id 的值是3 ,因此最后生成的路径是 /users/3
  (3)Koa-router 允许为路径统一添加前缀。

var router = new Router({prefix: '/users'});
router.get('/', callback); => /users
router.get('/:id', callback); => /users/:id

3、静态资源

  一个 HTTP 请求访问 web 服务静态资源,一般响应结果分为三种情况:

  • 访问文本,例如 js、css、PNG、JPG、GIF
  • 访问静态目录
  • 找不到资源,抛出错误

如果为他们一个个写路由会很麻烦,因此可以使用 koa-static 模块,该模块封装了这部分请求。

const Koa = require('koa');
const path = require('path');
const static = require('koa-static');
const app = new Koa();
// 静态资源目录对于相对入口文件index.js的路径
const staticPath = './static'
app.use(static(path.join(__dirname, staticPath)));
app.use(async (ctx) => {
  ctx.body = "hello world";
});
app.listen(3000, () => {
  console.log('[demo] static-use-middleware is starting at port 3000')
})

4、cookie

  koa 提供了从上下文直接读取、写入 cookie 的方法。

  • ctx.cookies.get(name, [options])读取上下文请求中的 cookie
  • ctx.cookies.set(name, value, [options]) 在上下文中写入 cookie

options 的配置如下:

  • signed:cookie 是否加密(如果加密的话必须用 app.keys 指定加密短语)
  • maxAge:cookie 有效时长
  • expires:cookie 何时过期
  • path:cookie 的路径,默认为 ‘/’
  • domain:cookie 的域名
  • secure:cookie 是否只有 https 请求下才发送
  • httpOnly:是否只有服务器可以去到 cookie,默认为 true
  • overwrite:是否允许重写

    const Koa = require('koa');
    const app = new Koa();
    app.keys = ['secret1', 'secret2'];
    app.use(async (ctx) => {
      if(ctx.url === '/index'){
        ctx.cookies.set(
          'cid',
          'hello worls',
          {
            signed:true,
            domain: '127.0.0.1',
            path: '/index',
            maxAge: 10 * 60 * 1000,
            expores: new Date('2017-09-09'),
            httpOnly: false,
            overwrite: false,
            secure: false
          } // 不用全写
        );
        ctx.body = 'cookies is ok';
      } else {
        ctx.body = 'hello world';
      }
    });
    app.listen(3000, () => {
      console.log('[demo] cookie is starting at port 3000')
    })
    

5、session

  koa 原生功能只提供了 cookie 的操作,但是没有提供 session 操作。session 就只用自己实现或者通过第三方中间件实现。在 koa2 中实现 session 的方案有以下几种:

  • 如果 session 数据量很小,可以直接存在内存中
  • 如果 session 数据量很大,想、则需要存储介质存放 session 数据

数据库存储方案

  • 将 session 存放在 MySQL 数据库中
  • 需要用到的中间件
    • koa-session-minimal 适用于 koa2 的 session 中间件,提供存储介质的读写接口
    • koa-mysql-session 为 koa-session-minimal 中间件提供 MySQL 数据库的 session 数据读写操作
    • 将 sessionId 和对应的数据存储到数据库
  • 将数据库存储的 sessionId 存到页面的 cookie 中
  • 根据 cookie 的 sessionId 去获取对应的session 信息。

参考Koa2进阶学习笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值