Koa异常处理说明

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Koa异常处理说明相关的知识,希望对你有一定的参考价值。

参考技术A

由于项目在Koa顶层有统一的异常处理,因此正常情况下,我们是需要编写 try catch 的,除非我们需要做对这个异常进行编辑,或者是这个异常我们自己能处理,不希望该异常冒泡到 统一异常处理函数

异常在各种开发语言中都有广泛的应用,适时的抛出 有效 的异常可以帮助开发者理解程序逻辑。例如:

koa uses http-errors to create errors,点过去看看。

统一异常处理的好处不用多说,那么在 Koa 中,如何使用?

我们先查看 Koa 的 API 文档,找到错误处理段落,原文如下:

因此,我们只需要给 Koa 添加一个异常监听事件并且处理这个事件就可以了。

到了这一步应该就差不多了,思路是添加一个全局的异常监听事件,当异常发生时,对其进行统一的处理。

根据客户端接受数据类型,区分返回格式,对于请求页面的,我们最好能重定向到相应的页面,区分 404 和 500 等异常页面,对用户来说会更加友好。

由于异常页面数量有限,直接写成静态页面即可,虽然节约的性能并不明显,主要是 UI 可能会提供不同风格的异常页面,方便定制。

所谓的 统一异常处理 ,无非就是在程序的最外层,包上一层 try catch ,以至于所有的异常都会被这个 catch 给catch住。但是我们注意上面的那段文档中有一句话:

default error handler also won\'t outputs errors when err.status is 404 or err.expose is true 。

大致意思是 404 是不会抛出异常的,也就是说我们写的这个 errorHandler 不会处理 404页面
那怎么办?少里 404 的异常处理还叫 统一的 异常处理么?

显然不是,所以我们得想办法解决。那为什么404不抛出异常呢?因为 404 是服务器没有找到访问目标,也就是 Koa 路由没有匹配到对于的url,并不是执行异常,因此无法被 try catch catch住。
因为它不是异常,所以不能被catch住,那么我们就为的给它抛出异常,这样问题不就解决了。

我们需要在 koa-router 加载之前,添加一个中间件,如下:

这样相当于在 koa-router 后面添加了一层判断。当路由匹配失败后,判断返回是不是404,如果是的,我们就手工抛出 404异常 , 这样就能被我们的统一异常处理方案处理了。

Koa笔记 02:常用中间件

目的

前面的文章 《Koa笔记 01:基础入门》 中对Koa做了个基础的介绍,Koa是个 HTTP中间件框架 ,本身并没有提供很多真正业务处理的功能,需要搭配各种中间件来实现,这篇文章选一些常见的中间件进行介绍。

基础说明

Koa的一些热门的中间件可以在这里找到 https://github.com/koajs/koa/wiki ,也可以在 https://www.npmjs.com/ 中通过关键词搜索,比如 koa websocket

需要注意的是Koa目前大版本到了Koa2,和版本1有较大的变化,中间件使用上要注意版本问题。

Koa的中间件都是一些函数,通过 Koa对象的 use() 方法来注册使用, use() 方法注册使用的先后顺序会影响一个HTTP请求中中间件调用的先后顺序,所以使用 中间件的先后顺序非常重要,接近入口或是出口的中间件需要放在前面 ,比如下面示例:

const Koa = require('koa');
const logger = require('koa-logger');
const helmet = require('koa-helmet');
const Router = require('@koa/router');
const serve = require('koa-static');
const conditional = require('koa-conditional-get');
const etag = require('koa-etag');
const compress = require('koa-compress');

const app = new Koa();
const router = new Router();

app.use(logger()); // 收到请求和发送响应时打印日志,在收发最两头处理

app.use(helmet()); // 处理一些安全性相关的HTTP头,在收到请求时处理

app.use(conditional()); // 缓存处理,在收到请求时处理
app.use(etag());

app.use(compress({br: false})); // 响应数据压缩,在进行应答时处理

app.use(router.routes()); // 路由处理,通常主要工作在此

app.use(serve(__dirname + '/static/', { maxage: 600000 })); // 文件服务,通常放在最后

app.listen(3000);

// 上面代码中完整的中间件顺序如下
// logger -> helmet -> conditional -> etag -> compress -> router -> serve -> router -> compress -> etag -> conditional -> helmet -> logger

// 有些中间件只在请求或响应阶段处理事务,所以实际的流程可能如下
// logger -> helmet -> conditional -> etag -> router -> serve -> compress -> etag -> conditional -> logger

