Vue.js学习—— 分别从前后端Nginx解决SpringBoot+vue.js项目中的跨域问题

Posted 沧海一粟11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

  

 

以上是关于Vue.js学习—— 分别从前后端Nginx解决SpringBoot+vue.js项目中的跨域问题的主要内容,如果未能解决你的问题,请参考以下文章

Nest+Vue实战:工作计划管理系统

Heroku 部署混乱:Vue.js 前端与 Flask 后端

vue.js的“Firebase + Validation Example”中如何使用mysql作为数据持久化后端?

Vue.js 3 s-s-r - 客户端水合期间缺少模板或渲染功能

Vue.js+Node.js全栈开发入门实战 | 推荐

vue.js 源代码学习笔记 ----- codegenEvents.js