天天看点

Koa - Node.js框架学习@郝晨光

本文由郝晨光整理总结并编写,未经允许禁止转载。

前言

学习koa,我之前学习过express,但是在使用express的时候,还是一直使用的回调函数的方式来处理异步,现在想想真是恐怖,后来了解到koa这个框架,它相对于express来说,小巧了很多,对于异步的处理也变得更加优雅了。用官方的话来说,koa是基于Node.js平台的下一代web平台开发框架。

Koa - Node.js框架学习@郝晨光

正文

  1. 首先肯定要先开始一个新的项目,新建一个文件夹
  2. 在文件夹目录中,使用命令提示符执行

    npm init -y

    ,初始化

    package.json

    文件;
  3. 安装
    • Koa 依赖 node - v7.6.0 或 ES2015及更高版本和 async 方法支持。
    • 先查看node的版本

      node -v

      ;
    • 然后执行

      npm install koa

      进行安装;
  4. 使用
    • 新建index.js;
    • 先上官网上最经典的hello wrold案例;
    • const Koa = require('koa');
      const app = new Koa();
      app.use(async ctx => {
          ctx.body = 'hello word!'
      })
      app.listen(8000, () => {
          console.log('Koa server listen in http://localhost:8000/');
      })
                 
    • 打开浏览器,输入

      localhost:8000/

      ,就可以看到我们的页面上显示了hello world!;
    • 那我们的第一个koa应用就已经运行起来了~。
  5. 读取 HTML 页面
    • 在Koa中,我们如果要使用 HTML 应该怎么做呢?
    • 在原生nodejs或者express中,我们使用的是fs模块,然后使用回调函数,一层套一层;
    • 在Koa中,我们依旧使用fs模块,但是,要对fs模块的读取文件,进行进一步的封装;
    • 在目录下,我们新建一个

      index.html

      ,并随便写一点东西;
    • 接着开始我们渐行渐远的程序生涯;
    • const Koa = require('koa');
      const fs = require('fs');
      const app = new Koa();
      function readFile(url) {
        return new Promise((resolve, reject) => {
        	fs.readFile(url, (err,file) => {
        		if(err) {
        			reject(err);
        		}else {
        			resolve(file);
        		}
        	})
        })
      }
      app.use(async ctx => {
          ctx.response.type = 'html'; // 重点
          ctx.body = await readFile('index.html');
      })
      app.listen(8000, () => {
          console.log('Koa server listen in http://localhost:8000/');
      })
      // 本文由郝晨光整理总结并编写,未经允许禁止转载。
                 
    • 可以看到,我们利用Promise将fs模块的readFile方法进行了二次封装,读取了本地的index.html文件
    • 重点的地方我已经标出来了,为什么要标重点呢?
    • 因为在Koa中,ctx.body默认返回的类型是

      text/plain

      ;而我们要返回html文件,所以应该在返回文件之前,设置好返回类型,让客户端可以正确的接收;
    • 然后我们使用

      async + await

      组合,在数据读取完成之后,返回读取的文件;
    • 最后,打开浏览器,可以看到浏览器上输出的就是我们

      index.html

      文件中写的内容
  6. 读取静态资源
    • html文件我们已经可以正确的读取并返回了,在我们的页面上,避免不了会使用很多的静态资源,例如css、js、image、font等等;这些静态资源我们应该怎么处理呢?
    • 在这里,我们使用一个Koa的中间件

      koa-static

    • 在命令提示符中执行

      npm install koa-static

    • 接着书写我们的程序
    • // ~~ 省略 ~~
      const app = new Koa(); // 新建koa对象
      const KoaStatic = require('koa-static'); // koa静态文件读取
      app.use(KoaStatic(__dirname)); // 使用中间件
      // ~~ 省略 ~~
                 
      • 接着,打开我们的浏览器,可以看到静态资源已经可以正确的请求到了;
      • 当然了,这个时候,我们可以把之前返回html文件时设置响应类型的一步省略掉了,因为

        koa-static

        已经帮我们做了这件事了。
  7. 定义路由
    • 所谓的路由,就是根据不同的请求路径,响应不同的内容;
    • 在Koa中,我们可以定义原生路由,也可以使用封装好的路由中间件;
    • 先看一下原生路由的写法吧!
    • app.use(async ctx => {
      	if(ctx.request.method==='GET') { // GET请求
        	switch (ctx.request.path) {
        		case '/': // 匹配默认路由
        			ctx.body = await readFile('index.html'); // 返回index.html文件
        			break;
                case '/about': // 匹配/about路由
            		ctx.body = 'about路由页面'; // 返回about路由页面
        			break;
        		default:
        			ctx.body = await readFile('index.html'); // 默认返回index.html文件
        			break;
        	}
        }else if(ctx.request.method==='POST') { // POST请求
        	switch (ctx.request.path) {
        		default:
        			ctx.body = 'post 请求'; // 响应post请求
        			break;
        	}
        }
      });
      //本文由郝晨光整理总结并编写,未经允许禁止转载。
                 
    • 可以看到我上边写的,对请求方式以及路由进行了处理,在不同的请求方式,不同的请求路径下,执行不同的操作,响应不同的结果。
      Koa - Node.js框架学习@郝晨光
  8. 路由中间件
    • 我们使用原生方式定义路由,未免有些太过繁琐,并且代码不便于阅览和维护;所以,建议使用中间件的方式进行路由配置。
    • 我这里使用的是 koa-router 这个中间件,当然,koa的路由中间件不是只有这一种。
    • 在命令提示符中安装

      npm install koa-router

      ;
    • 接着,进行我们的程序生涯;
    • // ~~ 省略 ~~
      const KoaRouter = require('koa-router');
      const router = new KoaRouter();
      router.get('/',async ctx => {
          ctx.body = await readFile('index.html');
      });
      
      router.get('/about',async ctx=> {
           ctx.body = 'about路由页面'
      });
      
      router.post('/form',async ctx => {
          ctx.body = 'post请求'
      });
      
      app.use(router.routes());
      // ~~ 省略 ~~
                 
    • 打开页面,并进行路由切换,可以看到没有任何问题;
    • 但是这样所有的路由配置都写在了index.js中,不利于维护,所以我们要将路由内容和公用方法提取出来。
      Koa - Node.js框架学习@郝晨光
  9. 代码模块化
    • 首先对路由进行模块化
    • 在目录下新建routes文件夹,并新建home.js,用来存放关于首页的一些路由配置。
    • 将上边的路由代码单独写到home.js中,并抛出,如下:
    • home.js
    • const KoaRouter = require('koa-router');
      const router = new KoaRouter();
      
      router.get('/',async ctx => {
        ctx.body = await readFile('index.html');
      });
      
      router.get('/about',async ctx=> {
      	ctx.body = 'about 路由'
      });
      
      router.post('/from',async ctx => {
         ctx.body = 'post请求'
      });
      
      module.exports = router;
                 
    • index.js
    • const homeRouter = require('./routes/home');
      
      app.use(KoaStatic(__dirname));
      
      app.use(homeRouter.routes());
                 
    • 在index.js中,直接引入使用即可,和原有代码没有任何区别。
    • 需要注意的是,对于功能中间件,例如

      koa-static

      这种,我们应该放在路由中间件之前。
    • 否则的话可能会出错,在路由中不能正确的读取静态文件等。
  10. 二级路由
    • 已经学会了一级路由的定义,我们趁热打铁,学习二级路由
    • 在routes目录下,新建user.js,定义用户路由
    • // user.js
      const KoaRouter = require('koa-router');
      const router = new KoaRouter({
        prefix: '/user'
      });
      
      router.get('/',async ctx => {
        ctx.body = '用户界面'
      });
      
      router.get('/:id',async ctx => {
      	ctx.body = '用户详情'+ctx.params.id;
      });
      
      router.post('/login',async ctx => {
      	ctx.body = '用户注册成功!'
      });
      
      module.exports = router;
      
      // index.js
      // ~~ 省略 ~~
      const userRouter = require('./routes/user');
      // ~~ 省略 ~~
      app.use(userRouter.routes());
                 
    • 接着,打开浏览器,我们测试一下我们的二级路由,是没有任何问题的。
      Koa - Node.js框架学习@郝晨光
  11. post请求处理
    • 我们都知道,使用post请求一般用来提交表单,或者修改数据等。而post请求中的数据,存放在请求体中,使用原生Node的方法的话,我们需要监听原生req对象上的data方法以及end方法,并将数据格式转化。而express中,我们有一个

      body-parser

      的插件可以使用。
    • 那么在Koa中,我们应该使用什么呢?
    • 在Koa中,我们使用

      koa-bodyparser

      这个中间件来处理post请求的数据
    • 在命令提示符安装

      npm install koa-bodyparser

      ;
    • 接着我们在index.js中使用这个中间件;
    • 加入下面两行代码,与原先使用

      koa-static

      中间件位置一样即可;
    • const KoaBodyParser = require('koa-bodyparser');
      
      app.use(KoaBodyParser());
                 
    • 使用了这个中间件,我们就可以在

      ctx.request.body

      中拿到post请求的数据了;
    • router.post('/login',async ctx => {
          ctx.body = ctx.request.body;
       });
                 
    • 接着改造一下我们的html文件,提交一下表单;
    • <form action="/user/login" method="post">
        	姓名:<input type="text" name="name" autocomplete="off"/>
        	<br>
        	<input type="radio" name="sex" value="男"/>男
        	<input type="radio" name="sex" value="女"/>女
        	<input type="submit" value="提交form">
       	</form>
                 
      • 可以看到,表单提交正常,我们也正确的拿到了表单提交的数据。
        Koa - Node.js框架学习@郝晨光
  12. CORS跨域配置
    • 在我们现在的服务器生涯中,避免不了要使用跨域,特别是CORS跨域。
    • 那么,在Koa中,我们应该怎么去设置跨域呢?
    • 我们可以使用中间件,也可以使用原生方法手写。
    • 老规矩,先看原生方法。
    • app.use(async (ctx, next) => {
        	// 允许来自所有域名请求
        	ctx.set("Access-Control-Allow-Origin", "*");
        	// 这样就能只允许 http://localhost:8080 这个域名的请求了
        	// ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
      
        	// 设置所允许的HTTP请求方法
        	ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE");
      
        	// 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段.
        	ctx.set("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type");
      
        	// 服务器收到请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
      
        	// Content-Type表示具体请求中的媒体类型信息
        	ctx.set("Content-Type", "application/json;charset=utf-8");
      
        	// 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。
        	// 当设置成允许请求携带cookie时,需要保证"Access-Control-Allow-Origin"是服务器有的域名,而不能是"*";
        	ctx.set("Access-Control-Allow-Credentials", true);
      
        	// 该字段可选,用来指定本次预检请求的有效期,单位为秒。
        	// 当请求方法是PUT或DELETE等特殊方法或者Content-Type字段的类型是application/json时,服务器会提前发送一次请求进行验证
        	// 下面的的设置只本次验证的有效时间,即在该时间段内服务端可以不用进行验证
        	ctx.set("Access-Control-Max-Age", 300);
      
        	/*
        	CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
            Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
            */
        	// 需要获取其他字段时,使用Access-Control-Expose-Headers,
        	// getResponseHeader('myData')可以返回我们所需的值
        	ctx.set("Access-Control-Expose-Headers", "myData");
        	await next();
        })
                 
      • 原生方法来自:node.js 应答跨域请求实现(以koa2-cors为例)
      • 接着我们来看中间件吧!
      • 在Koa2中,我们使用

        koa2-cors

        这个中间件来设置CORS跨域请求。
      • 先安装

        npm install koa2-cors

        ;
      • 接着,在index.js中使用。
      • const KoaCors = require('koa2-cors');
        // ~~ 省略 ~~
        // CORS跨域
        app.use(KoaCors({
        	origin: ctx => {
        		return ctx.request.header.origin;
        	},
        	exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
        	maxAge: 5,
        	credentials: true,
          	allowMethods: ['GET', 'POST', 'DELETE', 'OPTIONS'],
        	allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'Origin'],
        }));
        //本文由郝晨光整理总结并编写,未经允许禁止转载。
                   
      • 特别需要注意的是,在

        app.use()

        使用

        koa2-cors

        的时候,我们应该把它放在别的中间件的前边,特别是静态资源处理和路由处理中间件的前边,这样可以保证我们在跨域请求静态资源的时候不会出问题。

如果本文对您有帮助,可以看看本人的其他文章:

前端常见面试题(十三)@郝晨光

前端常见面试题(十二)@郝晨光

前端常见面试题(十一)@郝晨光

结言

感谢您的查阅,本文由郝晨光整理并总结,代码冗余或者有错误的地方望不吝赐教;菜鸟一枚,请多关照

继续阅读