建立一个简单的springboot项目,在vue前端浏览器中使用axios发送请求,结果却出现报错
什么是跨域?
同源策略:为了保证浏览器的安全,不同源(不同协议,不同域名,不同端口)的客户端脚本在没有明确授权的情况下,不能去读写对方的资源
什么是同源
所谓同源就是指两个页面有相同的协议,主机和端口号,一旦其中有一个不一样,就是不同源,此时无法读取非同源网页的Cookie,当然也就无法发送axios请求
如:注册时,ajax所在的源是5173,而服务器所在的源是8080,这就是不同源,发生了跨域
因此为了解决这个问题,我们可以配置一下代理,这样前端服务替浏览器发起请求。浏览器所在的源是5173,前端服务器的源也是5173,同源则不会发生跨域
你可能会疑问,前端服务器的源是5173,后端服务器的源是8080,它们也是不同源,怎么不会发生跨域呢?
这是因为跨域是发生在浏览器的,服务端是没有跨域策略的
CORS全称为 Cross Origin Resource Sharing(跨域资源共享)。这种方案对于前端来说没有什么工作量,和正常发送请求写法上没有任何区别,工作量基本都在后端这里。每一次请求,浏览器必须先以OPTIONS请求方式发送一个预请求(也不是所有请求都会发送 options,展开介绍 点我),通过预检请求从而获知服务器端对跨源请求支持的 HTTP方法。在确认服务器允许该跨源请求的情况下,再以实际的HTTP请求方法发送那个真正的请求。推荐的原因是:只要第一次配好了,之后不管有多少接口和项目复用就可以了,一劳永逸的解决了跨域问题,而且不管是开发环境还是正式环境都能方便的使用。详细 MDN 文档
在dev开发模式下可以使用 webpack 的proxy也很方便,参照 文档 就会使用了,楼主一些个人项目使用的就是该方法。但这种方法在生产环境是不能使用的。在生产环境中需要使用 nginx 进行反向代理。不管是proxy 和nginx 的原理都是一样的,通过搭建一个中转服务器来转发请求从而规避跨域的问题。
开发环境 | 生产环境 |
cors | cors |
proxy | nginx |
什么是反向代理
nginx反向代理,就是将前端发送的动态请求由 nginx 转发到后端服务器
你现在可能会问,为什么不像上面一样,直接在前端服务中配置代理,代替浏览器去访问后端服务器,而是使用nginx代理呢?
原因:
1、提高访问速度
nginx中可以做缓存,多次请求同一个接口的时候,就不用每次都去后端访问了。因为已经第一次访问就已经得到数据了,以后再去调用这个接口,直接使用这个缓存下来的数据就行了,速度极大的提升了。
2、进行负载均衡
所谓负载均衡,就是把大量的请求按照我们指定的方式均衡的分配给集群中的每台服务器。
就是说假如我们现在不使用nginx负载均衡,那么前端服务器只能固定的访问一台后端服务器,这样的话就会给服务器带来很大的压力。因此一般项目上线之后都会搭建一个服务器的集群,这样nginx就会将大量的请求均衡的分配给每一台服务器
3、保证后端服务安全
此时若想访问后端接口,那么只有访问nginx一个入口,这样后端并不对外部开放,就非常的安全了
前端解决方式
1、在vue的vite.config.js中配置代理
server:{
proxy:{
'/api':{ //获取路径中包含了/api的请求
target:'http://localhost:8888', //后端所在源
changeOrigin:true, //确认修改源
rewrite:(path) => path.replace(/^\/api/,'') //替换 /api 为 空字符串
}
}
}
2、使用nginx反向代理
打开nginx的配置文件 nginx.conf
listen是此时nginx的端口奥,location /api/ 是处理含有 /api 字符串的请求。
proxy_pass 是转发到的后端接口
3、负载均衡配置
和上面的差不多,只不过我们现在使用的集群服务器罢了
当然,我们也可以设置负载均衡的策略
后端解决方式
1、Springboot中配置CORS
直接添加注解@CrossOrigin
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
}
但是这个方法只会在本Controller中起作用,在别的Controller上也需要加,比较繁琐
2、全局跨域处理
配置一个跨域过滤器
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 MyCorsConfig {
@Bean
public CorsFilter corsFilter(){
CorsConfiguration config = new CorsConfiguration();
//允许谁来异步访问
// config.addAllowedOrigin("*"); //允许所有人访问,不安全不推荐
config.addAllowedOrigin("http://localhost:7777"); //这里写允许访问的前端服务器
config.setAllowCredentials(true); //传递cookie
config.addAllowedMethod("*"); //允许哪些方法访问(*是全部方法)
// config.addAllowedMethod("OPTIONS");
// config.addAllowedMethod("HEAD");
// config.addAllowedMethod("GET");
// config.addAllowedMethod("PUT");
// config.addAllowedMethod("POST");
// config.addAllowedMethod("DELETE");
// config.addAllowedMethod("PATCH");
// 允许的头信息
config.addAllowedHeader("*");
//过滤资源
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**",config);
return new CorsFilter(configSource);
}
}
测试
页面成功跳转