[same origin policy] 是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。 同源策略是浏览器安全的基石。
什么是源?
源[origin]就是协议、域名和端口号。例如:http://www.baidu.com:80这个URL。
什么是同源?
若地址里面的协议、域名和端口号均相同则属于同源。
同域:域名(父域名和子域名都相同),端口,协议都相同。
跨域:非同域的请求。在同源策略的限制下,非同源的网站之间不能发送 AJAX
请求。
注意:
跨域不是请求发不出去,而是服务端正常返回结果后被浏览器拦截返回结果。(浏览器为了防止非同源的请求 拿到服务器的返回数据结果)
哪些操作不受同源策略限制?
页面中的链接,重定向以及表单提交是不会受到同源策略限制的;
跨域资源的引入是可以的。但是JS不能读写加载的内容。如嵌入到页面中的,,,
降域
可以通过设置 document.damain=‘a.com’,浏览器就会认为它们都是同一个源。想要实现以上任意两个页面之间的通信,两个页面必须都设置documen.damain=‘a.com’。
JSONP跨域
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
CORS 跨域
跨域资源共享 CORS
因为是目前主流的跨域解决方案。所以这里多介绍点。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。IE8+:IE8/9需要使用XDomainRequest对象来支持CORS。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
跨域有2种请求,浏览器对于2种请求的处理不一样
在CORS出现前,发送HTTP请求时在头信息中不能包含任何自定义字段,且 HTTP 头信息不超过以下几个字段:
注意:这里的头信息是指我们主动设置的头部信息,在查看请求过程时会发现 浏览器会在头信息里设置Origin等信息,这些不算主动设置的。
简单请求:
浏览器会在 请求头信息 里增加一个Origin字段,表明本次请求的来源,若服务器返回的头部信息里需包含 Access-Control-Allow-Origin,并包含Origin 则浏览器正常返回数据,否则出现跨域错误。
如果需要携带cookie,请求时需设置(比如XMLHttpRequest.withCredentials = true)。若返回头部信息有 Access-Control-Allow-Credentials:true,则浏览器会正常返回数据,否则浏览器会拦截结果报 跨域错误。
注意:服务器会正常返回数据,只是浏览器拦截了结果。
服务器在返回头信息里设置(必须):
Access-Control-Allow-Origin: Origin
Eg:Access-Control-Allow-Origin:127.0.0.1:80
如果想设置匹配所有的Origin且不带cookie的,可以设置:
Access-Control-Allow-Origin: *
如果需要带Cookie(用户是否可以发送、处理 cookie),需设置:
Access-Control-Allow-Credentials:true
如果想匹配所有的Origin且带cookie:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: 请求的Origin(从request获取后填入)
千万不能同时设置Credentials=true且Origin=*,浏览器会报错。
Access-Control-Expose-Headers:可选,可以让用户拿到的字段。
有几个字段无论设置与否都可以拿到的,包括:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
不能同时满足简单请求的2个条件。
常见的情况是请求方法是PUT 或者 Content-Type字段类型是application/json 或者 头信息里自定义了属性
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Accept,Origin,X-Requested-With,Content-Type,Last-Modified,JSESSIONID,token;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
if ($request_method = 'OPTIONS'){
return 204;
}
或者
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
一般放在location块下 (nginx.cnf)。
解释:
1、Access-Control-Allow-Origin,这里使用变量 $http_origin取得当前来源域,也可以用“*”代表允许所有;
2、Access-Control-Allow-Credentials,为 true 的时候指请求时可带上Cookie,自己按情况配置吧;
3、Access-Control-Allow-Methods,OPTIONS一定要有的,另外一般也就GET和POST,如果你有其它的也可加进去;
4、Access-Control-Allow-Headers,这个要注意,里面一定要包含自定义的http头字段(就是说前端请求接口时,如果在http头里加了自定义的字段,这里配置一定要写上相应的字段),从上面可看到我写的比较长,我在网上搜索一些常用的写进去了,里面有“web-token”和“app-token”,这个是我项目里前端请求时设置的,所以我在这里要写上;
5、Access-Control-Expose-Headers,可不设置,看网上大致意思是默认只能获返回头的6个基本字段,要获取其它额外的,先在这设置才能获取它;
6、语句“ if ($request_method = ‘OPTIONS’) { ”,因为浏览器判断是否允许跨域时会先往后端发一个 options 请求,然后根据返回的结果判断是否允许跨域请求,所以这里单独判断这个请求,然后直接返回;
nginx里完整的跨域配置:
server {
listen 80 default_server;
server_name _;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
location /file {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods $http_access_control_request_method;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
add_header Access-Control-Max-Age 1728000;
return 204;
}
}
}
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); //支持cookie 跨域
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setMaxAge(300L);//设置时间有效
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://www.imooc.com/article/21976
https://howtodoinjava.com/java/servlets/java-cors-filter-example/
https://howtodoinjava.com/spring-boot2/spring-cors-configuration/
在浏览器上打开一个网站(非https的网站),F12后在console里输入
(function loadXMLDoc() {
var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatecatechange = function() {
}
xmlhttp.open("GET", "http://1.11.111.23:6088/event/list", true);
xmlhttp.withCredentials = true;
xmlhttp.send();
})()