Angular调用Spring Web Service遭遇CORS跨域问题求助
我开发了一个基于TypeScript的Angular应用,调用Java Spring Web Service时遇到CORS跨域问题。首次请求能从服务器获取access token,但后续所有请求都被拒绝,报错信息如下:
Access to XMLHttpRequest at X from origin Y has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
其中X是请求的资源URL,Y是请求源。Postman测试接口能正常返回JSON,但Angular端请求失败。
API网关模块代码
package it.sitgeo.apigateway.controller; import it.sitgeo.apigateway.exception.LoginException; import it.sitgeo.apigateway.model.AppUser; import it.sitgeo.apigateway.model.LoginForm; import it.sitgeo.apigateway.service.AppUserService; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @RestController @RequestMapping("/sitgeo") @RequiredArgsConstructor @CrossOrigin(allowedHeaders = "*") public class AppUserController { private final AppUserService service; @PostMapping(path = "/login", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) public ResponseEntity<String> login (@Valid @ModelAttribute LoginForm loginForm) throws LoginException { String access_token = service.login(loginForm.getUsername(), loginForm.getPassword()); if(access_token == null){ throw new LoginException("Le credenziali inserite non sono corrette"); } return ResponseEntity.ok(access_token); } }
PED模块控制器代码
package it.sitgeo.ped.Controllers; import it.sitgeo.ped.Entities.*; import it.sitgeo.ped.Repositories.*; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.mail.MessagingException; import java.io.IOException; @Slf4j @RestController @RequestMapping("/sitgeo/PED") @AllArgsConstructor @CrossOrigin(origins = {"http://localhost","Y"} ,allowedHeaders = "*") public class PEDController { final EmailConfiguration emailConfiguration; private final PraticaRepository praticaRepository; private final ComuneRepository comuneRepository; private final TitolareRepository titolareRepository; private final PdfRepository pdfRepository; private final ProcuratoreRepository procuratoreRepository; private final DomicilioElettronicoRepository domicilioElettronicoRepository; private final LocalizzazioneRepository localizzazioneRepository; private final CatastoRepository catastoRepository; private final TecnicoRepository tecnicoRepository; private final SoggettiTitolariRepository soggettiTitolariRepository; private final StatoUnitaRepository statoUnitaRepository; private final TipologiaRepository tipologiaRepository; //@CrossOrigin(origins = "http://localhost:4200") @GetMapping("/getCOMUNI/{provincia}") public ResponseEntity<?> getComuni(@PathVariable String provincia) { log.info("getCOMUNI {}", provincia); ResponseEntity<?> response; try { response = new ResponseEntity<String[]>(comuneRepository.searchComuneByProvincia(provincia), HttpStatus.OK); } catch (Exception e) { response = new ResponseEntity<String[]>(HttpStatus.BAD_REQUEST); } System.out.println(response.getBody()); return response; } }
PED模块CORS配置代码
package it.sitgeo.ped.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CORSConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("Y", "http://localhost") .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD","OPTIONS") .allowedHeaders("*"); } }
解决步骤
统一CORS配置规则
同时使用控制器级别的@CrossOrigin和全局CORSConfig会导致规则冲突,建议移除所有控制器上的@CrossOrigin注解,仅保留全局配置,确保所有接口遵循统一规则。补全请求源端口
Angular默认运行在http://localhost:4200,全局配置里的allowedOrigins需要添加完整的源地址(包含端口),同时开启凭证支持(如果请求携带token或cookie):registry.addMapping("/**") .allowedOrigins("Y", "http://localhost:4200") .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD","OPTIONS") .allowedHeaders("*") .allowCredentials(true);放行预检OPTIONS请求
如果项目中使用Spring Security或自定义拦截器,需确保OPTIONS请求不被权限校验拦截,可添加规则直接放行所有OPTIONS请求。Angular端请求配置
若请求携带token(如放在Authorization头),需在HTTP请求中设置withCredentials为true:this.http.get('请求URL', { withCredentials: true }) .subscribe(response => { /* 处理响应逻辑 */ });同步API网关配置
API网关模块的@CrossOrigin未指定origins,建议移除该注解,和全局配置保持一致,避免跨域规则不一致。
内容的提问来源于stack exchange,提问作者Alessia

