Solon v4.1.0

异常处理与排障

</> markdown
2026年9月14日 上午5:32:44

先判断调用失败发生在哪一层,再决定看哪里。Nami 源码的调用链大致是:

接口代理 → 解析上游 → 选择 Channel → 发请求 → Result → assertSuccess → Decoder

1、 常见异常类型

阶段常见现象首查内容
上游解析找不到服务实例、upstream 为 nullname、group、Discovery/LoadBalance
ChannelThere is no channel availableURL scheme、nami-channel-*
连接连接拒绝、连接超时服务是否启动、端口、网络、防火墙
响应NamiResponseExceptionHTTP 状态码、服务端路由和业务日志
解码NamiDecodeException 或字段转换失败Content-Type、coder/serialization、DTO
业务返回的异常被包装服务端异常堆栈、接口语义和幂等性

2、 处理 HTTP 错误

Result.assertSuccess() 在状态码 >= 400 时抛出 NamiResponseException。它包含状态码和响应描述:

import org.noear.nami.exception.NamiResponseException;

try {
    User user = userService.getById(1L);
} catch (NamiResponseException e) {
    int status = e.getCode();
    String description = e.getDescription();
    // 记录 status、description、接口和 traceId
}

响应体被读取为字符串后会被清理,排查时不要反复假设还能读取同一 body。连接、配置和通道问题通常是 NamiException 或带 cause 的包装异常,日志应保留完整异常链。

3、 固定 URL 优先排查

推荐严格按以下顺序恢复功能:

  1. 服务端是否以 Solon.start 启动,端口是否监听。
  2. 用固定 URL 调用,暂时去掉服务发现和 LoadBalance。
  3. 对照 @Mapping 检查完整路径、尾斜杠和 HTTP 方法。
  4. 检查请求参数:query、表单、@NamiBody/@Body 是否一致。
  5. 检查 http/https/tcp/ws 与已注册 channel 是否一致。
  6. 检查 Content-Type、Accept 以及双方编解码组件。
  7. 最后恢复发现、过滤器和自定义负载策略。

4、 一个实用的最小日志字段

traceId, service/group, resolved upstream, path, action, timeout, cost, status

不要记录 Token、Cookie、完整个人信息和大请求体。过滤器中可以统计耗时,但必须确保最终调用 inv.invoke()

Filter filter = inv -> {
    long start = System.currentTimeMillis();
    try {
        return inv.invoke();
    } finally {
        LOG.debug("url=" + inv.url + ", cost="
                + (System.currentTimeMillis() - start));
    }
};

5、 超时与重试

超时只说明客户端在期限内没有拿到结果,不代表服务端没有执行。对写操作盲目重试可能产生重复数据;重试前要有幂等键或明确的幂等设计。服务发现异常也不要通过无限重试掩盖配置错误。