一共8种解决方案,推荐使用3.1方法,简单高效,一分钟配完就能下班。
什么是跨域
跨域问题来自于浏览器同源策略的限制,包括DOM同源限制和ajax同源限制。
同源,指的是协议、域名、端口号都必须完全相同(同一ip的不同域名也是跨域)。
同源策略的主要目的是防止csrf攻击,它可以有效地避免由于恶意攻击带来的危险,浏览器器同源策略使得网络访问更加安全。
关于ajax跨域
ajax跨域指的是一个页面的ajax只能请求和当前页面同源的数据,如果发现请求到的数据不符合要求,浏览器就会阻止返回的数据。
例如:页面a与页面b放置在服务器1下。
页面a中的ajax请求指向服务器1,而页面b中的ajax请求指向服务器2。
两个ajax都能请求到数据,但是由于页面b在服务器1下,而页面b中的请求是服务器2,浏览器发现这一问题后,就会阻止返回的数据。
在实际开发与生产中,常常需要获取来自其他站点的资源,这时候就需要发起跨域请求,这时候就需要使用特殊的方法来处理,使得我们能够获得想要的数据。
解决方法
1 浏览器配置
弊端:无任何意义,不可能给每一个用户都进行配置,懒得写了,每种浏览器都不一样,相同浏览器的不同版本,配置也可能不一致。
2 将请求类型从xhr转换为script
原因:发出去的请求如果是xhr类型,则浏览器会进行校验。普通的ajax请求是xhr类型的。
发出去的请求如果是script类型,浏览器是不会校验的。
如何转换:
当dataType修改为JSONP,这时发出的请求则为script类型。
$.ajax({
url:"http://localhost:8080//test//get1",
dataType:"jsonp",
success:function(data){
console.log(data);
}
});
弊端:
1:服务器,也就是后台需要修改代码
2:只支持get
3:发送的不是xhr请求
如果实际情况和这三种弊端相冲突,则不能使用这种方式解决跨域。
调用方解决(反向代理)
原理:
页面a放置在服务器1下。
页面a想请求服务器2的数据,但页面a的ajax还是指向服务器1。
我们可以在服务器上进行配置,将收到的请求,转发到服务器2上。
页面a的ajax请求地址为:www.minmin.com/pangle
其实转发到了:http://服务器2.com/pangle
3.1 nginx反向代理配置 (修改nginx.conf文件)
server{
listen 80;
server_name www.minmin.com;
location /benji {
proxy_pass http://localhost:8080/;
}
#反向代理地址
location /pangle{
proxy_pass http://服务器2.com;
}
页面a的ajax请求地址为:www.minmin.com/pangle
其实转发到了:http://服务器2.com/pangle
3.2 apache反向代理配置
<VirtualHost *:80>
ServerName www.minmin.com
#代理域名
ProxyPass /local http://localhost:8080/
#反向代理地址
ProxyPass /pangle http://服务器2.com
</VirtualHost>
页面a的ajax请求地址为:www.minmin.com/pangle
其实转发到了:http://服务器2.com/pangle
被调用方解决(返回的信息里加字段,允许调用后,浏览器则不进行拦截)
原理:
基于http协议关于跨域方面的要求而做的修改。
从a域名调用b域名时,在b域名返回的信息里加些字段,告诉浏览器b允许a调用。
这样,浏览器通过校验就不会报跨域安全问题。
4.1 nginx 进行添加
server{
listen 80;
server_name www.minmin.com;
location /{
#所有的请求转到 localhost8080
proxy_pass http://localhost:8080/;
#添加内容
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
if ($request_method = OPTIONS){
return 200;
}
}
}
4.2 apache进行添加( conf/extra/httpd-vhosts.conf 文件)
<VirtualHost *:80>
#服务器名
ServerName www.minmin.com
#代理域名
ProxyPass / http://localhost:8080/
#添加内容
Header always set Access-Control-Allow-Origin "expr=%{req:origin}"
Header always set Access-Control-Allow-Header "expr=%{req:Access-Control-Reqest-Headers}"
Header always set Access-Control-Allow-Methods "#"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Max-Age "3600"
#处理预检命令OPTIONS,直接返回204
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.#)$ "/" [R=204,L]
</VirtualHost>
4.3 spring框架解决方案
在需要调用的类或者方法上添加注解
@CrossOrigin
4.4 Filter
添加一个Class 实现 javax.servlet.Filter
然后重写doFilter
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse)response;
HttpServletRequest req = (HttpServletRequest)request;
String origin = req.getHeader("Origin");
if( !org.springframework.util.StringUtils.isEmpty(origin) ){
//带cookie的时候 Origin必须是全匹配 , 不能使用*
res.addHeader("Access-Control-Allow-Origin", origin);
}
String header = req.getHeader("Access-Control-Request-Headers");
//支持所有自定义头
if( !org.springframework.util.StringUtils.isEmpty(header)){
res.addHeader("Access-Control-Request-Headers",header);
}
res.addHeader("Access-Control-Allow-Methods", "*");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
res.addHeader("Access-Control-Max-Age", "3600");
res.addHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}