// 实际上还会根据情况不同流程也会不一样,比如如果请求头部有安全问题那流程可能就是下面这样的
// logger -> helmet -> logger

安全防护

koa-helmet 这个中间件用来处理一些安全性相关的HTTP头,可以提高应用程序的安全性。

项目地址:https://github.com/venables/koa-helmet

使用 npm i koa-helmet 进行安装,当前版本为 6.1.0 。当前版本总共提供11项安全方面保护,使用方式如下:

const helmet = require('koa-helmet');

app.use(helmet()); // 启用所有安全保护功能

URL路由

URL路由是HTTP服务器最基础的功能需求,Koa中比较热门的中间件有下面两个:

@koa/router 项目地址:https://github.com/koajs/router
koa-route 项目地址:https://github.com/koajs/route

这里主要介绍下前者 @koa/router ,这个中间件源自于 koa-router(https://github.com/ZijianHe/koa-router)。

使用 npm i @koa/router 进行安装,当前版本为 10.1.1 。下面是个简单的使用演示:

const Koa = require('koa');
const Router = require('@koa/router');

const app = new Koa();
const router = new Router();

// GET /a
router.get('/a', (ctx, next) => {
    ctx.body = 'Hello Koa';
});

// POST /b
router.post('/b', (ctx, next) => {
    ctx.body = 'Hello Naisu';
});

app.use(router.routes()); // 启用路由

// 如果使用了不支持的方法访问响应头会返回 405 Method Not Allowed 和 Allow 字段
app.use(router.allowedMethods()); 

app.listen(3000);


上面演示中用到了 GETPOST 方法,此外还支持 PUTDELETErouter.del())方法,另外可以用 router.all() 来接收所有方法的请求。

上述添加url和回调函数的方法都可以填入多个回调函数(其实就相当于多个中间件),比如下面演示:

@koa/router 可以使用 redirect() 方法进行url重定向,比如下面演示:

@koa/router 支持动态路径,比如下面演示:

@koa/router 支持嵌套使用,比如下面演示:

body处理

body部分内容处理是HTTP服务器最基础的功能需求,Koa中比较热门的中间件有下面两个:

koa-body 项目地址:https://github.com/koajs/koa-body
koa-bodyparser 项目地址:https://github.com/koajs/bodyparser

这里主要介绍下前者 koa-body 。

使用 npm install koa-body 进行安装,当前版本为 4.2.0

Koa默认的Request是没有body对象的,用了 koa-body 之后就有body对象了:

const Koa = require('koa');
const koaBody = require('koa-body');
const app = new Koa();

app.use(koaBody());
app.use(ctx => {
    console.log(ctx.request.body);
});

app.listen(3000);

当然一般来说 POST 、 PUT 这些方法的 Request 中才会有 body 内容,所以这个中间件通常会结合上面的路由中间件来使用,下面是个简单的演示:

上面演示中可以看到对于 x-www-form-urlencoded 和 json 类型的body数据,该中间件默认会将其转换为JS对象。

koa-body 支持接收客户端上传的文件(file uploads),使能 multipart/form-data 格式消息体接收后 使用 ctx.request.files 即可获取,比如下面演示:

默认情况下接收的文件会存放在系统临时目录中(os.tmpDir())。

上面演示中设置了 multipart 选项参数,除了这个 koa-body 还有很多选项可以设置,主要是下面这些:

选项类型说明默认值
patchNodeBoolean将body附加到ctx.reqfalse
patchKoaBoolean将body附加到ctx.requesttrue
jsonLimitString / Integerjson body数据字节数限制1mb
formLimitString / Integerform body数据字节数限制56kb
textLimitString / Integertext body数据字节数限制56kb
encodingString编码格式utf-8
multipartBoolean解析multipart/form-datafalse
urlencodedBoolean解析urlencodedtrue
textBoolean解析texttrue
jsonBoolean解析jsontrue
jsonStrictBooleanjson严格模式true
includeUnparsedBoolean设置为true时可以获得为解析的body数据false
formidableObjectmultipart/form-data相关的更多选项
onErrorFunction错误处理,例如 onError(error, context){ }
strictBoolean启用后不会解析GET/HEAD/DELETE方法的bodytrue
parsedMethodsString[]要处理解析body的方法[‘POST’, ‘PUT’, ‘PATCH’]

上面的 formidable 对象的可设置选项如下:

