SpringBoot后端跨域问题
今天遇到一个问题,我访问同事电脑本地服务时浏览器报跨域错误,而且很奇怪的是 get请求不报错,但是post请求报错,看到跨域,开始挥三板斧
1.前端请求加上请求头:
devServer: { port: 8000, disableHostCheck: true, proxy: { '/ac-biz-auth/api': { target: 'http://localhost:8088', ws: false, changeOrigin: true } }, headers: { 'Access-Control-Allow-Origin': '*' } },
结果,不行
2.后端对应controller加上@CrossOrigin注解:
@Controller @CrossOrigin @RequestMapping("/" + AcStaticVarBizGwf.MODULE_CODE_AC_BIZ_GWF) public class AcBizGwfCtl extends BaseCtl { @Autowired private IAcBizGwfInfoService iPfBizRtFInfoService; @Autowired private AcBizGwfConfig acBizGwfConfig; // @PreAuth(value = "ac:core:biz:gwf:index", name = "网关引导首页") @GetMapping() public ModelAndView index(Model model) { model.addAttribute(AcStaticVarCoreModuleUi.PUBLIC_PTAH, acBizGwfConfig.publicPath()); model.addAttribute(AcStaticVarCoreModuleUi.ENABLE_HTTPS, acBizGwfConfig.getEnableHttps()); return new ModelAndView(AcStaticVarBizGwf.VIEW_AC_BIZ_GWF_INDEX); } // @PreAuth(value = "ac:core:biz:gwf:info", name = "获取子应用以及登录信息") @GetMapping("/info") @ResponseBody public AcBizGwfLoginInfoDto info() { return iPfBizRtFInfoService.getInfo(); } }
结果,不行
3.加上过滤器,统一处理响应:
@Configuration public class CorsConfig { private static final String MAX_AGE = "18000L"; @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (!CorsUtils.isCorsRequest(request)) { return chain.filter(ctx); } HttpHeaders requestHeaders = request.getHeaders(); ServerHttpResponse response = ctx.getResponse(); HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); if (requestMethod != null) { headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); } headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } return chain.filter(ctx); }; } }
此处标红的代码,实则是根据我们环境设置的,如果放过所有的请求,那么就设置为 “*” 即可
结果,也不生效,因为此处涉及一个大坑:此处这个过滤器我和@CrossOrigin一起用了,如果单独配置这个Filter,实则是可以的
最后,说明一下这次调试遇到的坑:
Springboot2.x之后,@CrossOrigin注解 的 allowCredentials 默认为 false ,即不支持带认证(令牌)的请求跨域,
正确配置:
@Controller @CrossOrigin(allowCredentials = "true") @RequestMapping("/" + AcStaticVarBizGwf.MODULE_CODE_AC_BIZ_GWF) public class AcBizGwfCtl extends BaseCtl { @Autowired private IAcBizGwfInfoService iPfBizRtFInfoService; @Autowired private AcBizGwfConfig acBizGwfConfig; // @PreAuth(value = "ac:core:biz:gwf:index", name = "网关引导首页") @GetMapping() public ModelAndView index(Model model) { model.addAttribute(AcStaticVarCoreModuleUi.PUBLIC_PTAH, acBizGwfConfig.publicPath()); model.addAttribute(AcStaticVarCoreModuleUi.ENABLE_HTTPS, acBizGwfConfig.getEnableHttps()); return new ModelAndView(AcStaticVarBizGwf.VIEW_AC_BIZ_GWF_INDEX); } // @PreAuth(value = "ac:core:biz:gwf:info", name = "获取子应用以及登录信息") @GetMapping("/info") @ResponseBody public AcBizGwfLoginInfoDto info() { return iPfBizRtFInfoService.getInfo(); } }
附上一个浏览器测试跨域demo,打开浏览器console控制台:
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://172.19.66.187:8095/rebook/ticketfastchange/queryDetails?id=37',true); xhr.setRequestHeader('content-type', 'application/json'); xhr.setRequestHeader('Authorization', 'Bearer 1a4d3a90-a15e-4200-98fe-e86f6067b3c6'); //将用户输入值序列化成字符串 xhr.send(); xhr.onload = function(e) { var xhr = e.target; console.log(xhr.responseText); }