zoukankan      html  css  js  c++  java
  • Vue.js学习(三)—— 分别从前后端Nginx解决SpringBoot+vue.js项目中的跨域问题

    一、什么是跨域

      (1)跨域

      由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一个与当前页面地址不同即为跨域。存在跨域的情况:

    网络协议不同,如http协议访问https协议。
    端口不同,如80端口访问8080端口。
    域名不同,如qianduanblog.com访问baidu.com。
    子域名不同,如abc.qianduanblog.com访问def.qianduanblog.com。
    域名和域名对应ip,如www.a.com访问20.205.28.90.

      (2)url格式

      一般格式:协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址

      示例:https://www.dustyblog.cn:8080/say/Hello 是由https + www + dustyblog.cn + 8080 + say/Hello组成。

      只要协议,子域名,主域名,端口号这四项组成部分中有一项不同,就可以认为是不同的域,不同的域之间互相访问资源,就被称之为跨域。

      (3)Cors

      CORS全称为Cross Origin Resource Sharing(跨域资源共享), 每一个页面需要返回一个名为Access-Control-Allow-Origin的http头来允许外域的站点访问,你可以仅仅暴露有限的资源和有限的外域站点访问。

      我们可以理解为:如果一个请求需要允许跨域访问,则需要在http头中设置Access-Control-Allow-Origin来决定需要允许哪些站点来访问。如假设需要允许https://www.dustyblog.c这个站点的请求跨域,则可以设置:

      Access-Control-Allow-Origin:https://www.dustyblog.cn。

    二、后端SpringBoot解决

      1、方案一:CORS局部配置-使用@CrossOrigin注解

      (1)在Controller上使用@CrossOrigin注解

      该类下的所有接口都可以通过跨域访问

    @RequestMapping("/demo2")
    @RestController
    //@CrossOrigin //所有域名均可访问该类下所有接口
    @CrossOrigin("https://blog.csdn.net") // 只有指定域名可以访问该类下所有接口
    public class CorsTest2Controller {
    
        @GetMapping("/sayHello")
        public String sayHello() {
            return "hello world --- 2";
        }
    }

      这里指定当前的CorsTest2Controller中所有的方法可以处理https://csdn.net域上的请求,其他域名不能请求

      (2)在方法上使用@CrossOrigin注解

    @RequestMapping("/preUser")
    @CrossOrigin("https://blog.csdn.net") 
    public Map<String,String> preUser(){
      Map
    <String,String> map = new HashMap<String,String>();
      map.put(
    "preUser","success");
      return map;
    }

      这里指定只有该方法可以处理https://csdn.net域上的请求,其他域名不能请求

      2、方案二:CORS局部配置-手工设置响应头(局部跨域)

    @RequestMapping("/hello")
    @ResponseBody
    public String index(HttpServletResponse response){
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
        return "Hello World";
    }
    Access-Control-Allow-Origin 表示允许哪些原始域进行跨域访问。
    Access-Control-Allow-Credentials表示是否允许客户端获取用户凭据。
    Access-Control-Allow-Methods 表示允许哪些跨域请求的提交方式。(例如GET/POST)
    Access-Control-Expose-Headers 表示允许暴露哪些头部信息给客户端。
    Access-Control-Max-Age 表示预检请求 [Preflight Request] 的最大缓存时间。

      3、方案三:CORS全局配置-实现WebMvcConfigurer(本人习惯用法)

      Spring Boot 2.0中已经废弃WebMvcConfigurerAdapter类, 开发人员可以通过实现WebMvcConfigurer接口实现相应的功能。

      新建跨域配置类:CorsConfig.java:
    /**
     * 跨域配置
     */
    @Configuration
    public class CorsConfig implements WebMvcConfigurer {
    
        @Bean
        public WebMvcConfigurer corsConfigurer()
        {
            return new WebMvcConfigurer() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**").
                            allowedOrigins("https://www.dustyblog.cn"). //允许跨域的域名,可以用*表示允许任何域名使用
                            allowedMethods("*"). //允许任何方法(post、get等)
                            allowedHeaders("*"). //允许任何请求头
                            allowCredentials(true). //带上cookie信息
                            exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
                }
            };
        }
    }

      4、方案四:CORS全局配置-使用Filter方式进行设置(过滤器实现)

      通过实现Fiter接口在请求中添加一些Header来解决跨域的问题,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。

    @Component
    public class CorsFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletResponse res = (HttpServletResponse) response;
            res.addHeader("Access-Control-Allow-Credentials", "true");
            res.addHeader("Access-Control-Allow-Origin", "*");
            res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
            res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
            if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
                response.getWriter().println("ok");
                return;
            }
            chain.doFilter(request, response);
        }
        @Override
        public void destroy() {
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }

      5、方案五:CORS全局配置-继承使用Spring Web中的CorsFilter

    package com.garyond.hurricane.config;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    
    import java.util.Arrays;
    
    /**
     *  跨域访问配置
     *
     *  @author Garyond
     */
    @Component
    public class CustomCorsFilter extends CorsFilter {
    
        public CustomCorsFilter() {
            super(configurationSource());
        }
    
        private static UrlBasedCorsConfigurationSource configurationSource() {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowCredentials(true);
            config.addAllowedOrigin("*");
            config.addAllowedHeader("*");
            config.setMaxAge(36000L);
            config.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"));
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/v1/**", config);
            return source;
        }
    }

      或者

    package com.ranxx.conf;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    
    /**
     * 跨域问题
     *
     * @author mousejoo
     */
    @Configuration
    public class CorsConfig {
        private CorsConfiguration buildConfig() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*"); // 1 允许任何域名使用
            corsConfiguration.addAllowedHeader("*"); // 2 允许任何头
            corsConfiguration.addAllowedMethod("*"); // 3 允许任何方法(post、get等)
            return corsConfiguration;
        }
    
        @Bean
        public CorsFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", buildConfig()); // 4
            return new CorsFilter(source);
        }
        
    
    }

      或者

    package com.example.longecological.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.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("content-type");
    
            //2.添加映射路径
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
    
            //3.返回新的CorsFilter.
            return new CorsFilter(configSource);
        }
    }

      

    三、前端Vue.js解决

      解决方案:采用proxyTable配置代理跨域

      (1)打开项目根目录下的config/index.js文件,参考以下proxyTable部分的配置:

    module.exports = {
      dev: {
        // Paths
        assetsSubDirectory: 'static',
        assetsPublicPath: '/',
        // *********代理跨域 主要代码**********
        proxyTable: {
          '/api': {  //匹配接口路径中的 /api,可以随意命名
            target: 'http://********:9001/api', //目标接口地址,设置调用的接口域名和端口号 别忘了加http、https
            changeOrigin: true, //是否跨域
            secure: true, // 允许https请求,https必须添加这个设置
            pathRewrite: {
              '^/api': '' // 路径重写 将 target 中的目标接口地址重写为 /api,这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
      } } }, }

      注意:每次修改配置文件需要重启服务才能生效:npm run dev

      (2)通过axios来实现发送访问

      在main.js中导入已安装好的axios,并挂载到原型上

    import Axios from 'axios'  //导入axios
    
    //将axios挂载到原型上
    Vue.prototype.$axios = Axios;

      (3)通过this.$axios.get().then()来实现数据请求

    //发送get请求
    show() {
          //用/api來代理'http://localhost:8083'
          this.$axios
            .get("/api/selectall")
            .then(res => {
              this.list = res.data.result;
              // }
            })
            .catch(e => {
              console.log(e);
            });
            },
    
    //发送post请求
    add() {
          this.$axios({
            method: "post",
            url: "/api/saveinfo",
            params: {
              name: this.name //传递的参数
            }
          }).then(res => {
                    this.show();
          });
        },

      注意:此种跨域解决方案,只能适用于测试阶段,因为项目打包发布之后,由于proxyTable不能再使用,所以无法跨域了。正式环境中,前端项目和后端项目放在一起就不存在跨域问题了。如果非要跨域,则可以采取上面的后端解决方法或者下面的Nginx替代前端的proxyTable代理功能。

    三、Nginx解决生产环境跨域问题

      1、安装好Nginx之后,打开安装目录下的conf/nginx.conf文件,参考以下server的简单配置:

    server {
            listen       9091;       #监听的端口
            server_name  localhost;  #服务器名称
    
            #charset koi8-r;
    
            #access_log  logs/host.access.log  main;
    
            location / {
                root   E:hld-workuniversitydist;  #项目物理路径
                index  index.html index.htm;         #项目的默认首页
            }   
            
            location /api {                                #检测并替换接口内的字符串
                proxy_pass http://**********:9001/api;   #跨域访问的目标URL
                proxy_set_header Host $host; 
                proxy_set_header X-Real-IP $remote_addr; 
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
                client_max_body_size 100m; 
            }
        }

      注:每次修改配置文件需要重启服务才能生效

      2、Nginx常用相关命令:

      需要在Nginx文件目录下运行命令行工具

      (1)启动

    start nginx 或 nginx.exe

      (2)停止

    nginx.exe -s stop 或 ginx.exe -s quit

      注:stop是快速停止nginx,可能并不保存相关信息;quit是完整有序的停止nginx,并保存相关信息。

      (3)重新载入

    nginx.exe -s reload

      (4)重新打开日志文件

    nginx.exe -s reopen

      (5)查看版本

    nginx -v

      

  • 相关阅读:
    重定义自定义类型
    范式
    管理
    JVM调优[转]
    I/O相关的等待事件
    等待事件监测性能瓶颈
    Shared pool
    SQL*Plus和PL/SQL
    Oracle优化器和执行计划
    10053事件
  • 原文地址:https://www.cnblogs.com/javahr/p/13280643.html
Copyright © 2011-2022 走看看