React+Spring Boot跨域问题:GET请求浏览器报错但Postman正常
问题分析与解决:React前端调用Spring Boot后端的CORS问题
问题背景
React前端(http://localhost:8081)向Spring Boot后端接口http://localhost:8080/api/projects/admin/toinspection发送GET请求时触发CORS报错,Postman中请求正常,但浏览器报错:
Access to XMLHttpRequest at 'http://localhost:8080/api/projects/admin/toinspection' from origin 'http://localhost:8081' has been blocked by CORS policy: The response to the preflight request doesn't pass the access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
相关代码片段
React前端代码(ProjectPage.tsx)
const ProjectsPage = () => { const [projectsData, setProjectsData] = useState<ProjectsData[]>([]) const projectsUrl = 'http://localhost:8080/api/projects/admin/toinspection' useEffect(() => { fetchData().then(r => console.log(r)) }, []); const fetchData = async() => { const token = Cookies.get('token') const response = await axios.get<ProjectsData[]>(projectsUrl, { headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, withCredentials: true }) setProjectsData(response.data) } return ( <div> <AdminPageTemplate type="projects" children={<AdminModContent data={projectsData}/>}/> </div> ); }; export default ProjectsPage;
React组件代码(AdminModContent.tsx)
const AdminModContent: React.FC<ModeratorContentProps> = ({ data }) => { if (!data || data.length === 0) { return ( <div className={styles.adminModContact__empty}> No content to moderate </div> ); } const renderContent = (item: ContentItem) => { if (!item) return null; switch (item.type) { case "projects": return ( <div key={item.id} className={styles.adminModContact__projects}> <p>ID: {item.id}</p> <h3>Project: {item.title}</h3> <p>Tech Stack: {item.technologyStack}</p> <p>Description: {item.mainText}</p> <p>Wishes: {item.wishes}</p> <div className={styles.adminModContact__actions}> </div> </div> ); }; return ( <div className={styles.adminModContact}> {data.map(item => renderContent(item))} </div> ); }; export default AdminModContent;
Spring Boot CORS配置(CorsConfig.java)
@Bean public WebMvcConfigurer getWebMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:8081") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true); } }; }
问题原因及解决思路
- 预检请求未被正确处理:浏览器发送的OPTIONS预检请求可能被自定义拦截器(如登录校验拦截器)优先拦截,导致响应未携带CORS头。
- CORS配置未生效:检查
CorsConfig类是否添加了@Configuration注解,没有的话Spring不会加载该配置。 - 不必要的请求头触发预检:GET请求无需设置
Content-Type: application/json,这个自定义头会触发预检请求,若后端未正确处理则报错。 - 配置优先级问题:
WebMvcConfigurer的CORS配置优先级低于过滤器,若存在其他过滤器可能导致配置不生效。
具体解决方案
- 确保配置类被Spring扫描:给
CorsConfig添加@Configuration注解,让Spring识别为配置类。 - 调整Axios请求头:移除GET请求中的
Content-Type头,避免触发不必要的预检:const response = await axios.get<ProjectsData[]>(projectsUrl, { headers: { Authorization: `Bearer ${token}`, }, withCredentials: true }) - 改用CorsFilter提升优先级:替换原
WebMvcConfigurer配置为CorsFilter,确保CORS处理优先于其他拦截器:@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Collections.singletonList("http://localhost:8081")); config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(Collections.singletonList("*")); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } } - 验证预检请求响应:在浏览器开发者工具Network标签中查看OPTIONS请求的响应头,确认是否包含
Access-Control-Allow-Origin等CORS相关字段,排查配置是否生效。
内容的提问来源于stack exchange,提问作者fpbidni
相关产品推荐
相关产品推荐

