ZIO HTTP 3中Endpoint接口的全局错误处理方案咨询
ZIO HTTP 3 通用Endpoint错误处理方案
下面提供三种实用的通用错误处理方案,避免每个Endpoint重复编写错误配置:
方案一:封装通用错误处理函数
写一个统一的函数,将业务逻辑返回的Task[A](即ZIO[Any, Throwable, A])转换成符合Endpoint要求的ZIO[Any, ZNothing, Response],集中处理所有通用错误:
import zio._ import zio.http._ import zio.json._ // 统一处理错误并转换为HTTP响应 def handleCommonErrors[R, A: JsonEncoder](zio: ZIO[R, Throwable, A]): ZIO[R, ZNothing, Response] = zio .map(data => Response.json(data.toJson)) // 统一序列化为JSON响应 .catchAll { case e: IllegalArgumentException => Response.badRequest(Json.obj("error" -> Json.string(e.getMessage))) case e: NoSuchElementException => Response.notFound(Json.obj("error" -> Json.string(e.getMessage))) case _ => Response.internalServerError(Json.obj("error" -> Json.string("服务器内部错误"))) }
使用时只需用该函数包裹业务逻辑:
val dataEndpoint = Endpoint.get("/api/data").out[String] dataEndpoint.implement { _ => handleCommonErrors(fetchData()) // fetchData: Task[String] 为业务方法 }
方案二:全局错误处理中间件
利用ZIO HTTP的Middleware机制,在路由层面添加全局错误捕获,所有Endpoint都会自动应用该处理逻辑:
import zio.http._ import zio.json._ // 定义全局错误处理中间件 val globalErrorMiddleware: Middleware[Any, Nothing, Any, Response, Any, Response] = Middleware.catchAll { case e: IllegalArgumentException => Response.badRequest(Json.obj("error" -> Json.string(e.getMessage))) case e: NoSuchElementException => Response.notFound(Json.obj("error" -> Json.string(e.getMessage))) case _ => Response.internalServerError(Json.obj("error" -> Json.string("服务器内部错误"))) } // 路由中应用中间件 val app = Routes( dataEndpoint.implement(_ => fetchData()), createEndpoint.implement(_ => createResource()) ).withMiddleware(globalErrorMiddleware)
这种方式无需修改单个Endpoint的实现,所有未被捕获的错误都会被中间件拦截并转换为对应HTTP响应。
方案三:自定义通用Endpoint模板
预先定义包含统一错误输出配置的Endpoint模板,业务Endpoint基于模板扩展,避免重复编写.outError:
import zio.http._ import zio.json._ // 定义通用API错误类型 sealed trait ApiError case class BadRequest(message: String) extends ApiError case class NotFound(message: String) extends ApiError case class ServerError(message: String) extends ApiError // 为错误类型提供JSON编码器 object ApiError { implicit val encoder: JsonEncoder[ApiError] = DeriveJsonEncoder.gen[ApiError] } // 定义通用Endpoint模板,预先配置错误输出 def baseEndpoint(method: Method, path: Path): Endpoint[Any, ApiError, Unit, String, Nothing] = Endpoint(method, path) .out[String] .outError( Status.BadRequest -> json[BadRequest], Status.NotFound -> json[NotFound], Status.InternalServerError -> json[ServerError] ) // 基于模板创建业务Endpoint val dataEndpoint = baseEndpoint(Method.GET, /"api"/"data") val createEndpoint = baseEndpoint(Method.POST, /"api"/"data") // 实现时只需将业务异常映射为ApiError dataEndpoint.implement { _ => fetchData() .mapError { case e: IllegalArgumentException => BadRequest(e.getMessage) case e: NoSuchElementException => NotFound(e.getMessage) case _ => ServerError("服务器内部错误") } }
该方案适合需要明确API错误契约的场景,让所有Endpoint的错误输出格式保持一致。
内容的提问来源于stack exchange,提问作者user22087954
相关产品推荐
相关产品推荐

