如果对服务端没有进行特殊处理,我们在进行前后端联调的时候游览器会发生报错:
这是因为请求被同源策略被阻止,浏览器出于安全的考虑,使用XMLHttpRequest对象发起HTTP请求(异步请求)时必须遵守同源策略,除非服务端允许非同源的请求,否则请求会被游览器拦截,发送失败。
那什么是同源策略呢?
同源策略(Same-Origin Policy),是一个web安全的基础原则。
什么是同源呢?指的是协议(如HTTP或HTTPS)、域名和端口号完全相同才算同源。
从一个地址请求另一个地址,如果协议、主机、端口三者全部一致则不属于跨域(CORS--cross origin resource share 跨域资源共享),否则有一个不一致就是跨域请求,即不同源就是跨域。
同源策略简单说就是要求在游览器中网页发送请求的时候,请求的协议,主机,端口要以发送请求的页面(或者脚步)的主机,协议,端口一致。
而非同源(跨域)的请求如果没对服务端做特殊处理,默认情况下游览器的请求是无法访问成功的。这就是游览器的同源策略。
在游览器中进行前后端联调的时候,本地的端口号与游览器中网页的协议一致,主机一致,但是端口号不一致,所以就会请求接口服务失败。这就是违反了同源策略,产生了跨域问题。所以游览器请求本地接口会失败。
注:为什么Postman没有跨域问题呢?因为Postman不是游览器,没有同源策略。
在普通的跨域请求中(非简单请求),浏览器会先发送一个 OPTIONS 请求,该请求称为预检请求(preflight request),用来检查是否允许跨域访问。服务器收到预检请求后,根据请求中的头部信息进行判断,并返回相应的响应头,表示是否允许跨域访问。如果服务器返回的响应头中包含了允许跨域的信息(返回Access-Control-Allow-Origin 头信息),浏览器才会发送实际的跨域请求。
如果服务器没有正确设置响应头,或者返回的响应头中不包含允许跨域的信息,浏览器会拦截跨域请求,导致请求失败。
另外,需要注意的是浏览器的同源策略限制只存在于浏览器环境中。只有游览器才有跨域请求,如果在服务器端进行跨域请求,是不受同源策略限制的。
同源策略的作用是防止恶意网站通过在其页面中注入恶意脚本并获取其他来源的数据,防止跨站点脚本攻击(Cross-Site Scripting,XSS)、跨站点请求伪造(Cross-Site Request Forgery,CSRF)等安全问题的发生。
那我们怎么让跨域请求成功发送呢?
通过script标签的src属性进行跨域请求,如果服务端要响应内容则首先读取请求参数callback的值,callback是一个回调函数的名称,服务端读取callback的值后将响应内容通过调用callback函数的方式告诉请求方。如下图:
服务端在响应头添加 Access-Control-Allow-Origin:*,这样浏览器才会发送实际的跨域请求。
原理:
实现:
既可以用在controller层方法上,表示让这个controller层的接口允许跨域,也可以用在controller层的该类中所有接口允许跨域
(实现的原理就是在响应头添加Access-Control-Allow-Origin)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry){
//设置允许跨域的路径
registry.addMapping("*")
//是否允许cookie
.allowCredentials(true)
//设置允许的请求方式
.allowedMethods("GET","POST","DELETE","PUT")
//设置允许的header属性
.allowedHeaders("*")
//跨域允许时间
.maxAge(3600);
}
}
简单说以前是直接访问服务器,现在是先访问nginx再由nginx访问服务器。nginx相当于代理,因为nginx不是游览器,所以没有跨域的问题,通过这样子就解决了跨域的问题。