跨域问题解决方案

释放双眼,带上耳机,听听看~!

为什么会有跨域问题

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

什么是跨域问题

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

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

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

跨域问题解决方案

解决方案

1、Jsonp

2、nginx反向代理

3、CORS方式

1、Jsonp

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

2、nginx反向代理

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

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

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

3、CORS方式

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

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

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

 

介绍:

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:只限于三个值

1
1`

application/x-www-form-urlencoded

1
1`

1
1`

multipart/form-data

1
1`

1
1`

text/plain

1
1`

                                                                               (三选一)

 

2.简单请求处理方案

发起一个ajax请求

请求信息如下:

跨域问题解决方案

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

 

请求头

跨域问题解决方案

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

1
1`

Origin

1
1`

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条信息,就可以实现跨域。


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

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

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

**二、特殊请求(

不重要)**

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

**预检请求 **

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

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

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

跨域问题解决方案


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

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

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

 

**预检请求的响应 **

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

跨域问题解决方案

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

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

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

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

 

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

 

代码实现


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.web.cors.CorsConfiguration;
4import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
5import org.springframework.web.filter.CorsFilter;
6
7@Configuration
8public class LeyouCorsConfig {
9    @Bean
10    public CorsFilter corsFilter() {
11        //1.添加CORS配置信息
12        CorsConfiguration config = new CorsConfiguration();
13        //1) 允许的域,不要写*,否则cookie就无法使用了
14        config.addAllowedOrigin("http://manage.leyou.com");
15        //2) 是否发送Cookie信息
16        config.setAllowCredentials(true);
17        //3) 允许的请求方式
18        config.addAllowedMethod("OPTIONS");
19        config.addAllowedMethod("HEAD");
20        config.addAllowedMethod("GET");
21        config.addAllowedMethod("PUT");
22        config.addAllowedMethod("POST");
23        config.addAllowedMethod("DELETE");
24        config.addAllowedMethod("PATCH");
25        // 4)允许的头信息
26        config.addAllowedHeader("*");
27
28        //2.添加映射路径,我们拦截一切请求
29        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
30        configSource.registerCorsConfiguration("/**", config);
31
32        //3.返回新的CorsFilter.
33        return new CorsFilter(configSource);
34    }
35}
36

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

 

给TA打赏
共{{data.count}}人
人已打赏
安全经验

Google Adsense(Google网站联盟)广告申请指南

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索