springboot中的跨域问题

springboot中的跨域问题,如果不注意的话,容易造成错误,本次springboot版本为2.13  前端错误信息:

Access to XMLHttpRequest at 'http://localhost:8080/user/loginOn' from origin 'http://localhost:8082' 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.

第一种:是在每个Controller里,加上注解:@CrossOrigin

import javax.validation.Valid;
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController{

也可以在方法上加上,比如这样,这样针对具体的方法

  @CrossOrigin
    @ApiOperation(value = "用户登录",notes = "")
    @PostMapping("/loginOn")
    public ResponseMessage loginOn(@RequestBody @Valid UserReq userReq){

每一个Controller这样写也是很麻烦。

第二种:是实现WebMvcConfigurer接口,在接口中进行跨域支持

以前可以继承WebMvcConfigurerAdapter,springboot2.x版本已经将其@Deprecated

我们直接实现接口:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 跨域支持
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600 * 24);
    }

但使用这种方法,我今天遇到一个坑,我准备在拦截器里面对用户的请求进行拦截

@Component
public class RequestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       Object loginUser = request.getSession().getAttribute("token");
        if(loginUser == null){
        //自定义的异常类,这里抛出异常,交给全局异常捕捉类处理 throw new ServiceException("没有权限,请先登录!"); }else{ return true; }
} @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }

全局异常捕捉类:

@RestControllerAdvice
public class GlobleExceptionHandler {
    @ExceptionHandler(value = ServiceException.class)
    public ResponseMessage caughtException(ServiceException e){

        return new ResponseMessage(e.getMsg());
    }
}
ResponseMessage 是自定义的统一的响应信息类:
@Data
public class ResponseMessage {
    private Integer Code;
    private String msg;
    private Integer count;
    private Object data;

    public ResponseMessage(Object data) {
        this.data = data;
    }

    public ResponseMessage(String msg) {
        this.msg = msg;
    }

    public ResponseMessage(Integer code, String msg) {
        Code = code;
        this.msg = msg;
    }

    public ResponseMessage(Integer code, String msg, Integer count) {
        Code = code;
        this.msg = msg;
        this.count = count;
    }

    public ResponseMessage(Integer code, String msg, Integer count, Object data) {
        Code = code;
        this.msg = msg;
        this.count = count;
        this.data = data;
    }

    public static  ResponseMessage success(String msg){
        return new ResponseMessage(200,msg);
    }

    public static ResponseMessage fail(Integer code,String msg){
        return new ResponseMessage(code,msg);
    }
}
ResponseMessage

通过这样的处理发现,前端一直报跨域异常问题,这时候有了第三种方法

第三种:使用CorsFilter过滤器:

写一个MyCorsConfig 配置类

@Configuration
public class MyCorsConfig {

    @Bean
    public CorsFilter corsFilter() {

        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        //设置过滤器的顺序
        bean.setOrder(0);
        return new CorsFilter(source);
    }
}

最终解决本次demo的跨域问题。

第四种:采用springcloud  gateway实现跨域:

采用上述配置时,发现没有起作用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Configuration
public class MyCorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();

        //1、配置跨域
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);

        source.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsWebFilter(source);
    }
}

也可以采用yml的配置形式:

spring:
  cloud:
    gateway:
      # 跨域
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowedMethods:
            - GET
              POST
              DELETE
              PUT
              OPTION

官方配置参考:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#cors-configuration

可能出现报错:

The 'Access-Control-Allow-Origin' header contains multiple values 'http://lo“,but onl one is allowed

原因是gateway里设置了跨域,在调用的微服务里面也设置了跨域,设置了多个跨域,去掉微服务里面的即可。

原文地址:https://www.cnblogs.com/tdyang/p/12141816.html