Scala POST接口遇地址不存在时返回500而非预期404问题排查
问题分析与修复方案
根因判断
你的怀疑存在合理性,但需结合实际执行流分析:
可能的核心问题1:无效AddressResponse触发空指针
如果addressClient.getAddressById在404场景下意外解析出了无效的AddressResponse(比如后端404响应体结构恰好匹配AddressResponse字段),此时ensureAddressType会执行谓词_.properties.addressType === specificTypeId。若该AddressResponse的properties为null或未初始化,访问属性会抛出空指针异常,导致整个异步流失败,框架将其转化为500内部服务器错误。这完全符合你描述的现象:能命中谓词断点、无法进入domain赋值、无解析异常日志(因为解析本身成功了,只是数据无效)。
可能的核心问题2:错误处理链路异常
若addressClient正确返回Left(AddressClientError),EitherT.ensure不会执行谓词逻辑(仅Right分支才会触发)。此时返回500的原因可能是:
logErr方法内部失败(比如customLogger获取失败),导致leftSemiflatMap将EitherT转化为失败的F,而非正常的Left(ErrorResponseBody);AddressClientError.toErrorResponse未设置正确的HTTP状态码(比如默认返回500而非404)。
修复方案
方案1:加固ensureAddressType的参数校验
修改ensureAddressType,先校验AddressResponse的有效性,再判断地址类型,避免空指针:
情况A:properties是Option类型
def ensureAddressType: EitherT[F, MyError, AddressResponse] => EitherT[F, MyError, AddressResponse] = _.ensure(RequestValidationError("Invalid address type or missing properties."))( addr => addr.properties.exists(_.addressType === specificTypeId) )
情况B:properties是可空字段(非Option)
def ensureAddressType: EitherT[F, MyError, AddressResponse] => EitherT[F, MyError, AddressResponse] = _.flatMap { addr => if (addr.properties == null) { EitherT.leftT(RequestValidationError("Address properties are missing.")) } else if (addr.properties.addressType === specificTypeId) { EitherT.rightT(addr) } else { EitherT.leftT(RequestValidationError("Invalid address type.")) } }
方案2:修复错误处理链路
确保logErr稳定执行
修改logErr,捕获日志获取失败的异常,避免整个流中断:
def logErr[E <: MyError](error: E)(implicit pos: Position): F[MyError] = { customLogger.flatMap(logger => logger.error(s"${error.message} error-id: ${error.errorId}", error) .as(error) ).recoverWith { case logFailure => // 降级处理:打印控制台日志,保证流继续执行 Sync[F].delay(println(s"Failed to log error: $logFailure")).as(error) } }
修正错误响应的状态码
确保AddressClientError转换为ErrorResponseBody时返回404状态码:
// 假设ErrorResponseBody定义包含status字段 case class ErrorResponseBody(status: Int, message: String, errorId: UUID) // 在AddressClientError的toErrorResponse实现中: override def toErrorResponse(entityType: String): ErrorResponseBody = ErrorResponseBody(404, this.message, this.errorId)
验证步骤
- 临时在
createEntity中添加日志,打印addressClient.getAddressById(newEntity.addressId).value的结果,确认返回的是Left(AddressClientError)还是无效的Right(AddressResponse); - 查看404响应的具体内容,确认是否被意外解析为有效的
AddressResponse。
内容的提问来源于stack exchange,提问作者Laodao
相关产品推荐
相关产品推荐

