You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

验证步骤

  1. 临时在createEntity中添加日志,打印addressClient.getAddressById(newEntity.addressId).value的结果,确认返回的是Left(AddressClientError)还是无效的Right(AddressResponse);
  2. 查看404响应的具体内容,确认是否被意外解析为有效的AddressResponse。

内容的提问来源于stack exchange,提问作者Laodao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 19:42:20