全面解析Ajax跨域问题

  • 关键词:跨域问题

一、什么是跨域

产生跨域的原因:

1.浏览器的限制:当浏览器发现你的请求是跨域的时候,会做校验,如果校验不通过,将会报跨域安全问题。

2.跨域:发出去的请求只要域名,端口,协议中有一个不同,都会产生跨域。

3.发送的是xhr(XMLHTTPRequest)请求,如果发送的不是xhr请求,就算是跨域,浏览器也不会报错。

二、解决思路

跨域解决方案:

1.浏览器–>需用户配置。

2.XHR–>JSONP。

3.跨域:

(1)被调用方修改代码支持跨域。

(2)调用方隐藏跨域(通过代理)。

image

三、全面解决跨域问题

1.浏览器的跨域设置:

在浏览器的属性设置页面的目标输入框里加上–disable-web-security,这样就可以让浏览器支持跨域了。

2.JSONP解决跨域问题:

(1)利用script标签,请求可以跨域来解决跨域问题。

(2)办法:使用ajax发送请求,dataType为JSONP,即可解决跨域问题。

(3)但这需要接口返回一个script标签,如果返回其他格式的数据,浏览器将会把它当成是js代码解析,所以将会报错。

(4)jsonp是一种非正式传输协议,是前后台约定的协议,而不是官方协议。

(5)jsonp的实现原理是:前后台约定带有“callback”这个参数的请求就是jsonp请求,前台发出去的请求加了“callback”参数,当后台发现请求中带“callback”时,后台就知道这是一个jsonp请求,就会把返回的数据由json变成JS代码返回,JS代码内容就是一个函数的调用,函数名是“callback”参数的值,而原来需要返回的json对象数据在这里作为参数传递返回。

(6)jsonp实现原理:jquery动态创建一个script,使用script发送出去,不是xhr请求。后台与前台约定使用相同的如callback函数,服务器返回的就会是javascript脚本,不是json。jsonp除了callback还有一个_的函数,是防止缓存的。如果cache设置为true,就没有_函数。

3.JSONP请求的弊端:

(1)服务器需要改动代码支持

(2)只支持GET

(3)发送的不是XHR请求

4.跨域解决方向:

(1)被调用方解决(在响应头增加指定字段,告诉浏览器允许调用。这种解决方案的请求是直接从浏览器发送的)

服务端实现:

在响应头中返回规定字段,允许指定地址和指定方法请求数据,如果要指定多个,可以将地址和方法改成*号即可。

简单请求和非简单请求

image

当浏览器要发送跨域请求时,如果请求是复杂请求,浏览器会先发送一个options预检命令即一个options请求,当该请求通过时才会再发送真正的请求。该option请求会根据请求的信息去询问服务端支不支持该请求。比如发送的数据是json类型(通过content-type设置)的话,会携带一个请求头Access-Control-Request-Headers: content-type去询问支不支持该数据类型,如果支持,则请求就会通过,并发送真正的请求。

复杂请求每次都要发送两条请求,效率很低,可以通过将预检命令缓存来减少请求。设置方法是服务端响应头设置Access-Control-Max-Age,值是缓存时间。

带Cookie的跨域:

image

  • “Access-Control-Allow-Credentials”,”true”。
  • Access-Control-Allow-Origin 不能为* ,必须为【调用方】的域名+端口。
  • 发送的Cookie是【被调用方】的cookie。

NGINX配置:

  • host文件中写入域名;
  • nginixconf配置文件中载入自定义文件夹vhost下的*.conf的所有文件;
  • 在vhost/b.com.conf自定义文件中实现请求端口和请求头配置参数。

Nginx请求代理设置:

image

APACHE配置:

APACHE配置:

image

Spring框架解决方案:

在类或者方法上添加注解——@CrossOrigin

(2)调用方解决(这是隐藏跨域的解决法案。这种跨域请求不是直接从浏览器发送的,而是从中间的http服务器转发过去的)

反向代理 :访问同一域名的的两个URL,去到两个不同的服务器。

  • NGINX实现隐藏跨域:

在下面的a.com.conf文件中配置参数后,在前端代码中把请求http://localhost:8081/test地址改成代理地址/ajaxserver

  • APACHE实现隐藏跨域:

apache配置文件配置好后,同样在前端代码中把ajax请求地址http://localhost:8080/test替换成代理地址/ajaxserverapache