Ajax跨域问题分析

一、什么是跨域问题

前台调用后台服务接口的时候,如果这个接口跟调用方不是同一个域的就会产生跨域问题

二、原因

1. 浏览器的限制

浏览器出于安全的考虑,当它发现你的请求是跨域的时候,就会做一些校验,校验不通过,就会爆出跨域安全问题。

2. 跨域

发出去的请求不是你本域,请求里面协议、域名、端口任何一个不一样,浏览器就认为是跨域。

3. XHR(XMLHttpRequest)请求

如果你发送的不是XHR请求的话,就算是跨域,浏览器也不会报错。


我做两个ajax发送请求,一个正常发送ajax调用接口请求,一个采用图片的形式发送一个普通的请求(直接在image标签中,放入该访问url),结果如上图所示,正常发送的请求,为XHR请求类型,而图片形式发送的普通请求,产生的是json请求。

而此时我们浏览器的错误之报出了一个错误,如下:


所以可以证明,发送的不是XHR请求的话,就算是跨域,浏览器也不会报错。

另外注意:当同时满足上述三个原因,才会发生浏览器跨域安全问题。

三、解决思路和方法

1. 指定参数,让浏览器不去校验

命令行启动chrome,输入: chrome --disable-web-security

价值不大,需要每个人都做客户端的改动

2. 发送的请求不是XHR类型----Jsonp

Jsonp全称为Json for padding,可理解为json的一种补充使用方式,是一个非官方协议,它是一个约定,约定了我请求的参数里面,如果包含指定的参数,默认就是callback,这就是一个jsonp请求。服务器发现这是一个jsonp请求的时候,就会将返回的值由原来的Json对象改为js代码,js代码的内容为函数调用的形式,函数名为callback参数的值,函数参数为原来要返回的json对象。接下来,在服务器端代码,添加如下内容:

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpBodyAdvice(){
  public JsonpAdvice(){
    super("callback");
  }
}
然后我依次在前端js脚本中,用ajax发送了正常的json请求和jsonp请求,结果如下:


从图中可以看出,Jsonp发出去的请求不是XHR类型,返回的响应式是JS脚本,并且请求发出去的时候,加了callback参数,这参数是在服务器端定义的,后台发现有callback参数,就知道这是一个Jsonp请求,于是就会将返回的数据由json变成js,而js的内容就是一个函数调用,也可以简单理解为,Jsonp通过动态创建的script标签,在script标签里面发出跨域请求,是一种变通的解决方案。

另外,要注意的是callback后面可能会跟着“_”参数,参数值是随机的数字,如下:


该参数主要是为了防止请求被缓存,若在ajax请求了设置了cache:true就不会出现这多余的参数值。

jsonp的缺点:

          1)服务器代码需要改动

           若不改动,浏览器将会将服务器返回的Json对象中的字符串当作JS代码来解析,就会报错。

          2)只支持get请求

          3)发送的不是XHR请求,这样就用不到该请求的一些特性

3. 解决跨域

典型的JAVAEE框架结构图如下所示:


从该图中,可以得出解决跨域问题的两种思路。

1)被调用方支持跨域解决思路

被调用方修改代码,让其支持跨域,基于http协议关于跨域方面的要求而做的修改,从a域名调用b域名时,在b域名返回的信息里加些字段,告诉浏览器b允许a调用。浏览器通过校验就不会报跨域安全问题。

常用方法:

1.1 采用过滤器,对返回请求中Header进行头文字的追加允许跨域的信息,根据不同的携带方式请求,进行不同的Header字段设置,使其支持跨域,一般都是增加Access-Control-Allow-Origin(表示允许跨域的域),Access-Control-Allow-Methods(表示允许跨域的方法)两个字段

其中要注意的是带有Cookie的ajax跨域,Access-Control-Allow-Origin的value不能为"*", 其值必须是当前调用方的url,如:res.addHeader("Access-Control-Allow-Origin", "http://localhost:8081");之后把Access-Control-Allow-Credentials的value设置为true.

1.2 在Nginx、apache配置虚拟节点,采用代理模式

其中运用到的就是虚拟主机的概念,多个域名指向同一个服务器,服务器通过不同的域名,将请求转到不同的应用服务器(例如Tomcat),看上去好像多个主机,实际就一个主机。其实本方法,就相当于之前过滤器方法的操作,从应用服务器Tomcat上转到了Nginx中转服务器上。

1.3 spring框架的自带解决方式,其中本人比较推荐spring这种解决方式,只需要在相应的需要支持跨域方法上添加@CrossOrigin注解即可

2)调用方隐藏跨域解决思路

当域名不是自己公司的时,可以用此方法解决。通过一个代理,使得从浏览器发出的请求都是a域名的请求,在代理里面把指定的url转到b域名里面,使得在浏览器上看上去就是同一个域名。

常用方法:

采用Nginx和Apache的反向代理配置,本方法类似于上述被调用方方法中的Nginx和Apache配置,一个是反向代理到其他Nginx上,一个是正向代理到自身不同的应用,并追加Header字段信息进行返回响应。

4. 请求是先执行还是先判断

在解决跨域问题时,尤其在使用被调用方支持跨域的解决思路中,我们需要知道浏览器对请求的执行和判断的顺序。

浏览器在发送跨域请求的时候,会判断请求的类型,判断其是否是简单请求和非简单请求。

    简单请求:先执行后判断
    非简单请求:先发出一个预检命令,然后在发出请求。先判断后执行。

关于常见的简单请求和非简单请求,如下图所示:


当浏览器发现当前请求时跨域的时候,会在请求头部增加当前域信息的字段,当请求返回来,就会检查响应头里面是否有允许跨域的信息,如果没有,就会报错。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值