跨域问题及CORS解决跨域

情景

manage.leyou.com域名下的网站,向服务器api.leyou.com发起ajax请求。

在这里插入图片描述

什么是跨域问题?

跨域是指跨域名的访问,一下情况都属于跨域:

在这里插入图片描述
如果域名和端口都相同,但是请求路径不同,不属于跨域:

www.jd.com/itemww.jd.com/goods域名是指从http://双斜杠到后面的第一个/之间的部分。

在开始的案例中,从manage.leyou,comapi.leyou.com属于二级域名不同,存在跨域问题;

为什么会有跨域问题?

跨域不一定会有会跨域问题,因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效组织跨站攻击。所以跨域问题是对ajax的一种限制。

解决跨域问题的方案

  • Jsonp:利用script标签可以跨域的原理实现:
    限制:
    - 需要服务的支持;
    - 只能发起GET请求;

  • nginx反向代理:利用nginx反向代理把跨域为不跨域,支持各种请求方式;
    缺点:需要在nginx进行额外配置,语义不清晰,需要维护大量域名。

  • CPRS:规范化的跨域请求解决方案,安全可靠;

    • 优势:
      • 在服务端进行控制是否跨域,可自定义规则;
      • 支持各种请求方式;
    • 缺点:
      • 会产生额外的请求。

CORS解决跨域

什么是CORS?

cors是一个W3C标准,全称是跨域资源共享(Cross-origin resouce sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了ajax只能同域名使用的限制。

需要浏览器和服务器同时支持,目前,所有除了IE10之下的浏览器几乎都支持。并且自动完成,不用要用户参与。对于服务端,cors与ajax没有任何差别,但是浏览器会在请求头携带一些头信息,我们需要以此判断时都允许其跨域,然后在响应头中加入一些信息即可,可以通过过滤器完成。

原理

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

简单请求

只要同时满足以下两大条件,就属于简单请求:

  • 请求方法是以下三种方法之一:HEAD、GET、POST
  • HTTP的头信息不超出以下几种字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

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

在这里插入图片描述

指出当前请求属于哪个域(协议+域名+端口),服务会根据这个值决定是否允许其跨域。

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

Access-Control-Allow-Origin: http://manage.leyou.com   #可接受的域
Access-Control-Allow-Credentials: true	#是否允许携带cookie,默认不携带
Content-Type: text/html; charset=utf-8

如果跨域请求想要操作cookie,需要满足3个条件:

  • 服务的响应头中需要携带Access-Control-Allow-Credentials: true
  • 浏览器发起ajax需要制定withCredential为true
  • 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定域名

特殊请求

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

预检请求

特殊请求会在正式通信之前,增加一次HTTP查询请求,称为预检请求;浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些http动词和头信息字段。只有得到肯定的答复,浏览器才会发出正式的ajax请求,否则就报错。

预检请求

OPTIONS /cors HTTP/1.1
Origin: http://manage.leyou.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.leyou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

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

  • Access-Control-Request-Method:接下来会用到的正式请求方式,比如PUT
  • Access-Control-Request-Headers:会额外用到的头信息;

预检请求响应

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

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

这个响应中多出3个头:

  • Access-Control-Allow-Methods 服务器指定的允许正式请求访问的方式;
  • Access-Control-Allow-Headers 允许携带的头
  • Access-Control-Max-Age 本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次进行预检。

实现

实际上SpringMVC已经帮我们封装了CORS过滤器,我们将这个过滤器加在网关服务上即可。

@Configuration
public class GlobalCorsConfig {

    @Bean
    public CorsFilter corsFilter(){
        //添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //允许的域
        config.addAllowedOrigin("http://manage.leyou.com");
        //是否发送cookie信息
        config.setAllowCredentials(true);
        //允许请求的方式
        config.addAllowedMethod("*");
        //允许的头信息
        config.addAllowedHeader("*");
        //添加映射路径
        UrlBasedCorsConfigurationSource configurationSource= new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**",config);
        return new CorsFilter(configurationSource);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值