跨域

163 阅读2分钟

1、什么是跨域

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域

主要的表现形式:

跨域的原因 实例
域名不同 www.jd.com与www.taobao.com
域名相同,端口不同 www.jd.com:8080 与www.jd.com:8081
二级域名不同 item.jd.com与miaosha.jd.com

反例:

域名和端口都相同,但是路径不同

2、为什么有跨域问题

跨域问题是浏览器对于ajax请求的一种安全限制,一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。

因此,跨域是针对AJAX的一种限制

3、解决方案

  1. Jsonp

    1. 最早的解决方案,利用script标签可以跨域的原理实现

      1. 缺点

        1. 需要服务的限制
        2. 只能发送GET请求
  2. nginx反向代理

    1. 利用nginx反向代理把跨域为不跨域,支持各种请求方式

      1. 缺点:

        1. 需要nginx进行额外配置,语义不清晰
  3. CORS(跨域资源共享)

    1. 利用nginx反向代理把跨域为不跨域,支持各种请求方式

      1. 优势:

        1. 在服务端进行控制是否允许跨域,可自定义规则
        2. 支持各种请求
      2. 缺点:

        1. 会产生额外的请求

4、cors解决跨域问题

  • 浏览器端都有浏览器自动完成,我们无需操心
  • 服务端可以通过拦截器统一实现,不必每次都去进行跨域判定的编写

cors原理比较复杂,但是SpringMVC已经帮我们写好CORS的过滤器了 CorsFilter,

我们直接用就可以了,

方式一:

直接在controller,添加**@CrossOrigin**

方式二:

在网关配置:

@Configuration
public class GlobalCORSConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //1) 允许的域,不要写*,否则cookie就无法使用了
        config.addAllowedOrigin("http://manage.xxx.com");
        config.addAllowedOrigin("http://www.xxx.com");
        //2) 是否发送Cookie信息
        config.setAllowCredentials(true);
        //3) 允许的请求方式
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        // 4)允许的头信息
        config.addAllowedHeader("*");
        // 5)有效期 单位秒
        config.setMaxAge(3600L);
        //2.添加映射路径,我们拦截一切请求
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        //3.返回新的CORSFilter
        return new CorsFilter(configSource);
    }

优化:

1、把一些属性抽取application.yml

ly:
  cors:
    allowedOrigins:
      - http://manage.xxx.com
    allowedCredentials: true
    allowedHeaders:
      - "*"
    allowedMethods:
      - GET
      - POST
      - DELETE
      - PUT
      - OPTIONS
      - HEAD
    maxAge: 3600
    filterPath: "/**"

2、定义一个配置类,加载这些属性

@Data
@ConfigurationProperties(prefix = "ly.cors")
public class CORSProperties {
    private List<String> allowedOrigins;
    private Boolean allowedCredentials;
    private List<String> allowedMethods;
    private List<String> allowedHeaders;
    private Long maxAge;
    private String filterPath;

3、读取配置

@Configuration
@EnableConfigurationProperties(CORSProperties.class)
public class GlobalCORSConfig {
    @Bean
    public CorsFilter corsFilter(CORSProperties prop) {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //1) 允许的域,不要写*,否则cookie就无法使用了
        prop.getAllowedOrigins().forEach(config::addAllowedOrigin);
        //2) 是否发送Cookie信息
        config.setAllowCredentials(prop.getAllowCredentials());
        //3) 允许的请求方式
        prop.getAllowedMethods().forEach(config::addAllowedMethod);
        // 4)允许的头信息
        prop.getAllowedHeaders().forEach(config::addAllowedHeader);
        // 5)配置有效期 单位秒
        config.setMaxAge(prop.getMaxAge());
        //2.添加映射路径,我们拦截一切请求
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration(prop.getFilterPath(), config);
        //3.返回新的CORSFilter.
        return new CorsFilter(configSource);
    }
}