Handle Exceptions and Customize Status Pages

预计阅读时间:4分钟

StatusPages功能使Ktor应用程序可以对任何故障状态做出适当的响应. 使用标准应用程序配置安装此功能:

fun Application.main() {
    install(StatusPages)
}

StatusPages提供了三个主要配置选项:

  1. exceptions -根据映射的例外类配置响应
  2. status配置对状态码值的响应
  3. statusFile配置来自类路径的标准文件响应
此功能在io.ktor.features.StatusPages类中定义,并且不需要其他构件.

目录:

Exceptions

异常配置可以为导致抛出异常的调用提供简单的拦截模式. 在最基本的情况下,可以为任何异常配置500 HTTP状态代码.

install(StatusPages) {
    exception<Throwable> { cause ->
        call.respond(HttpStatusCode.InternalServerError)
    }
}

更具体的响应可以允许更复杂的用户交互.

install(StatusPages) {
    exception<AuthenticationException> { cause ->
        call.respond(HttpStatusCode.Unauthorized)
    }
    exception<AuthorizationException> { cause ->
        call.respond(HttpStatusCode.Forbidden)
    }
}

当与自定义状态代码响应配对时,这些自定义可以很好地工作,例如,在用户未通过身份验证时提供登录页面.

每个调用仅由单个异常处理程序捕获,该异常处理程序是对象图上与抛出的异常最接近的异常. 当处理同一对象层次结构中的多个异常时,将仅执行一个.

install(StatusPages) {
    exception<IllegalStateException> { cause ->
        fail("will not reach here")
    }
    exception<ClosedFileSystemException> {
        throw IllegalStateException()
    }
}
intercept(ApplicationCallPipeline.Fallback) {
    throw ClosedFileSystemException()
}

单一处理还意味着避免了递归调用堆栈. 例如,此配置将导致创建的IllegalStateException传播到客户端.

install(StatusPages) {
    exception<IllegalStateException> { cause ->
        throw IllegalStateException("")
    }
}

Logging Exceptions

重要的是要注意,添加上面的处理程序将"吞噬"由路由生成的异常. 为了记录实际生成的错误,您可以手动记录cause ,也可以简单地将其重新抛出,如下所示:

install(StatusPages) {
    exception<Throwable> { cause ->
        call.respond(HttpStatusCode.InternalServerError, "Internal Server Error")
        throw cause
    }
}

Status

status配置为应用程序中的状态响应提供了自定义操作. 以下是一个基本配置,该配置在响应文本中提供有关HTTP状态代码的信息.

install(StatusPages) {
    status(HttpStatusCode.NotFound) {
        call.respond(TextContent("${it.value} ${it.description}", ContentType.Text.Plain.withCharset(Charsets.UTF_8), it))
    }
}

StatusFile

status配置在响应对象上提供可自定义的操作时,更常见的解决方案是提供错误HTML页面,供访问者在错误或授权失败时看到. statusFile配置提供了这种类型的功能.

install(StatusPages) {
    statusFile(HttpStatusCode.NotFound, HttpStatusCode.Unauthorized, filePattern = "error#.html")
}

这将从类路径解析两个资源.

  1. 在404上,它将返回error404.html.
  2. 在401上,它将返回error401.html.

statusFile配置将已配置状态列表中的任何#字符替换为状态代码的值.

Redirections using StatusPages

通过执行call.respondRedirect("/moved/here", permanent = true)进行重定向时,将执行其余的被调用函数. 因此,在保护子句中进行重定向时,您必须返回该函数.

routing {
    get("/") {
        if (condition) {
            return@get call.respondRedirect("/invalid", permanent = false)
        }
        call.respondText("Normal response")
    }
}

其他框架在重定向上使用异常,因此正常流程会中断,您可以在保护子句或子函数中执行重定向,而不必担心返回所有子函数链. 您可以使用StatusPages功能对此进行模拟:

fun Application.module() {
    install(StatusPages) {
        exception<HttpRedirectException> { e ->
            call.respondRedirect(e.location, permanent = e.permanent)
        }
    }
    routing {
        get("/") {
            if (condition) {
                redirect("/invalid", permanent = false)
            }
            call.respondText("Normal response")
        }
    }
}

class HttpRedirectException(val location: String, val permanent: Boolean = false) : RuntimeException()
fun redirect(location: String, permanent: Boolean = false): Nothing = throw HttpRedirectException(location, permanent)

异常重定向示例中有一个更高级的示例显示了这一点.

by  ICOPY.SITE