spring boot + vue3 前后端分离处理跨域问题

1、什么是跨域

请求同域资源

在协议,域名 (或 ip 地址)相同,端口号相同下的请求资源,可以看做是同域资源

请求跨域资源

请求的资源只要 是协议 、域名(或 ip 地址)、端口号中任意一个不同的资源都可以认为是跨域资源

如:

端口号不同

127.0.0.1:80 与 127.0.0.1:8888  属于跨域

域名 (或 ip 地址) 不同

127.0.0.1:80 与 www.baidu.com:80  属于跨域

2、前后端分离项目中的跨域问题

例如:

前端 vue项目: 127.0.0.1:70

后端 SpringBoot项目: 127.0.0.1:8888

我们在前端 vue 项目中存放页面,页面中的数据是通过 axios 发起异步请求从 后端 SpringBoot项目中获取的

因此当我们访问前端页面时候, 我们可以理解为所在的当前所在 127.0.0.1:70 域上,所以访问这个127.0.0.1:70 域 的资源都是OK的,但如果使用 js 的方法访问其他域的资源时 就会出现跨域问题

本次教程拿 验证码 举例:

浏览器输入 127.0.0.1:70 访问登录资源,在 login.vue 中的 created 方法中调用 获取验证码方法 ( 发起axios 请求 127.0.0.1:8888 )

此时就会出现跨域的问题

3、方法一:SpringBoot后端进行处理

在 每个 Controller 类上加入 @CrossOrigin 注解

或者

在 Controller的基类中加上 @CrossOrigin 注解然后其他 Controller 类就有了这个 @Controller

此时跨域访问就不会报错了。

login.vue 访问的后端地址:

@CrossOrigin 注解解决方案的优缺点:

优点 :

  • 使用起来简单,直接在Controller类上加 @CrossOrigin 注解即可

缺点:

  • 如果后端技术使用的不是 SpringBoot,后端代码还需要处理跨域问题
  • 浏览器直接访问 后端API,在某种程度上是不太安全的

4、方法二:在Vue前端进行处理(仅限开发环境)

浏览器 在同一个页面访问不同的域 是存在跨域问题的

但 服务器之间的访问是 没有跨域问题

因此 需要在前端设置代理, 通过代理访问 SpringBoot后端API

要是直接在代码里请求http://127.0.0.1:8888/api/captcha/captchaImage?type=math是会有跨域限制的,我们使用代理的方式来绕过,请求的时候也不必给出完整的请求地址(见4.4)

4.1 安装

cnpm install axios

4.2 配置请求 baseURL

在 src / utils / request.js 

// 创建axios实例
const request  = axios.create({ 
  baseURL: '/api',
  timeout: 10000
})

这样会为所有的 请求url 前面都加上 ‘/api’,方便做 统一代理

4.3 配置 proxy

在 vue.config.js 

module.exports = {
  devServer: {
    // 自动打开浏览器
    open: true,
    port: 70,
    proxy: {
  
      '/api': {
        target: `http://localhost:8888/ruoyi`,
        changeOrigin: true,//开启代理
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

4.4 login.vue 页面发送验证码的请求

请求 API

import request from '@/utils/request'
// 获取验证码
export function getCodeImg() {
  return request({
    url: '/captcha/captchaImage?type=math',
    method: 'get'
  })
}

相当于请求遇见 /api 才做代理,但真实的请求中没有/api,所以在pathRewrite中把 /api 去掉, 这样既有了标识, 又能在请求接口中把 /api 去掉

注意
pathRewrite:如果不写则只能修改代理的域名,如果写则可以修改代理的域名和后边的路径

请求的截图:

我们发现 请求验证码的地址是前端服务器的地址

http://localhost:70/api/captcha/captchaImage?type=math

但我们配置了 proxy

proxy 解决跨域问题优缺点

优点:

  • 在浏览器中屏蔽了实际访问后端的 地址,相对安全
  • 后端代码不必要进行额外处理跨域

缺点

  • 在浏览器中看不到后端访问的地址,开发阶段调试不太方便

5、方法三:使用 nginx代理

前边部分的代码设置主要用来设置node服务的代理解决跨域问题的,打包后的前端项目,就是一个html和对应的js。要想独立部署又要解决跨域问题,就一定要从web容器的设置上下手。

前半部分的设置和 方法二 一样,之后对代理的设置如下:


	# 新增的服务
	server {
		listen       8086; # 监听的端口
		server_name 47.106.197.14; # 机器ip

		location / {
			root /home/;  # vue 打包后静态文件存放的地址
			index index.html; # 默认主页地址
		}
	
	
		location /api {
			proxy_pass http://47.106.197.89:9096/; # 代理接口地址
		}
		error_page   500 502 503 504  /50x.html;
		location = /50x.html {
			root   html;
		}

	}

6、proxy匹配规则

在 proxy 中可以写多个代理地址

  devServer: {
      proxy: {
          '/user': {
              //要访问的跨域的api的域名
              target: 'http://www.user.com',
              changOrigin: true,
          },
          '/order': {
              target: 'http://www.order.com',
              changOrigin: true,
          },
          '/pay': {
              target: 'http://www.pay.com',
              changOrigin: true,
          },
      }
  }

proxy 的匹配规则是根据正则匹配 如上 /user、/order、/pay 如果 请求地址 包含 此字符串,就算匹配成功,一旦匹配成功就 不会 继续向下匹配
如:

  • 请求 /user/info 则匹配 target 为 http://www.user.com
  • 请求 /order/user/list 则匹配 target 也为 http://www.user.com
  • 请求 /order/pay/user/list 则匹配 target 也为 http://www.user.com
  • 请求 /pay/order/list 则匹配 target 为 http://www.order.com

如果我们需要以 某个路径开头 才算 匹配成功,则可以改成:'^/user'、'^/account'、'^/pay

7、结合多axios实例的配置

结合之前的关于多实例的博客,在项目中可以这样配置

//main.js
var instance1 = axios.create({
  baseURL: '/api1',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});

var instance2 = axios.create({
  baseURL: '/api2',
  timeout: 2000,
  headers: {'X-Custom-Header': 'foobar'}
});

var instance3 = axios.create({
  baseURL: '/api3',
  timeout: 3000,
  headers: {'X-Custom-Header': 'foobar'}
});


Vue.prototype.$http1=instance1 ;
Vue.prototype.$http2=instance2 ;
Vue.prototype.$http3=instance3 ;
  devServer: {
  	proxy: {
  		'/api1': {
  			target: 'http://127.0.0.1:8888/projectA',
  			changOrigin: true,
  			pathRewrite: {
  				'^/api1': ''
  			}
  		},
  		'/api2': {
  			target: 'http://127.0.0.1:8889/projectB',
  			changOrigin: true,
  			pathRewrite: {
  				'^/api2': ''
  			}
  		},
  		'/api3': {
  			target: 'http://127.0.0.1:8899/projectC',
  			changOrigin: true,
  			pathRewrite: {
  				'^/api3': ''
  			}
  		},
  	}
  }
//使用第一个实例
this.$http1({
    method: 'post',
    url: 'consumer/trace',
    data: {
        openId: "oEy5O1231312321315sk",
        userId: "2597123134300"
    }
}).then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
})

url的变化如下 consumer/trace --> api1/consumer/trace --> 小型服务器 (api1/consumer/trace  --> /consumer/trace  --> http://127.0.0.1:8888/projectA/consumer/trace) --> 后台

其他的两个接口同理

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值