一.理解跨域问题
主要出现在前后端分离项目
引起跨域问题的原因
浏览器的同源策略,由于跨域不符合浏览器的同源策略,被浏览器拦截了
浏览器的同源策略
- 概念,它限制了从一个源的文档或脚本与另一个源的资源进行交互。主要是为了安全。
- 通俗来说,浏览器不允许在
js
(脚本)中请求非同源(协议,ip
地址,端口号任何一个不相同认为不同源)的资源。 - 举个例子:我前端项目的地址是
http://localhost:8080/XXXX
, 在js(javascript脚本
)中是不允许请求http://localhost:9000
的因为不同源,只能请求8080
端口。 - 前后端分离项目,通常在
js
中使用ajax
请求非同源服务器的数据,往往会引发跨域问题。
二.跨域问题的解决办法
跨域问题出现是因为再js
中请求了不同源(协议,ip
,端口不同)的服务器,只需要请求相同的源的服务器就可以解决这个问题,这就用到了代理,所有请求都请求相同的Node.js
或nginx
,对于部分请求(主要是获取静态资源的,不涉及跨域问题)直接返回对应资源,对于涉及跨域的请求,让node.js
或nginx
请求到对应资源再返回给浏览器,毕竟只有浏览器才有同源策略,服务器是没有的。
既然跨域浏览器不允许,那就直接告诉浏览器允许跨域----后端接口允许跨域,也可以解决跨域问题
解决方法1-------代理(前端配置)
如果不明白什么是代理,请阅读知识小贴士
-
没有代理,浏览器通过
http://localhost:8080/home.htm
l获取html
网页数据,在html
页面向http://localhost:9000/xx
获取html
页面具体数据,由于浏览器同源策略请求是不允许的
-
通过
nginx
或Node.js
代理后,获取url
为http//localhost:9000/xxx.html
的html
页面
获取url
为http://localhost:9000/api/xxx
页面内的数据 ,相同的http://localhost:9000
并不会引发跨域问题,只不过带api
前缀的被Node.js
或ngiinx
代理了,向http://localhost:8080/xxx
获取对应资源后再返回给客户端
-
实际解决问题(在前端添加代理配置)
在vue.config.js
中添加如下配置,只要是带api
前缀的都会被代理到http://localhost:9000
,请求路径
http://localhost:8080/api/xxx
被代理到http://localhost:9000/api/xxxx
这样解决了跨域问题问题
module.exports = {
devServer:{
proxy:{
'/api':{//匹配所有以'/api'开头的请求路径
target:'http://localhost:9000',//代理目标的基础路径
changeOrigin:true, //可要可不要看具体需求
pathRewrite:{'^/api':''} 可要可不要看具体需求
}
}
}
}
解决方法2-----开启跨域资源共享CORS
(后端)
-
cors概念
cors是w3c标准全称是跨域资源共享。 -
使用cors解决跨域问题
主要实现方式是在服务器端添加响应头Access-Control-Allow-Origin(允许请求的域) 和Access-Control-Allow-Methods(允许请求的方法)- 在springboot中在controller加@CrossOrigin注解,springboot框架会自动实现。加注解后controller类中的所有接口都被允许访问
- 手动添加–创建一个拦截器,在每个请求响应时增加允许跨域的请求头
将下面拦截器放在项目中就可以解决跨域问题
@Configuration
public class CorsConfig implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
String origin = request.getHeader("Origin");
if(origin!=null) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
String headers = request.getHeader("Access-Control-Request-Headers");
if(headers!=null) {
response.setHeader("Access-Control-Allow-Headers", headers);
response.setHeader("Access-Control-Expose-Headers", headers);
}
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
知识小贴士
什么是代理?
是一个位于客户端和目标服务器之间的服务器(代理服务器),为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。