SpringBoot + VUE2 前后端分离项目 [开发环境]/[生产环境] 请求发生跨域问题的处理

2 篇文章 0 订阅

一、项目技术栈

SpringBoot  +  VUE2

二、服务器容器

Tomcat8 + Nginx

三、议题

浏览器同源策略的影响 不同协议、不同主机[ IP、域名 ]、不同端口  间通信会发生跨域


四、事件场景

1、生产环境:

前后端项目处于同一局域网下的内网环境中的不同主机及端口下

2、生产环境:

前后端项目处于同一物理服务器下的不同web容器下:

  • SpringBoot项目处于Tomcat容器下;
  • VUE项目处于Nginx容器下。

五、跨域问题的解决

1、生产环境:

SpringBoot项目

后端解决的原理就是在请求的响应头内添加若干允许请求通过跨域检查的属性:

@Configuration
public class ResourcesConfig implements WebMvcConfigurer{

    /**
     * 跨域配置
     */
    @Bean
    public CorsFilter corsFilter()
    {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // 设置访问源地址
        config.addAllowedOrigin("*");  // 此处可以特异性的修改为你允许通过的主机,多个用","分隔
        // 设置访问源请求头
        config.addAllowedHeader("*");
        // 设置访问源请求方法
        config.addAllowedMethod("*");
        // 对接口配置跨域设置
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

VUE项目

前端项目解决的思路就是将该跨域的请求代理成前端自身所在主机的 Agreement ://IP:Port

后再向服务端发送

在vue-cil框架下搭建的项目  可配置 不同用途的环境,

vue.config.js 脚手架 配置文件内:

  // webpack-dev-server 相关配置
  devServer: {
    host: '0.0.0.0',
    port: port,
    open: true,
    proxy: {
      // detail: https://cli.vuejs.org/config/#devserver-proxy
      [process.env.VUE_APP_BASE_API]: {
        target: `http://192.168.0.100:8080`,  // 后端开发接口地址
        //ws: true,
        changeOrigin: true,
        pathRewrite: {
          ['^' + process.env.VUE_APP_BASE_API]: ''
        }
      }
    },
    disableHostCheck: true
  }

开发环境配置文件   .env.development

# 开发环境配置
ENV = 'development'

# XX系统/开发环境
VUE_APP_BASE_API = '/dev-api'

# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true

当环境为开发环境时:面对axios异步请求时通过代理将该以'/dev-api'开头的请求代理到proxy:{}块内将target的后端接口  但实际的接口并无"/dev-api"此段上下文  ,所以通过pathRewrite:{}块进行地址重写将'/dev-api'替换为' ' ,从而实现api的还原, 然后请求到达服务端。  此段在npm 并部署 后 将不起作用

2、生产环境

 SpringBoot项目

后端解决的思路仍旧就是在请求的响应头内添加若干允许请求通过跨域检查的属性:

@Configuration
public class ResourcesConfig implements WebMvcConfigurer{

    /**
     * 跨域配置
     */
    @Bean
    public CorsFilter corsFilter()
    {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // 设置访问源地址
        config.addAllowedOrigin("*");  // 此处可以特异性的修改为你允许通过的主机,多个用","分隔
        // 设置访问源请求头
        config.addAllowedHeader("*");
        // 设置访问源请求方法
        config.addAllowedMethod("*");
        // 对接口配置跨域设置
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

VUE项目

前端项目解决的思路就是将该跨域的请求代理成前端自身所在主机的 Agreement ://IP:Port

后再向服务端发送, 但现在部署到web容器后  代理的操作只能寄希望于web容器 ,当前使用的是

Nginx容器

Nginx配置 [ nginx.conf ]:

server {
        listen       8088;
        listen       [::]:8088;
        server_name  bi.xx.com;  # 域名或IP
 	    # 处理静态文件
	    location / {
	       root 		 /usr/Prng/Bi/cilent/dist;  # 静态文件的路径
		   index 		 index.html index.htm;
		   try_files $uri $uri/ /index.html; # 处理单页面应用(SPA)
		      # 添加以下配置以允许跨域请求
	        if ($request_method = 'OPTIONS') {
	            add_header 'Access-Control-Allow-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-Allow-Credentials' 'true'; # 启用凭证支持
	            add_header 'Access-Control-Max-Age' 1728000;
	            add_header 'Content-Type' 'text/plain; charset=utf-8';
	            add_header 'Content-Length' 0;
	            return 204;
	        }
			  
	        	  add_header 'Access-Control-Allow-Origin' '*';
	            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
	            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
	            add_header 'Access-Control-Allow-Credentials' 'true'; # 启用凭证支持
	            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
#	            add_header 'X-Debug-Location' "static-api-block";  # 添加自定义响应头
	        
		   
	    }

		 # 代理 API 请求
	    location ^~ /prod-api/ {
	    	rewrite ^/prod-api/(.*)$  /$1 break; # 重写路径将  api 替换为空
	        proxy_pass http://bi.xx.com:8080/;  # 当以/结尾时 也会将匹配的前缀/prod-api置空
	        	        
#	         # 添加CORS头部
	        add_header 'Access-Control-Allow-Origin' '*' always;
	        add_header 'Access-Control-Allow-Credentials' 'true' always;
	        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
	        add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept' always;
#	        add_header 'X-Debug-Location' "prod-api-block";  # 添加自定义响应头
#	
#	        # 处理预检请求
	        if ($request_method = 'OPTIONS') {
	            add_header 'Access-Control-Allow-Origin' '*' always;
	            add_header 'Access-Control-Allow-Credentials' 'true' always;
	            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
	            add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept' always;
	            return 204;
	        }
	        	  
	        proxy_set_header Host $host;
	        proxy_set_header X-Real-IP $remote_addr;
	        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	        proxy_set_header X-Forwarded-Proto $scheme;

		   # 自定义日志配置
#        access_log /var/log/nginx/prod-api-access.log;
#        error_log /var/log/nginx/prod-api-error.log;
	    }

    }

比如一个实际请求要从8088向8080发送:http://bi.xx.com:8080/a/b/c  ,但经过代理后请求流程变为

8088向自己的主机端口发送代前缀prod-api的请求  跨域检查通过   即当8088 产生请求http://bi.xx.com:8088/prod-api/a/b/c  当此请求到达nginx时   location ^~ /prod-api/ {}匹配到此请求

将前缀去除、将主机端口变成http://bi.xx.com:8080  ,完整的请求又变为http://bi.xx.com:8080/a/b/c  发送至服务端


六、location 匹配规则

在 Nginx 中,location 块用于定义不同的 URL 路径匹配规则,来处理不同的请求。Nginx 通过检查请求的 URI 来决定使用哪个 location 块。以下是 Nginx 中几种常见的 location 匹配规则及其优先级:

  • 精确匹配 (=)
  • 前缀匹配 (^~)
  • 正则匹配 (~~*)
  • 普通前缀匹配(无特殊字符)

精确匹配 (=)

location = /exact/path { ... }:用于精确匹配请求的 URI。只有完全匹配的请求才会被处理。

location = /login { 
    # 处理精确匹配 /login 的请求 
}

前缀匹配 (^~)

location ^~ /prefix/ { ... }:用于匹配以指定前缀开头的 URI,如果匹配成功,将立即停止搜索,并且不会继续检查正则表达式。

location ^~ /static/ { 
    # 处理以 /static/ 开头的所有请求 
}

正则匹配 (~~*)

  • location ~ /regex/ { ... }:区分大小写的正则表达式匹配。
  • location ~* /regex/ { ... }:不区分大小写的正则表达式匹配。
location ~* \.(gif|jpg|jpeg)$ { 
    # 处理所有以 .gif、.jpg、.jpeg 结尾的请求(不区分大小写) 
}

普通前缀匹配

location /prefix { ... }:用于匹配以指定前缀开头的 URI,匹配过程将继续寻找其他匹配规则(正则匹配)。

location /images/ { 
    # 处理以 /images/ 开头的所有请求 
}

匹配优先级

Nginx 按以下顺序处理请求:

  1. 精确匹配 (=)。
  2. 前缀匹配 (^~)。
  3. 正则匹配 (~~*),按文件中出现的顺序。
  4. 普通前缀匹配。

示例配置

假设前端项目在 Nginx 上的 8088 端口,后端项目在 Tomcat 的 8080 端口,并且后端接口没有 /api 前缀:

server {
    listen 8088;
    server_name your_domain.com;

    # 配置前端项目
    location / {
        root /path/to/your/vue/project;
        try_files $uri $uri/ /index.html;
    }

    # 配置反向代理,将 /api/ 请求转发到 Tomcat 服务器
    location /api/ {
        rewrite ^/api/(.*)$ /$1 break;
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 添加CORS头
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Origin, Authorization, Content-Type, Accept';
    }

    # 处理OPTIONS预检请求
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Origin, Authorization, Content-Type, Accept';
        return 204;
    }
}

七、proxy_pass 结尾带不带"/"的区别

proxy_pass 指令的路径后面是否带有斜杠 (/) 确实有区别。具体来说,proxy_pass http://localhost:8080/proxy_pass http://localhost:8080 的行为在 URL 路径的重写和转发方面有所不同。

带斜杠的 proxy_pass

proxy_pass http://localhost:8080/;
  • 如果 proxy_pass 后面的 URL 以斜杠结尾,Nginx 会将匹配的 location 部分替换为 proxy_pass 指令后面的路径。

  • 例如:

    location /api/ { 
        rewrite ^/api/(.*)$ /$1 break; 
        proxy_pass http://localhost:8080/; 
    }

    如果请求是 http://your_domain.com/api/login,它会被重写为 http://localhost:8080/login,并转发到后端服务器。

不带斜杠的 proxy_pass

proxy_pass http://localhost:8080;
  • 如果 proxy_pass 后面的 URL 不以斜杠结尾,Nginx 不会将匹配的 location 部分替换为 proxy_pass 指令后面的路径,而是直接追加请求的 URI。

  • 例如:

    location /api/ { 
        rewrite ^/api/(.*)$ /$1 break; 
        proxy_pass http://localhost:8080; 
    }

    如果请求是 http://your_domain.com/api/login,重写后会是 /login,但最终转发的路径会是 http://localhost:8080/api/login,因为 proxy_pass 后面没有斜杠。

总结

在你当前的场景中,假设你希望去掉 /api 前缀,并且正确转发请求路径,你应该使用带有斜杠的 proxy_pass

Spring BootVue前后端分离项目中,当前端Vue通过ajax或axios请求后端的API时,会经常遇到跨域问题。 跨域是由于同源策略(Same Origin Policy)导致的,即浏览器限制了在不同源之间进行通信(不同源指协议、域名、端口号任意一个不同)。解决跨域问题的方法有很多,这里介绍一种常见的处理方式。 在Spring Boot后端配置中,我们可以通过添加一个跨域配置类来实现对请求跨域的处理。首先创建一个类,命名为CorsConfig(跨域配置类名可自定义),并在该类上加上@Configuration注解。然后在类中添加一个方法addCorsMappings,使用@CrossOrigin注解配置允许跨域的规则。例如可以设置允许所有来源(origin)、所有方法(methods)和所有请求头部(allowedHeaders),如下所示: @Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*"); } }; } } 这样就实现了对所有请求的跨域访问授权。在allowedOrigins方法中可配置指定的允许来源,如指定某个特定的域名;allowedMethods方法可配置允许的请求方法,如GET、POST等;allowedHeaders方法可配置允许携带的请求头信息。 在Vue前端项目中,可以在开发环境中通过配置代理实现请求转发来解决跨域问题。在vue.config.js(Vue的配置文件)中,添加以下代码: module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', // 后端API地址 ws: true, changeOrigin: true } } } } 以上代码表示将以/api开头的请求转发到http://localhost:8080地址,并开启WebSocket和改变请求的源地址。这样前端项目就可以通过/api访问后端API,而不用担心跨域问题。 这样,我们就能够很方便地解决Spring BootVue前后端分离项目中的请求API跨域问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值