为什么会有跨域问题:
1、什么是跨域
2、跨域原因
- 域名不同:www.jd.com/www.taobao.com
- 域名相同,端口不同:www.jd.com:8080/www.jd.com:8081
- 二级域名不同:item.jd.com/miaosha.jd.com
- 协议不同:http/https
- 请求路径不同不属于跨域
3、跨域问题
- 跨域不一定会有跨域问题
- 跨域问题:浏览器对于ajax请求的一种安全限制,一个页面发起ajax请求,只能与当前域名相同的路径,这样能有效阻止跨站攻击
解决跨域问题的方案:
1、Jsonp
- 最早的解决方案,利用script标签可以跨域的原理
- 限制:需要服务的支持 \ 只能发起GET请求
2、nginx反向代理
- 利用nginx把跨域反向代理为不跨域,支持各种请求方式
- 限制:需要在nginx进行额外配置,语义不清晰
3、CORS
- 规范化的跨域请求解决方案,安全可靠
- 优势:在服务端控制是否跨域,可自定义规则 / 支持各种请求方式
- 限制:会产生额外的请求
CORS解决跨域问题:
1、什么是CORS
- W3C标准,全称“跨域资源共享”(Cross-origin resource sharing)
- 允许浏览器向跨域服务器发起XMLHttpRequest(ajax底层对象)请求,从而克服ajax只能同源使用的限制
- CORS需要浏览器端与服务器端都支持该功能
- 浏览器端:目前,所有的浏览器都支持该功能(IE10以下不行),不需要用户参与,浏览器自动完成
- 服务器端:CORS通信与ajax没有差别,不需要改变业务逻辑。浏览器的请求会带有一些是否允许跨域的头信息,然后响应头中需要加入一些信息,一般通过过滤器完成
2、CORS原理
a、简单请求
- 同时满足以下两大条件:
– 请求方法是以下三种方法之一:HEAD \ GET \ POST
– HTTP头信息不超出以下几种字段:Accept \ Accept-Language \ Content-Language \ Last-Event-ID \ Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain) - 当发起简单请求时,会在请求头携带origin字段,会指出当前请求属于哪个域(协议+域名+端口),服务会根据这个值决定是否允许跨域,如果服务端允许跨域,会在响应头中携带下面信息:
– Access-Control-Allow-Origin: http://manage.leyou,com // 可接收的域,是一个具体域名或者*(代表任何域名)
– Access-Control-Allow-Credentials: true // 是否允许携带cookie,默认情况下不会携带
– Content-Type: text/html; charset=utf-8
- 要想操作cookie解决跨域问题,需满足以下条件:
– 服务的响应头中需设置允许携带cookie
– 响应头中的可接收的域一定不能为*,必须指定域名
b、特殊请求
- 不符合简单请求条件的请求,例如PUT请求
- 特殊请求会在正式通信之前,增加一次HTTP查阅请求,成为“预检”请求:浏览器询问服务器当前页面所在域名是否在服务器许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定回复,浏览器才会发出正式XMLHttpRequest请求,否则就会报错
- “预检”请求:
– OPTIONS /cors HTTP/1.1
– Origin: http://manage.leyou.com
– Access-Control-Request-Method: PUT // 接下来会用到的请求方式PUT
– Access-Control-Request-Headers: X-Custom-Header // 额外用到的头信息
– Host: apii.leyou.com
– Accept-Language: en-US
– Connection: keep-alive
– User-Agent: Mozilla/5.0...
- 预检请求的响应
– HTTP/1.1 200 OK
– Access-Control-Allow-Origin: http://manage.leyou.com // 允许请求
– Access-Control-Allow-Credentials: true // 是否允许携带cookie,默认情况下不会携带
– Access-Control-Allow-Methods: GET,POST,PUT // 允许访问的方式
– Access-Control-Allow-Headers: X-Custom-Header // 允许携带的头信息
– Access-Control-Max-Age: 1728000 // 本次许可的有效时长,单位是秒,过期之前的Ajax请求不需要预检
CORS过滤器实现:
1、建立过滤器对象
- 在zuul网关微服务创建过滤器配置
- 使用Java配置类实现
- 步骤:
– 创建配置对象
– 创建配置源
– 使用配置源作为参数创建过滤器对象
package com.leyou.gateway.config;
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 LeyouCorsFilter {
@Bean
public CorsFilter corsFilter(){
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("http://manage.leyou.com");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**",configuration);
return new CorsFilter(configurationSource);
}
}