这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战」
本文为 koa 依赖系列文章,前几篇也可以在站内查看:
- koa 中依赖的库 parseurl
- Koa 依赖的库 type-is 和 content-disposition
- Koa 依赖的库 accepts、content-type 和 cache-content-type
- Koa 依赖的库 encodeurl 和 escape-html
- Koa 中依赖的库 statuses
- Koa 依赖的库 cookies
- Koa 依赖的库 on-finished 和 destroy
调用 context 下 throw 方法时会抛出一个 HttpError,这个 HttpError 是通过 http-errors 提供的 createError 创建的,同时 Koa 也在内部转发导出了 HttpError 类型,我们可以直接使用。
HttpError 类型是通过调用 createHttpErrorConstructor 方法构造的,createHttpErrorConstructor 内部定义了一个抽象类 HttpError,这个类继承自 Error,需要使用 createError 创建 HttpError。
function createHttpErrorConstructor () {
function HttpError () {
throw new TypeError('cannot construct abstract class')
}
inherits(HttpError, Error)
return HttpError
}
复制代码
createError 的逻辑比较复杂,前面是一些列 arguments 的处理,处理的细节可以忽略,可以看到这里的比较重要的一个参数是 status,默认的状态码是 500,也可以通过参数传入其他状态码值,最终 constructor 是根据状态码来获取的:
var HttpError = createError[status] || createError[codeClass(status)]
复制代码
createError 上面的附加信息是通过 populateConstructorExports 构造的:
populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError)
复制代码
http 错误可以分为客户端错误和服务器错误两种,对应状态码为 4XX 和 5XX,因此这里会首先对传入的错误进行类型划分:
function codeClass (status) {
return Number(String(status).charAt(0) + '00')
}
switch (codeClass(code)) {
case 400:
CodeError = createClientErrorConstructor(HttpError, name, code)
break
case 500:
CodeError = createServerErrorConstructor(HttpError, name, code)
break
}
复制代码
这里客户端和服务端的错误创建的是两种不同类型,而对应的错误名会使用 statuses 库把状态码转化为字符串信息。
ClientError 和 ServerError 都是 Error,原型的修改是通过 setprototypeof 库来实现的,它的内部逻辑也比较简单:
'use strict'
/* eslint no-proto: 0 */
module.exports = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties)
function setProtoOf (obj, proto) {
obj.__proto__ = proto
return obj
}
function mixinProperties (obj, proto) {
for (var prop in proto) {
if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
obj[prop] = proto[prop]
}
}
return obj
}
复制代码
定义好类型后,error 数据信息是使用 Error.captureStackTrace 来设置的。
http-errors 的内部主要就是类型的定义逻辑,由于没有使用 class,因此在内部可以看到使用 js 函数进行集成构造等操作,有相关需要可以参考。errors 相关的内容就这么多,接下来看一下 assert 相关的逻辑。
context 上的 assert 方法是 http-assert 包提供的,这个包导出了 assert 函数,传入的内容不是 truthy 时抛出一个 http error,这个错误就是调用上面的 http-errors 中 createError 方法创建的:
function assert (value, status, msg, opts) {
if (value) return
throw createError(status, msg, opts)
}
复制代码
除了默认的 assert 函数,上面还导出了一系列辅助函数:fail、equal、notEqual、ok、strictEqual、notStrictEqual、deepEqual、notDeepEqual。这里可以从函数名看出来对应的功能,其中 ok 与默认导出的 assert 效果相同,fail 直接抛 error,三组 equal 的区别在于判断方式不同:
- equal & notEqual:使用
==
判断。 - strictEqual & notStrictEqual:使用
===
判断。 - deepEqual & notDeepEqual:调用 deep-equal 库判断,这是一个判断相等的库,可以对两个对象的内容进行递归比较。
以上就是 http-errors 和 http-assert 的全部内容了,这两部分在 koa 作为直接导出的 API,实际应用还是比较多的,尤其是在测试场景下。