选项类型说明默认值
maxFieldsInteger字段数量限制1000
maxFieldsSizeInteger字段总字节数限制(文件除外)2mb
uploadDirString文件接收目录os.tmpDir()
keepExtensionsBoolean保留文件原始扩展名false
hashString如果要计算问价hash,可以设置为sha1或md5false
multiplesBoolean多文件上传true
onFileBeginFunction开始接收文件事件,onFileBegin(formName, file){ }
https://github.com/node-formidable/formidable#filebegin

静态文件

静态文件服务是HTTP服务器最基础的功能需求,Koa中比较热门的中间件主要是 koa-static

项目地址:https://github.com/koajs/static

使用 npm install koa-static 进行安装,当前版本为 5.0.0 ,使用方法如下:

const serve = require('koa-static');

app.use(serve(root, opts)); // root是静态文件所在目录,opts是可用选项

可用选项如下:

选项说明默认值
maxage设置max-age值,单位为毫秒0
hidden传输隐藏文件false
index默认文件index.html
defer如果设置为true,则将在next()返回后才发送文件
gzip提供.gz文件支持true
brotli提供.br文件支持true
setHeaders用户自定义响应头
extensions可设置文件扩展名字符串数组,当url没有扩展名时将从这里尝试false

下面是个简单的演示:

const Koa = require('koa');
const serve = require('koa-static');
const app = new Koa();

app.use(serve(__dirname + '/static/', { maxage: 600000 }));

app.listen(3000);

koa-static 是基于 koa-send 的,所以更多内容也可以参考 koa-send :https://github.com/koajs/send

缓存处理

当用户端请求资源时通常会在客户端本地或者网络节点中生成缓存,当客户端再起请求该资源是服务器可以通过一定的处理来判断资源是否更新,需要重新发送资源还是客户端可以使用缓存的资源。使用缓存可以减小网络带宽和服务器的压力。

在Koa中缓存处理比较热门的是使用 koa-conditional-getkoa-etag 两个中间件,两者结合使用。

koa-conditional-get 项目地址:https://github.com/koajs/conditional-get
使用 npm install koa-conditional-get 进行安装,当前版本为 3.0.0

koa-etag 项目地址:https://github.com/koajs/etag
使用 npm install koa-etag 进行安装,当前版本为 4.0.0

使用方法如下:

const conditional = require('koa-conditional-get');
const etag = require('koa-etag');

app.use(conditional());
app.use(etag());

下面是个简单的演示:

数据压缩

通常HTTP通讯中对于大块的数据会压缩有进行传输,以减小网络压力、节省浏览。Koa比较热门的中间件是 Koa Compress

项目地址:https://github.com/koajs/compress

使用 npm install koa-compress 进行安装,当前版本为 5.1.0 ,使用方法如下:

const compress = require('koa-compress');

app.use(compress({
    threshold: 2048, // 响应大于2048字节才压缩,默认为1024(1kb)
    br: false // 禁用br压缩方式,这样接下来会使用gzip
}));

下面是个简单的演示:

模板引擎

模板引擎是HTTP服务器中经常用到的功能,Koa中比较热门的中间件有下面两个:

koa-ejs 项目地址:https://github.com/koajs/ejs
koa-views 项目地址:https://github.com/queckezz/koa-views

认证与会话

身份认证与会话管理也是Web中常用的功能,这类技术方案很多,下面是一些使用比较多的技术中比较热门的中间件:

koa-jwt 项目地址:https://github.com/koajs/jwt
koa-basic-auth 项目地址:https://github.com/koajs/basic-auth
koa-session 项目地址:https://github.com/koajs/session
koa-passport 项目地址:https://github.com/rkusa/koa-passport

运行日志

koa-logger 这个中间件可以打印输出HTTP请求与响应相关信息。

项目地址:https://github.com/koajs/logger

使用 npm install koa-logger 进行安装,当前版本为 3.2.1 ,使用方法与演示如下:

const logger = require('koa-logger');

app.use(logger()); // 该中间件使用时通常放在最前面

总结

这篇文章介绍了Koa中间件查询使用的一些基础内容,并介绍了一些常用的中间件。有这些内容基本上就可以用来开发基本的HTTP服务器应用了。

以上是关于Koa异常处理说明的主要内容,如果未能解决你的问题,请参考以下文章

全栈项目|小书架|服务器开发-Koa2 全局异常处理

学习koa开发API--- 对异常和参数的处理

KOA学习笔记

异常处理常见异常说明

noexcept异常说明及其使用

160 01 Android 零基础入门 03 Java常用工具类01 Java异常 03 异常处理简介 01 异常处理分类