Spring Boot接口跨域异常:调用Github API时Angular报CORS错误
我来帮你分析下这个问题哈!首先看现象:直接访问/getrepo接口没问题,但Angular调用就报CORS头不匹配的错,而/getuser却正常工作,这说明问题大概率出在两个接口的返回值处理上。
问题原因
你注意到两个接口的返回值差异了吗?getUser方法返回的是user.getBody()(也就是响应体内容),而getRepository方法返回的是整个ResponseEntity<Object>对象。当你返回ResponseEntity时,Spring Boot的@CrossOrigin注解可能没有正确给这个响应添加上Access-Control-Allow-Origin头,导致浏览器拿到的响应头中这个字段为null,触发了同源策略的报错。
解决方案
这里给你几个可行的修复方案:
1. 调整返回值为响应体(快速修复)
把getRepository方法的返回值改成和getUser一致,只返回响应体内容:
@CrossOrigin(origins = "http://localhost:4200") @RequestMapping(method = RequestMethod.GET, value = "/getrepo/{username}") public Object getRepository(@PathVariable String username) { restTemplate = new RestTemplate(); headers = new HttpHeaders(); headers.set("User-Agent", "profile-analyzer"); HttpEntity<String> entity = new HttpEntity<>("parameters", headers); ResponseEntity<Object> repository = restTemplate.exchange("https://api.github.com/users/"+ username + "/repos" + "?client_id=" + client_id + "&client_secret=" + client_secret, HttpMethod.GET, entity, Object.class); return repository.getBody(); // 修改这里,返回响应体 }
这样框架会统一处理响应,包括正确添加CORS的响应头,应该就能解决问题。
2. 配置全局CORS(更稳妥的长期方案)
单个接口加@CrossOrigin容易出现遗漏或处理差异,建议配置全局CORS规则,覆盖所有接口:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 对所有接口生效 .allowedOrigins("http://localhost:4200") // 允许的前端域名 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法 .allowedHeaders("*") // 允许所有请求头 .allowCredentials(true); // 如果前端需要携带Cookie,开启这个选项 } }
配置完成后,你可以去掉所有接口上的@CrossOrigin注解,所有接口的CORS处理会统一生效。
3. 优化返回值类型(可选)
getRepository用Object接收返回值不够规范,Github的仓库接口返回的是仓库对象数组,建议自定义Repository实体类来接收,或者用List<Map<String, Object>>作为返回类型,这样序列化更稳定,也能避免因返回类型问题间接影响响应头处理:
// 示例:用List<Map<String, Object>>接收 ResponseEntity<List<Map<String, Object>>> repository = restTemplate.exchange( "https://api.github.com/users/"+ username + "/repos?client_id=" + client_id + "&client_secret=" + client_secret, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Map<String, Object>>>() {} ); return repository.getBody();
验证
修改完成后重启Spring Boot服务,再用Angular调用/getrepo接口,应该就能正常获取数据了。
内容的提问来源于stack exchange,提问作者Dasun Pubudumal

