跨域问题与解决办法

83 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制,初衷是为了保证用户的安全,防止恶意网站窃取数据。但这个保护机制导致不同站点之间的正常调用带来了了阻碍。

跨域三种情况

  1. 协议不同,如 http 和 https;
  2. 域名不同
  3. 端口不同

解决跨域问题

使用 @CrossOrigin 注解

@CrossOrigin 既可以修饰类,也可以修饰方法。当修饰类时,表示此类中的所有接口都可以跨域;当修饰方法时,表示该方法可以跨域。

@CrossOrigin(origins = "*")
public class ShipQueryController {
​
    @CrossOrigin(origins = "*")
    public void searchShips(@RequestBody TestDemo shipEntity){
    
    }
}

使用配置文件

创建配置文件,实现 WebMvcConfigurer 接口,重写addCorsMappings 方法,设置允许跨域的代码

@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    // 设置允许跨域的路径
    registry.addMapping("/**")
        // 设置允许跨域请求的域名
        .allowedOrigins("*")
        // 是否允许证书
        .allowCredentials(true)
        // 设置允许的方法
        .allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "OPTIONS")
        // 设置允许的header属性
        .allowedHeaders("*")
        // 跨域允许时间
        .maxAge(3600);
  }
}

使用 CorsFilter 对象

@Configuration // 一定不能忽略此注解
public class MyCorsFilter {
    @Bean
    public CorsFilter corsFilter() {
        // 1.创建 CORS 配置对象
        CorsConfiguration config = new CorsConfiguration();
        // 支持域
        config.addAllowedOriginPattern("*");
        // 是否发送 Cookie
        config.setAllowCredentials(true);
        // 支持请求方式
        config.addAllowedMethod("*");
        // 允许的原始请求头部信息
        config.addAllowedHeader("*");
        // 暴露的头部信息
        config.addExposedHeader("*");
        // 2.添加地址映射
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", config);
        // 3.返回 CorsFilter 对象
        return new CorsFilter(corsConfigurationSource);
    }
}

使用 Response 对象

通过对 HttpServletResponse 进行设置 Header 来实现跨域

public void searchShips(@RequestBody HttpServletResponse response){
        response.setHeader("Access-Control-Allow-Origin", "*");
    }

实现 ResponseBodyAdvice

通过重写 ResponseBodyAdvice 接口中的 beforeBodyWrite(返回之前重写)方法,我们可以对所有的接口进行跨域设置

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 设置跨域
        response.getHeaders().set("Access-Control-Allow-Origin", "*");
        return body;
    }
}

原理分析

跨域本质是浏览器行为,初衷是保证用户的访问安全,防止恶意网站窃取数据。那解决跨域只需要告诉浏览器这是一个安全的请求。

只需要在返回头中设置 “Access-Control-Allow-Origin”即可解决,此参数就是用来表示允许跨域访问的原始域名,当设置为“*” 时,表示允许所有站点跨域访问。

所以以上 5 种解决跨域问题的本质都是给响应头中加了一个 Access-Control-Allow-Origin 的响应头而已。