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

预检请求成功却返回404:Spring Rest Controller故障排查求助

问题描述

我正在开发搭配Angular客户端的Spring应用,新增了两个Rest Controller,其中一个正常工作,另一个(PriceConfigRestController)的所有端点均出现问题:调用时预检请求成功,但后续返回404错误。已确认请求URL正确,用Postman测试也得到相同的404响应。怀疑该Controller未被Spring扫描注册,但不知道如何验证,且两个新Controller目录结构一致,目前陷入困境。

附上该Controller代码:

@RestController
@Validated
public class PriceConfigRestController implements ApiRestController {

    public static final String URI_PRICECONFIG_BY_ID_INTERNAL = URI_PRICECONFIGS_INTERNAL + "{priceConfigId}";
    public static final String URI_DELETE_PRICECONFIG_BY_ID_INTERNAL = URI_PRICECONFIGS_INTERNAL + "{priceConfigId}";
    public static final String URI_PRICECONFIGS_BY_ORGANIZER_ID = URI_ORGANIZERS_INTERNAL + "{organizerId}/priceconfigs";

    private static final Logger LOGGER = LoggerFactory.getLogger(PriceConfigRestController.class);

    private final PriceConfigService priceConfigService;

    public PriceConfigRestController(PriceConfigService priceConfigService) {
        this.priceConfigService = priceConfigService;
    }

    @RequestMapping(value = URI_PRICECONFIGS_INTERNAL, method = RequestMethod.POST, consumes = APPLICATION_JSON)
    public ResponseEntity<PriceConfigDto> createPriceConfig(@RequestBody @Valid @NotNull PriceConfigDto priceConfigDto){
        PriceConfigDto resultDto = priceConfigService.createPriceConfig(priceConfigDto);
        LOGGER.debug("PriceConfig with ID : " + resultDto.getId() + " created: Response: " + HttpStatus.OK);
        return new ResponseEntity<>(priceConfigDto, HttpStatus.OK);
    }

    @RequestMapping(value = URI_DELETE_PRICECONFIG_BY_ID_INTERNAL, method = RequestMethod.DELETE)
    public ResponseEntity<Boolean> deletePriceConfigById(@PathVariable Long priceConfigId) throws ResourceNotFoundException {
        priceConfigService.deletePriceConfigById(priceConfigId);
        LOGGER.debug("Removed priceConfig with ID: " + priceConfigId + " Response: " + HttpStatus.OK);
        return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK);
    }

    @RequestMapping(value = URI_PRICECONFIG_BY_ID_INTERNAL, method = RequestMethod.GET)
    public ResponseEntity<PriceConfigDto> getPriceConfigById(@PathVariable Long priceConfigId) throws ResourceNotFoundException {
        PriceConfigDto priceConfigDto = priceConfigService.getPriceConfigById(priceConfigId);
        LOGGER.debug("PriceConfig ID: " + priceConfigId + " Response: " + HttpStatus.OK);
        return new ResponseEntity<>(priceConfigDto, HttpStatus.OK);
    }

    @RequestMapping(value = URI_PRICECONFIGS_BY_ORGANIZER_ID, method = RequestMethod.GET)
    public ResponseEntity<List<PriceConfigDto>> getPriceConfigsByOrganizerId(@PathVariable Long organizerId) {
        List<PriceConfigDto> priceConfigDtos = priceConfigService.getPriceConfigsByOrganizerId(organizerId);
        LOGGER.debug("PriceConfigsByOrganizerId ID: " + organizerId + " Response: " + HttpStatus.OK);
        return new ResponseEntity<>(priceConfigDtos, HttpStatus.OK);
    }

}
排查与解决步骤

一、验证Controller是否被Spring注册

  • 启用Spring Boot Actuator的beans端点:在application.properties中添加management.endpoints.web.exposure.include=beans,启动应用后访问/actuator/beans,搜索priceConfigRestController,能找到则说明已注册,否则未被扫描。
  • 添加构造方法日志:在PriceConfigRestController的构造方法中加入LOGGER.info("PriceConfigRestController initialized"),启动应用时查看日志是否有该输出,有则说明Controller已被实例化。
  • 检查扫描范围:确认启动类上的@SpringBootApplication或@ComponentScan注解的扫描路径包含该Controller所在包。若启动类与Controller不在同一父包下,需显式指定,比如@SpringBootApplication(scanBasePackages = {"com.your.project.package"})。

二、检查URI常量定义

代码中使用的URI_PRICECONFIGS_INTERNAL、URI_ORGANIZERS_INTERNAL未在当前代码中定义,需确认:

  • 常量是否以/开头?比如URI_PRICECONFIGS_INTERNAL若为priceconfigs而非/priceconfigs,拼接后的路径会缺少前缀斜杠,导致匹配失败。
  • 常量值是否存在拼写错误,或与其他Controller的路径冲突?

三、打印所有注册端点

添加配置类打印Spring已注册的所有端点,确认PriceConfigRestController的路径是否正确:

@Component
public class EndpointPrinter implements ApplicationListener<ApplicationReadyEvent> {

    private final RequestMappingHandlerMapping handlerMapping;

    public EndpointPrinter(RequestMappingHandlerMapping handlerMapping) {
        this.handlerMapping = handlerMapping;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        handlerMapping.getHandlerMethods().forEach((key, value) -> {
            System.out.println("Endpoint: " + key.getPatternsCondition() + " -> " + value.getBean());
        });
    }
}

启动应用后查看控制台输出,确认目标Controller的端点是否存在,以及路径是否与你请求的一致。

四、其他排查点

  • 检查拦截器/过滤器是否修改了请求路径,导致无法匹配到Controller。
  • 确认@Validated依赖是否完整:需引入spring-boot-starter-validation依赖,缺失可能导致Controller初始化失败。
  • 检查PriceConfigService是否正常注入:若该Service存在初始化异常,会导致Controller无法正常注册。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:54:51