什么是跨域
协议、ip、端口,三者中有一不同就产生了跨域
同源策略
同源策略发生在浏览器中,两个服务器可以直接进行跨域请求。同源策略限制了从同一个源加载的文档或搅拌如何与来自另一个源的资源进行交互,这是一个用于隔离潜在恶意文件的重要安全机制。
同源策略限制的内容有:
cookie,LocalStorage,IndexDB等存储性内容
DOM节点
AJAX请求不能发送
解决办法
JSONP
利用
<script>标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的json数据。JSONP请求一定需要对方的服务器做支持才可以JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
JSONP的优点时兼容性好,可用于解决主流浏览器的跨域数据访问问题。缺点时仅支持GET方法,具有局限性,不安全,可能会遭受到XSS攻击
我用的方法
CROS
CROS(Cross-origin resource sharing),跨域资源共享。CROS其实是浏览器指定的一个规范,浏览器会自动进行CORS通信,它的实现则主要在服务端,它通过一些HTTP Header来限制可以访问的域。
对于那些会对服务器数据产生副作用的HTTP请求,浏览器会使用OPTION方法发起一个预检请求,从而可以获知服务器端是否允许跨域请求,服务器端确认允许后,才会发起实际的请求。在预检请求的返回中,服务器端可以告知客户端是否需要身份认证信息。我们只需要设置响应头,即可进行跨域请求。
使用CORS解决跨域问题的时候,会在发送请求时出现两种情况,分为简单请求和复杂请求:
简单请求:只要满足以下两大条件,就属于简单请求:
使用GET、HEAD、POST方法之一;
Content-Type的值仅限于:text/plain、multipart/form-data、application/x-www-form-urlencoded,请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问;
复杂请求:不符合以上条件的就属于复杂请求,复杂请求的CORS请求,会在正是通信之前,增加一次HTTP查询请求,称为预检请求,改请求方法是OPTION方法的,通过该请求来指导服务端是否允许跨域请求。
我们通常发送的请求都是复杂请求,后台需被请求的servlet中添加header设置,Access-Control-Allow-Origin这个header在W3C标准里用来检查该跨域是否可以被通过,如果值为*则表明当前页面可以跨域访问,默认情况下是不允许的
一般通过编写一个过滤器来过滤跨域请求
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
//设置可以请求的域名
response.setHeader("Access-Control-Allow-Origin", "http://10.184.133.118:8080");
//设置是否接收cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
//设置可以请求的方法
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
//设置可以接收的请求头
response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, uni-request-source");
HttpServletRequest httpServletRequest = (HttpServletRequest) req;
//如果是预检请求 发送成功
if (httpServletRequest.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
}
//过滤请求
chain.doFilter(req, response);
}
}@CrossOrigin注解
这个方法仅对Java有用。springboot中,在Controller类上添加一个 @CrossOrigin(origins ="*") 注解就可以实现对当前controller 的跨域访问了,当然这个标签也可以加到方法上,或者直接加到入口类上对所有接口进行跨域处理,注意这个注解只在JDK1.8版本以上才起作用
使用SpringCloud网关
服务网关(zuul)又称路由中心,用来统一访问所有api接口,维护服务。Spring Cloud Zuul通过与Spring Cloud Eureka的整合,实现了对服务实例的自动化维护,所以在使用服务路由配置的时候,我们不需要向传统路由配置方式那样去指定具体的服务实例地址,只需要通过Ant模式配置文件参数即可
Node中间件代理(两次跨域)
实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。这样的话,我们可以让服务器替我们发送一个请求,请求其他服务器下面的数据。然后我们的页面访问当前服务器下的接口就没有跨域问题了。 代理服务器,需要做以下几个步骤:
接受客户端请求
将请求 转发给服务器
拿到服务器 响应 数据
将 响应 转发给客户端
nginx反向代理
实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。实现思路:通过nginx配置一个代理服务器做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
将nginx目录下的nginx.conf修改如下:
// proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET, POST, OPTIONS;
add_header Access-Control-Allow-Headers *;
}
}