• 解决跨域问题大集合:vue-cli项目 和 java/springboot(6种方式) 两端解决(完美解决)


    导言

    一、跨域问题描述

    1. 跨域报错信息

    Access to XMLHttpRequest at ‘http://localhost:8087/api/user/list’ from origin ‘http://localhost:8081’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
    在这里插入图片描述

    2. 什么是跨域

    简单一句话概况:当一个请求 url 的协议、域名、端口三者之间任意一个与当前页面 url 不同即为跨域

    还不懂这个概念就找度娘吧,在这个博文里解释概念不是重点哈。

    一、vue-cli配置代理

    配置proxy来支持跨域,向后台请求登陆和数据,在Vue.config.js 配置文件中配置代理

    方法一和方法二配置了也有可能不生效,还是爆跨越错误,请看第三点

    1. 方法一

    这个方法是有缺点的,只能配置一个。推荐使用方法二

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
      lintOnSave: false,                        	// 关闭 ESlint
      devServer: {
      	proxy: 'http://localhost:8888'
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2. 方法二

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
      lintOnSave: false,                        	// 关闭 ESlint
      devServer: {
        // https: true,                             // 开启 https 模式
        proxy: {                                	// 配置服务器代理
          '/api': {                             	// 匹配访问路径中含有 '/api' 的路径
            target: 'http://localhost:8087/api/',   // 测试地址、目标地址
            pathRewrite: {                      	// 匹配所有的以/api开头的换成 ''
              '^/api':'' 							// 这边如果为空的话,那么发送到后端的请求是没有/api这个前缀的, 所以我在target 后面加上了 /api/
            }, 
            ws: true,                           	// 用于支持websocket
            changeOrigin: true,                 	// 伪装同源
          }
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3. 注意的点(很重要)

    a、axios 的 baseURL配置

    我们在配置axios的全局地址baseURL时,一般是这样配置的:

    const http = axios.create({
      baseURL: 'http://localhost:8087/',
    })
    
    • 1
    • 2
    • 3

    还有可能不是这样直接配置的,而且先定义的变量,通过其他配置在取这个baseURL,但是这个一定是会配置的,我一般是定义下面的这个变量的,方便管理

    // 判断当前的运行环境, 如果是开发,则取开发地址 否则 取生产地址 
    let  baseUrl = '/'
    if (process.env.NODE_ENV === 'development') {
      baseURL = 'http://localhost:8087/api/';
    } else { // production 生产环境
      baseURL = '/';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    b、解决问题

    所以不论是 生产 还是 开发 环境下,我的请求都会发送给我们配置的baseURL而不会走我们的代理!!!

    所以我们得修改一下配置,使我们的生产路径在开大环境下才生效

    let  baseUrl = '/'
    if (process.env.NODE_ENV === 'development') {
      baseURL = '/';
    } else { // production 生产环境
      baseURL = '/';
    }
    
    const http = axios.create({
      baseURL,
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这样在开发环境下,我们的 baseURL = "/" , 代理就可以生效了。

    注意

    二、后端解决跨域问题

    借鉴博文SpringBoot解决跨域的5种方式

    1. JAVA解决CORS跨域请求的几种方式

    对于 CORS的跨域请求,主要有以下几种方式可供选择:

    1. 返回新的CorsFilter(全局跨域)
    2. 重写 WebMvcConfigurer(全局跨域)
    3. 使用注解 @CrossOrigin(局部跨域)
    4. 手动设置响应头 (HttpServletResponse) (局部跨域)
    5. 自定web filter 过滤器 实现跨域 (全局跨域)
    6. 自定义 springboot interceptor 拦截器 实现跨域 (全局跨域)

    注意:

    1. CorFilter / WebMvConfigurer / @CrossOrigin 需要 SpringMVC 4.2以上版本才支持,对应springBoot 1.3版本以上
    2. 上面前两种方式属于全局 CORS 配置,后两种属于局部 CORS配置。如果使用了局部跨域是会覆盖全局跨域的规则,所以可以通过 @CrossOrigin 注解来进行细粒度更高的跨域资源控制。
    3. 其实无论哪种方案,最终目的都是修改响应头,向响应头中添加浏览器所要求的数据,进而实现跨域

    2. 返回新的CorsFilter(全局跨域)

    @Configuration
    public class GlobalCorsConfig {
     
        @Bean
        public CorsFilter corsFilter() {
            //1. 添加 CORS配置信息
            CorsConfiguration config = new CorsConfiguration();
            //放行哪些原始域
            config.addAllowedOrigin("*");
            //是否发送 Cookie
            config.setAllowCredentials(true);
            //放行哪些请求方式
            config.addAllowedMethod("*");
            //放行哪些原始请求头部信息
            config.addAllowedHeader("*");
            //暴露哪些头部信息
            config.addExposedHeader("*");
            //2. 添加映射路径
            UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
            corsConfigurationSource.registerCorsConfiguration("/**",config);
            //3. 返回新的CorsFilter
            return new CorsFilter(corsConfigurationSource);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3. 重写 WebMvcConfigurer(全局跨域)

    // 案例 一
    @Configuration
    public class CorsConfig implements WebMvcConfigurer {
     
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    //是否发送Cookie
                    .allowCredentials(true)
                    //放行哪些原始域
                    .allowedOrigins("*")
                    .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                    .allowedHeaders("*")
                    .exposedHeaders("*");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    // 案例 二 ,同上
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
     
     
    @Configuration
    public class AccessControlAllowOriginFilter implements WebMvcConfigurer {
     
        @Override
        public void addCorsMappings(CorsRegistry registry){
            registry.addMapping("/*/**")
                    .allowedHeaders("*")
                    .allowedMethods("*")
                    .maxAge(1800)
                    .allowedOrigins("*");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4. @CrossOrigin 注解(局部跨域)

    在控制器(类上)上使用注解 @CrossOrigin:,表示该类的所有方法允许跨域。

    @RestController
    @CrossOrigin(origins = "*")
    public class HelloController {
     
        @RequestMapping("/hello")
        public String hello() {
            return "hello world";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在方法上使用注解 @CrossOrigin:

      @RequestMapping("/hello")
      @CrossOrigin(origins = "*")
       //@CrossOrigin(value = "http://localhost:8081") //指定具体ip允许跨域
      public String hello() {
            return "hello world";
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5. 手动设置响应头 (HttpServletResponse) (局部跨域)

    使用 HttpServletResponse 对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里 Origin的值也可以设置为 “*”,表示全部放行。

    @RequestMapping("/index")
    public String index(HttpServletResponse response) {
     
        response.addHeader("Access-Allow-Control-Origin","*");
        return "index";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6. 自定web filter 过滤器 实现跨域 (全局跨域)

    首先编写一个过滤器,可以起名字为MyCorsFilter.java

    package cn.wideth.aop;
     
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.stereotype.Component;
     
    @Component
    public class MyCorsFilter implements Filter {
     
      public void doFilter(ServletRequest req, ServletResponse res, 
      FilterChain chain) throws IOException, ServletException {
      
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
        chain.doFilter(req, res);
        
      }
      
      public void init(FilterConfig filterConfig) {}
      public void destroy() {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    7. 自定义 springboot interceptor 拦截器 实现跨域 (全局跨域)

    先写拦截器MyInterceptor.java的实现类

    package com.feng.springboot_interceptor.interceptor;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpServletResponse response = (HttpServletResponse) res;
    	    response.setHeader("Access-Control-Allow-Origin", "*");
    	    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    	    response.setHeader("Access-Control-Max-Age", "3600");
    	    response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("MyInterceptor...请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
            //HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("MyInterceptor....在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对 应的视图之后执行(主要是用于进行资源清理工作)");
            //HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在写WebAppConfig.java,重写 WebMvcConfigurer.java 类,将拦截器注入(我这里写的是对请求的过滤,可以忽略掉)

    package com.feng.springboot_interceptor.config;
    
    import com.feng.springboot_interceptor.interceptor.MyInterceptor;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebAppConfig implements WebMvcConfigurer {
        @Value("${open.url}")
        private String openUrl;
    
        @Bean
        public MyInterceptor getMyInterceptor() {
            return new MyInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 拦截以 /api 开头的请求,但是排除  openUrl:/**/open/**。 即 :匹配这个(/**/open/**)URL的所有请求不拦截
            registry.addInterceptor(getMyInterceptor()).addPathPatterns("/api/**").excludePathPatterns(openUrl);
            // WebMvcConfigurer.super.addInterceptors(registry);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    vivo 消息中间件测试环境项目多版本实践
    Vue3中rem适配方案 淘宝flexible在PC端适配
    Zotero(1)---文献管理软件Zotero安装教程
    windows 各种inject/hook学习材料(自用)
    SQL关于日期的计算合集
    (三)Linux 用户和权限
    gitLab批量下载有权限的项目
    BYD精制项目除铜工艺去除铜离子
    Error: 0x800701bc WSL 2 ?????????????????? https://aka.ms/wsl2kernel
    Win10电脑需要安装杀毒软件吗?
  • 原文地址:https://blog.csdn.net/qq_40036754/article/details/126338337