为什么要设置跨域请求?
一个界面发起的ajax请求,只能是当前页面同域名发起的,这样就可以有效避免黑客发起的对服务器的恶意攻击;
请求跨域了,那么请求到底发出去没有?
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。
常用的跨域问题的解决方式?
一,nginx :
a网站向b网站请求1.js文件时,向b网站发送一个获取的请求,nginx根据配置文件接收这个请求,代替a网站向b网站来请求这个资源,nginx拿到这个资源后再返回给a网站,以此来解决了跨域问题。
例子:
server {
#监听8000端口
listen 8000;
#监听指定的ip地址
server_name 10.10.2.116;
#对对应url路径执行反向代理,如10.10.2.116:8000/demo
location /demo {
#目标的ip地址
proxy_pass http://www.leyou.com;
}
}
缺点: 需要的nginx进行额外配置;
二,CORS:
规范的跨域请求解决方案,安全可靠:
优点: 在服务端进行控制是否允许跨域,可以自定义规则,如header,method,origin,自定义限制;
缺点: 会产生额外的请求;
简单请求和和复杂请求的区分:
1.请求方式的区分:head,put,post;
2.头信息的限制:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
发送简单请求时 浏览器会自动识别并携带字段 origin =www.leyou.com,服务器会根据这个值进行判定是否允许跨域
不满足简单请求条件则就是复杂请求
CORS跨域请求的原理:
浏览器想服务端发送预检请求:
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...
服务端收到预检请求后,如果允许跨域,会发出响应:
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
服务端返回自己对跨域的请求的要求限制:
- Access-Control-Allow-Origin:可接受的域,是一个具体域名或者*,代表任意
- Access-Control-Allow-Methods:允许访问的方式
- Access-Control-Allow-Headers:允许携带的头
- Access-Control-Max-Age:本次许可的有效时长,单位是秒
允许客户端可以携带Cookie
- Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true
客户端跨域想要携带COOKIE要满足的要求:
- 服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。
- 浏览器发起ajax需要指定withCredentials 为true
- 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名
实际操作:
- 需要的配置一个Bean ,CorsFilter 过滤类 包含
UrlBasedCorsConfigurationSource----》 1.path:对映射路径的限制 2.CorsConfiguration---》封装了对跨域请求的限制,origin,header,method的设置;
-
CorConfiguration 封装对跨域请求的限制:
允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://manage.leyou.com");
config.addAllowedOrigin("http://www.leyou.com");
允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
允许的头信息
config.addAllowedHeader("*");
是否发送Cookie信息
config.setAllowCredentials(true);
添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
返回新的CorsFilter.
return new CorsFilter(configSource);
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 GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://manage.leyou.com");
config.addAllowedOrigin("http://www.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);
}
}