1、了解跨域之前先说一下什么是同源策略?
如果两个页面的 协议、域名、端口三者完全相同,则说明两页面为同源。如果其中一个不一样则为不同源。
同源策略(英文全称Same origin policy)是浏览器提供的一个安全功能。
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。 这是一个用于隔离潜在恶意文件的重要安全机制。
说白了就是浏览器规定,A网站的JavaScript,不允许和非同源的网站C之间,进行资源的交互,例如:
①无法读取非同源网页的Cookie、LocalStorage 和IndexedDB
②无法接触非同源网页的DOM
③无法向非同源地址发送Ajax请求(这句是关键:只有发送ajax请求才存在跨域的问题。ifream和访问其他页面的静态资源不会出现跨域问题。)
localhost 和127.0.0.1 两者为不同源。(原因:localhost 只有在计算机联网的状态下才能转成127.0.0.1。其根本原因是因为计算机的配置让其转换,所以他们并没有什么关系,只是前期人们已经习惯了他们之间对等罢了)。
从百度上偷来的例子图片:
2、什么是跨域,为什么会产生跨域?
上面描述了什么是同源策略,反之,如果违反了同源策略则会出现跨域。
跨域问题出现之后,如果有人说通过前端配置即可解决此问题,那简直是扯淡。(跨域属于后端问题,单凭前端修改不能解决此问题)。
跨域的报错如下:
一个小的知识点:当跨域产生的时候,并不是此请求被拦截了,其实请求是能够发送成功的,后端接口也是能够接收到请求并且能够进行数据返回的。只是浏览器的同源策略的导致的。页面上出现了未响应的效果。
3、产生跨域之后,怎么解决?
当跨域产生之后,需要A页面访问B程序的接口信息。
目前能够百度到的最常用的就是两种方式:
JSONP:出现的早,兼容性好(兼容低版本IE)。是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持GET请求,不支持POST请求。(基本没人在用了,局限性太大。不过使用起来倒也简单,简单的代码如下:)
$.ajax({
url :'url',
//如果要使用$.ajax() 发起JSONP请求,必须指定datatype 为jsonp
dataType:'jsonp',
success: function(res) {
console. log (res)
})
CORS:出现的较晚,它是W3C标准,属于跨域Ajax请求的根本解决方案。支持GET和POST请求。缺点是不兼容某些低版本的浏览器。(比较常用)
深入讲解一下CORS:CORS其实就是跨域资源共享,它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
1、普通跨域请求:只需服务器端设置Access-Control-Allow-Origin
2、带cookie跨域请求:前后端都需要进行设置
那么问题来了,怎么在服务器端设置 Access-Control-Allow-Origin ?
1、其实Spring MVC 在处理这个问题上已经想到了这个问题。如果想要局部的解决某一个接口的跨域问题,可以在接口上增加注解方式进行解决。
@CrossOrigin
弊端:对于跨域解决范围太小,如果一个系统里面接口超级多,那么这样做的话,岂不是要累死了。
@RequestMapping(value = "/getreferenceauthorization", method = RequestMethod.POST)
@CrossOrigin
public String getreferenceauthorization(@RequestBody String params, HttpServletRequest request) {
try {
JSONObject jsonObject = JSONObject.parseObject(params);
String token = jsonObject.getString("token");
if (ZwdtConstant.SysValidateData.equals(token)) {
JSONObject obj = (JSONObject) jsonObject.get("params");
// 2、返回数据
JSONObject dataJson = new JSONObject();
String content = "请对您的证照进行授权确认!";
dataJson.put("noticeContent", content);
return JsonUtils.zwdtRestReturn("1", "成功", dataJson);
}
else {
return JsonUtils.zwdtRestReturn("0", "身份验证失败!", "");
}
}
catch (Exception e) {
log.error(e.getMessage(), e);
return JsonUtils.zwdtRestReturn("0", "失败", "");
}
finally {
}
}
2、手动设置响应头(不推荐,比加注解还要麻烦)
@RequestMapping("/index")
public String index(HttpServletResponse response) {
response.addHeader("Access-Allow-Control-Origin","*");
return "index";
}
3、使用自定义filter实现跨域 (可以用,但是作为一个业务开发来讲,着实有点为难)
@Component
public class MyCorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
4、引用第三方封装好的跨域组件(这个可以,别人已经封装好,我们只需要拿来用就可以了。)
cors-filter为第三方组件。在pom文件中引用jar文件配置即可。
<!-- 跨域请求 -->
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
</dependency>
然后在web.xml里面做一些基础的配置即可使用。
<!-- 跨域过滤器配置-->
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>cors.allowGenericHttpRequests</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowSubdomains</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, HEAD, POST, OPTIONS</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified, Authorization</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>X-Test-1, X-Test-2</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.maxAge</param-name>
<param-value>3600</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
如果此位置没有进行任何的拦截操作,则不会进行任何的跨域拦截。无论是否为第三方的请求都不会有跨域问题。
讲到这的话,后端基本上就能处理基本的跨域问题了。
但是一般情况下这种不会放在web.xml的过滤器中去处理此问题。如果开启跨域,在和第三方进行接口对接时,第三方接口变动,这边就需要在web.xml中更改他们变更后的ip。后期维护比较麻烦,如果不开启就会存在安全问题。
所以:一般的业务开发不需要关注的框架配置就开始发挥作用了。