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

Spring项目重新分包后访问S3出现No Access-Control-Allow-Origin错误如何解决

问题描述

我对Spring项目做了简单的重新分包操作后,访问S3云存储时出现了Access-Control-Allow-Origin相关CORS错误。
我搭建了本地S3兼容服务器存储视频,基于Spring框架直接从本地云端拉流播放视频,所有功能此前均运行正常。

原来所有类都放在com.example.video包下,包含如下类:

  • S3Config.java:存储AmazonS3Client相关配置
  • User.java:模型类
  • VideoController.java:简易控制器
  • VideoStreamingServiceApplication.java:项目启动类

之后我新建了com.example.s3包,将User.java和S3Config.java移动到该包下,一开始出现自动装配报错,我通过配置组件扫描解决了装配问题,但修复后拉流时出现如下报错:

Access to XMLHttpRequest at "http://localhost/9999/recordins/a.m3u8" from origin 'null' has been block by CORS policy: No 'Access-Control-Allow-Origin' header is present on the request resource .

我已经在接口返回中配置了对应的响应头,我的VideoController.java代码如下:

@RestController
@RequestMapping("/cloud")
@ConfigurationProperties(prefix = "amazon.credentials")
public class VideoCotroller {
    @Autowired
    private S3Config s3Client;
    private String bucketName= "recordings";
    Logger log = LoggerFactory.getLogger(VideoCotroller.class);
    @Autowired
    User userData;

@GetMapping(value = "/recordings/{fileName}", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
    public ResponseEntity<StreamingResponseBody> streamVideo(HttpServletRequest request, @PathVariable String fileName) {
        try {
            long rangeStart = 0;
            long rangeEnd;
            AmazonS3 s3client = s3Client.getAmazonS3Client();
            String uri = request.getRequestURI();
            System.out.println("Fetching " + uri);
            S3Object object = s3client.getObject("recordings", fileName);
            long size = object.getObjectMetadata().getContentLength();
            S3ObjectInputStream finalObject = object.getObjectContent();        
            final StreamingResponseBody body = outputStream -> {
                int numberOfBytesToWrite = 0;
                byte[] data = new byte[(int) size];
                while ((numberOfBytesToWrite = finalObject.read(data, 0, data.length)) != -1) {
                    outputStream.write(data, 0, numberOfBytesToWrite);
                }   
                finalObject.close();
            };
            
            rangeEnd = size - 1;
            return ResponseEntity.status(HttpStatus.OK)
                    .header("Content-Type", "application/vnd.apple.mpegurl")
                    .header("Accept-Ranges", "bytes")
// HERE IS THE ACCESS CONTROL ALLOW ORIGIN
                    .header("Access-Control-Allow-Origin", "*")
                    .header("Content-Length", String.valueOf(size))
                    .header("display", "staticcontent_sol, staticcontent_sol")
                    .header("Content-Range", "bytes" + " " + rangeStart + "-" + rangeEnd + "/" + size)
                    .body(body);
            //return new ResponseEntity<StreamingResponseBody>(body, HttpStatus.OK);
        } catch (Exception e) {
            System.err.println("Error "+ e.getMessage());
            return new ResponseEntity<StreamingResponseBody>(HttpStatus.BAD_REQUEST);
        }}

如果我将包结构恢复为原来的单包结构,所有功能又恢复正常。请问为什么重新分包会引发该CORS问题?有什么修复方案?


原因分析

该问题和你调整组件扫描的配置直接相关:

  1. Spring Boot默认只会扫描启动类所在包及其子包下的组件,你移动S3Config和User到新包后,为了修复装配问题新增的组件扫描配置,大概率只指定了com.example.s3,漏了原来的com.example.video包,导致你项目里原来配置的全局CORS过滤器、CORS配置类没有被Spring容器加载。
  2. 你虽然在Controller的GET接口里手动加了CORS响应头,但浏览器在发送实际GET请求前会先发OPTIONS预检请求,这个请求不会走到你写的GET接口逻辑里,自然不会携带CORS头,就会触发跨域报错。
  3. 恢复单包时启动类的默认扫描覆盖了所有组件,全局CORS配置生效,所以不会报错。
修复方案

方案1:调整组件扫描配置

在启动类的@ComponentScan注解里同时加入两个包,确保所有配置类都被加载:

@SpringBootApplication
@ComponentScan(basePackages = {"com.example.video", "com.example.s3"})
public class VideoStreamingServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(VideoStreamingServiceApplication.class, args);
    }
}

方案2:给当前Controller单独加跨域注解

如果不想修改全局扫描配置,直接在VideoController类上加@CrossOrigin注解即可让该类的所有接口自动支持跨域,包括OPTIONS预检请求:

@RestController
@RequestMapping("/cloud")
@CrossOrigin(origins = "*")
@ConfigurationProperties(prefix = "amazon.credentials")
public class VideoCotroller {
    // 原有代码保持不变
}

方案3:统一配置全局CORS规则

新增CORS配置类,放在确保会被扫描到的包下,一劳永逸解决所有接口的跨域问题:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 03:45:04