跨域问题解决方案

为什么会有跨域问题

因为跨域问题是浏览器对于ajax请求的一种安全限制,一个页面发起的ajax请求,只能是与当前页相同域的url,这能有效的阻止跨站攻击。所以跨域问题只针对ajax请求,不包括静态资源的请求。

什么是跨域问题

当ajax请求和页面的域名不同、端口不同、协议不同时就会产生请求失败的情况。

协议不同可以是,http协议和https协议。

如果出现跨域问题,浏览器控制台会报这样一个错

解决方案

1、Jsonp

2、nginx反向代理

3、CORS方式

1、Jsonp

最早的解决方案,利用script标签可以跨域的原理实现。

优缺点

https://www.cnblogs.com/ricesm/p/5055043.html

2、nginx反向代理

利用nginx把跨域反向代理为不跨域,支持各种请求方式。也就是在发送ajax请求时,把url写成和当前网页不跨域的形式,然后通过nginx反向代理到相应的web应用服务器路径。nginx作为中介。

优点:请求效率高,由于nginx支持的并发量很大,所以并不影响请求速度。后台程序无需修改。

缺点:需要在nginx进行额外配置,增加运维成本。

3、CORS方式

规范化的跨域请求解决方案,安全可靠。

优点:在服务端进行控制是否允许跨域,可自定义规则。支持各种请求方式。浏览器不需要做额外操作,正常请求即可。

缺点:如果是特殊请求,会产生额外的请求。不支持IE10以下版本浏览器。

 

介绍:

同源:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

 XMLHttpRequest:http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。

CORS通信与AJAX没有任何差别,因此你不需要改变以前的业务逻辑。只不过,浏览器会在请求中携带一些头信息,我们需要以此判断是否允许其跨域,然后在响应头中加入一些信息即可。这一般通过过滤器完成即可。 

 

原理:

1.浏览器会将ajax请求分为两类,其处理方案略有差异:简单请求、特殊请求

 

一、简单请求(重要

1.什么是简单请求?

        简单请求是满足以下两种情况的请求:

                       a.   请求方法为head、get、post

                       b.   http的头信息超出一下几种字段:

                               - Accept
                               - Accept-Language
                               - Content-Language
                               - Last-Event-ID
                               - Content-Type:只限于三个值`application/x-www-form-urlencoded`、`multipart/form-data`、`text/plain`

                                                                               (三选一)

 

2.简单请求处理方案

发起一个ajax请求

请求信息如下:

请求信息

ajax请求的域名是http://api.leyou.com

 

请求头

请求头信息

浏览器发现发起的ajax请求是简单请求时,会在请求头中携带一个字段:`Origin`。

Origin中会指出当前请求属于哪个域(协议+域名+端口,形如  Origin : http://manage.leyou.com)。服务器会根据这个值决定是否允许其跨域。

origin就是当前页面的域名+端口+协议

我们可以看出,ajax请求的域名和当前域名不一致,存在跨域问题

 

响应头

响应头信息

 

如果服务器允许跨域,需要在返回的响应头中携带下面信息:

Access-Control-Allow-Origin: http://manage.leyou.com       

     作用是告诉浏览器,该请求允许跨域的白名单。可接受的域,是一个具体域名或者 * ,   * 就是任意域名。也就是说服务端允许该ajax请求在http://manage.leyou.com 这个域名下跨域

Access-Control-Allow-Credentials: true         

     是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true

Content-Type: text/html; charset=utf-8 

   

小结   

有了携带  这三条信息  的响应头,浏览器 就会同意该ajax请求跨域了。

 

代码实现

原理已经清楚了,就是服务端需要在响应头给加3条信息,就可以实现跨域。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class LeyouCorsConfiguration {
    @Bean
    public CorsFilter corsFilter(){
        //初始化cors配置对象
        CorsConfiguration configuration = new CorsConfiguration();
        //允许这个域名跨域,可以设置多个,如果可以携带cookie则不能写*,*代表所有域名都能跨域
        configuration.addAllowedOrigin("http://manage.leyou.com");
        configuration.setAllowCredentials(true);//允许携带cookie
        configuration.addAllowedMethod("*");//代表所有的请求方法都可以,(get post put delete等八种)
        configuration.addAllowedHeader("*");//允许携带任何头信息
        //初始化cors配置源对象
        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**",configuration);//所有路径都要检测一下
        //返回corsFilter实例,参数:cors配置源对象
        return new CorsFilter(configurationSource);
    }
}

我们只需要加上这样一个过滤器,就可以了。

CorsFilter是spring给我们准备好的。我们需要加点配置就行了。

二、特殊请求(不重要

不符合简单请求的条件,会被浏览器判定为特殊请求,例如请求方式为PUT。

预检请求

特殊请求会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

一个“预检”请求的样板:

简单请求相比,除了Origin以外,多了两个头

Access-Control-Request-Method:接下来会用到的请求方式,比如PUT

Access-Control-Request-Headers:会额外用到的头信息

 

预检请求的响应

        服务的收到预检请求,如果许可跨域,会发出响应:

除了Access-Control-Allow-OriginAccess-Control-Allow-Credentials以外,这里又额外多出3个头:

Access-Control-Allow-Methods:允许访问的方式

Access-Control-Allow-Headers:允许携带的头

Access-Control-Max-Age:本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次进行预检了

 

如果浏览器得到上述响应,则认定为可以跨域,后续就跟简单请求的处理是一样的了。

 

代码实现

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class LeyouCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //1) 允许的域,不要写*,否则cookie就无法使用了
        config.addAllowedOrigin("http://manage.leyou.com");
        //2) 是否发送Cookie信息
        config.setAllowCredentials(true);
        //3) 允许的请求方式
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        // 4)允许的头信息
        config.addAllowedHeader("*");

        //2.添加映射路径,我们拦截一切请求
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}

原理和简单请求一样,只要把这个过滤器,放到spring容器就行了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值