天天看点

跨域解决方案详解

1.什么是跨域?

当前端调取的后台接口和前端服务不在同一个域中,就会出现跨域问题。如今前后端分离成为主流,接口往服务化发展,独立部署,前端往往要频繁访问不同的接口服务,解决跨域问题就成了一道绕不过去的槛。

2.为什么会产生跨域?

当同时满足“浏览器限制”、“跨域”、“XHR(XmlHttpRequest)请求”三个条件时,才会发生跨域问题。

3.跨域问题解决方案:

3.1.前端修改

3.1.1.浏览器命令行启动,关闭跨域校验:–disable-web-security命令

跨域解决方案详解

3.1.2.jsonp解决跨域

jsonp是什么?

json的补充协议,不是官方协议

jsonp解决跨域需要改后台吗?

需要,如果后台返回的还是json对象,前台会报错(小tips:关于controllerAdvice注解:详见https://www.cnblogs.com/lenve/p/10748453.html,这个注解常用于:全局异常处理、全局数据绑定、全局数据预处理)

跨域解决方案详解

jsonp原理:

和json不同,jsonp返回的type不是xhr,而是script,所以不会引起跨域问题。同理,jsonp返回的content-type不是json对象,而是javascript,所以java后台需要改动。jsonp是一个前后端约定的协议,如上后台代码,就是约定了当前台传参参数带callback时,就是一个jsonp请求,就不要返回json数据了,而是返回js代码,返回的名就是callback值,返回的值就是结果数据。

jsonP有什么弊端?:

1.服务器需要改动代码支持,如果服务端代码不是自己的,就比较麻烦

2.只支持get方法,因为返回的type是javascript,而不是json

3.不是XHR请求,XHR有很多新特性(异步、各种事件等),如果不是XHR请求就不能使用这些特性

综上,解决跨域的最好方法就是解决请求跨域,而不是解决请求是XHR

3.2.支持跨域:

被调用方做修改(修改被调用方http服务器,目的是在响应头中增加数据,告诉浏览器我允许跨域访问)

三种实现方式

3.2.1、服务器端实现(重点),Filter解决方案

浏览器是先执行后判断(思考:是不是所有请求都是先执行后判断?),所谓先执行后判断就是请求会先到后端执行,后端返回没问题,code也是200,但是再后端返回后会判断是否允许跨域。

浏览器如何判断是否跨域?如果是跨域请求,浏览器会在请求头中添加域名origin,后台返回后,浏览器会查看返回头中允许访问的域名是否包含当前域名,以此来判断。所以可以通过在返回头中添加信息的方式来允许跨域。

filter解决方案:在启动项里添加过滤器,在过滤器实现类中实现逻辑。如下图(思考:是否允许所有的请求跨域?)

跨域解决方案详解
跨域解决方案详解

简单请求和非简单请求:浏览器在发送请求前,会先判断请求是简单请求还是非简单请求,如果是简单请求,就先执行后判断,如果是非简单请求,浏览器会先发送一个OPTIONS预检命令,检查通过后才会将跨域请求真正发送过去

预检命令缓存:非简单请求每次都要请求两次,先发送一次预检命令再发送真正请求,比较影响效率,http协议增加了一个响应头,可以用来对预检命令进行缓存,命令如下:

res.addHeader("Access-Control-Max-Age","3600");

这条命令的意思是将预检命令缓存一小时,一小时内不会再发送预检命令

跨域解决方案详解

带cookie的跨域:当前端发送的请求带cookie时(ajax请求通过设置with-Credentials为true来是发送),域名必须全匹配才能跨域访问,即响应头origin不能设置为,同时响应头要加一个参数

res.addHeader("Access-Control-Allow-Credentials","true");
           

带自定义头的跨域:在响应头中加入自定义的请求头即可,即:

res.addHeader("Access-Control-Allow-Headers","content-Type,AAA,BBB");

后端接口可通过@RequestHeader(Value=“x-header1”)参数来获取命名为x-header1的请求头header AAA,前端ajax设置请求头如下:

跨域解决方案详解

3.2.2、nginx配置

当前端服务不直接调用后台接口,而是通过nginx做转发,我们就可以用nginx虚拟主机来配置跨域访问,不需要通过filter配置,具体配置如下

跨域解决方案详解

3.2.3、Apache配置

apache配置和nginx基本一致,增加五个请求响应头,记得把对应的模块放开

跨域解决方案详解

Spring框架下的跨域解决:

spring框架中配置跨域非常简单,只需要加@CrossOrigin注解即可,这个注解可以用在类上,也可以用在方法上,用在类上表示该类所有方法允许访问,你可以对这个注解做一些配置,但是一般情况没必要

3.3.隐藏跨域:

调用方做修改(修改调用方http服务器)

隐藏跨域的实现原理:前台在发送请求的时候,请求地址写的是相对地址,然后通过nginx反向代理实现访问对应的服务器。而不是直接在前台写绝对地址,这样对浏览器来说,我访问的是本域的相对地址,就不存在跨域问题,具体配置如下(以下分别是apache、nginx的配置):

跨域解决方案详解
跨域解决方案详解