什么是跨域
要想弄明白什么是跨域就要知道什么是同源策略,要想知道什么是同源策略就要先知道什么是源。
源:如果两个页面(接口)的协议,端口或者域名都相同,那么两个页面就有相同的源。
下表给出了相对http://store.company.com/dir/page.html同源检测的示例:
URL 结果 原因
http://store.company.com/dir2/other.html 成功
http://store.company.com/dir/inner/another.html 成功
https://store.company.com/secure.html 失败 不同协议 ( https和http )
http://store.company.com:81/dir/etc.html 失败 不同端口 ( 81和80)
http://news.company.com/dir/other.html 失败 不同域名 ( news和store )
同源策略
同源策略是浏览器的一个安全限制,从一个源加载的文档或者脚本默认不能访问另一个源的资源。例如a.com/111/html页面不能访问b.com/person这种接口,因为他们是不用的源。
注意:下面几个不受同源策略限制
1、页面中链接(例如页面的<a href="http://www.w3school.com.cn">W3School</a>)、重定向和表单提交不受同源策略限制
2、跨域资源的引入是不受同源策略的限制,但是js读不到其中的内容。<script src="..."></script>,<img>,<link>,<iframe>等。
怎么解决跨域
介绍生产中最常用的两种解决跨域的方法。CORS解决跨域问题和通过代理解决跨域问题。
CORS解决跨域问题
CORS是Cross-Origin Resources Sharing的简写,中文翻译为“跨域资源共享”,是W3C的标准。通过CORS,浏览器允许向其他源服务器发送资源请求。
设置CORS需要浏览器和服务器两个方面支持。目前基本上主流的浏览器都支持CORS(IE 8 和 9 需要通过 XDomainRequest 来实现),所以只要后端服务支持CORS,就能够实现跨域。服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符(*)则表示所有网站都可以访问资源。要实现CORS跨域其实非常简单,说白了就是在服务端设置一系列的HTTP头,主要分为请求头和响应头,在请求和响应时加上这些HTTP头即可轻松实现CORS。
虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求和复杂请求。针对不同的情况,服务端的设置也不一样。
- 简单请求
只要同时满足以下两大条件,就属于简单请求
条件 1:使用下列方法之一:
GET
HEAD
POST
条件 2:Content-Type 的值仅限于下列三者之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded - 复杂请求
不符合以上条件的请求就肯定是复杂请求了。
复杂请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来向服务端询问从当前源发送请求以及允许的请求方法和请求字段。
HTTP请求头:
#请求域
Origin: ”http://localhost:8080“
#这两个属性只出现在预检请求中,即OPTIONS请求
Access-Control-Request-Method: ”POST“
Access-Control-Request-Headers: ”content-type“
HTTP响应头:
#允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
Access-Control-Allow-Origin: ”http://localhost:8080“
#允许访问的头信息
Access-Control-Expose-Headers: "Set-Cookie"
#预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
Access-Control-Max-Age: ”1800”
#允许Cookie跨域,在做登录校验的时候有用
Access-Control-Allow-Credentials: “true”
#允许提交请求的方法,*表示全部允许
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,PATCH
例如简单请求
请求头:
响应头:
springboot里面可以这样设置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
通过代理解决跨域问题
实现原理:同源策略是浏览器需要遵循的标准,而如果是请求都发给代理服务器代理服务器再向后端服务器请求就可以规避跨域的问题。
例如用nginx做代理服务器。
nginx配置
server{
# 监听80端口
listen 80;
# 域名是localhost
server_name localhost;
#凡是localhost:8080/api这个样子的,都转发到真正的服务端地址http://localhost:8080
location ^~ /api {
proxy_pass http://localhost:8080;
}
}