跨域问题解决方案

什么是跨域?

  • 浏览器为了用户的安全, 仅允许向同域名、同端口的服务器发送请求.
  • 比如:前端的域名是user, 后端域名是user-backend, 域名不一样就出现了跨域, 跨域的话就报错了

预检请求

  • 为了防止跨域, 或者说为了检测跨域, 浏览器它会在发送正式请求之前, 发送一个预检请求, 预检的请求方法是OPTIONS
  • 预检请求经常用来检查是否跨域, 或者换一句话说, 当我们请求的域名是和当前网页域名不同的时候, 就会发送预检请求
  • 预检请求的作用: 就是提前探路, 如果有问题, 那也不用发下一个请求了, 或者说下一个请求直接拒绝掉

如何解决跨域

  1. 把域名和端口改成相同的(不常用)

    • 在前后端分离的情况下, 域名和端口基本上无法同步, 所以不常用
  2. 网关支持(nginx)

    • 在nginx的配置文件中加入以下内容
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    location ^~ /api/ {
        proxy_pass http://127.0.0.1:8080/api/;
        add_header 'Access-Control-Allow-Origin' $http_origin;
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers '*';
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
    }
    
  3. 修改后端服务

    • (1) 在代码中添加@CrossOrigin注解, 用于处理跨域请求, 它允许来自"http://xxx.com"的请求访问资源, 并允许携带凭证(如cookies) image

    • ((2) 添加web全局清求拦截器(常用) image

    • (3) 返回新的CorsFilter

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    @Configuration
    public class CorsConfig {
        private CorsConfiguration buildConfig() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*");
            corsConfiguration.addAllowedHeader("*");
            corsConfiguration.addAllowedMethod("*");
            corsConfiguration.setMaxAge(3600L);
            corsConfiguration.setAllowCredentials(true);
            return corsConfiguration;
        }
    
        @Bean
        public CorsFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", buildConfig());
            return new CorsFilter(source);
        }
    }
    
    • (4) 手工设置响应头(HttpServletResponse)
    1
    2
    3
    4
    5
    6
    
    @RequestMapping("/test")
    @ResponseBody
    public String test(){
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
        return "success";
    }
    
使用 Hugo 构建
主题 StackJimmy 设计