全面解析Ajax跨域问题
- 关键词:跨域问题
一、什么是跨域
产生跨域的原因:
1.浏览器的限制:当浏览器发现你的请求是跨域的时候,会做校验,如果校验不通过,将会报跨域安全问题。
2.跨域:发出去的请求只要域名,端口,协议中有一个不同,都会产生跨域。
3.发送的是xhr(XMLHTTPRequest)请求,如果发送的不是xhr请求,就算是跨域,浏览器也不会报错。
二、解决思路
跨域解决方案:
1.浏览器–>需用户配置。
2.XHR–>JSONP。
3.跨域:
(1)被调用方修改代码支持跨域。
(2)调用方隐藏跨域(通过代理)。
三、全面解决跨域问题
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)被调用方解决(在响应头增加指定字段,告诉浏览器允许调用。这种解决方案的请求是直接从浏览器发送的)
服务端实现:
在响应头中返回规定字段,允许指定地址和指定方法请求数据,如果要指定多个,可以将地址和方法改成*号即可。
简单请求和非简单请求
当浏览器要发送跨域请求时,如果请求是复杂请求,浏览器会先发送一个options预检命令即一个options请求,当该请求通过时才会再发送真正的请求。该option请求会根据请求的信息去询问服务端支不支持该请求。比如发送的数据是json类型(通过content-type设置)的话,会携带一个请求头Access-Control-Request-Headers: content-type去询问支不支持该数据类型,如果支持,则请求就会通过,并发送真正的请求。
复杂请求每次都要发送两条请求,效率很低,可以通过将预检命令缓存来减少请求。设置方法是服务端响应头设置Access-Control-Max-Age,值是缓存时间。
带Cookie的跨域:
- “Access-Control-Allow-Credentials”,”true”。
- Access-Control-Allow-Origin 不能为* ,必须为【调用方】的域名+端口。
- 发送的Cookie是【被调用方】的cookie。
NGINX配置:
- host文件中写入域名;
- nginixconf配置文件中载入自定义文件夹vhost下的*.conf的所有文件;
- 在vhost/b.com.conf自定义文件中实现请求端口和请求头配置参数。
Nginx请求代理设置:
APACHE配置:
APACHE配置:
Spring框架解决方案:
在类或者方法上添加注解——@CrossOrigin
(2)调用方解决(这是隐藏跨域的解决法案。这种跨域请求不是直接从浏览器发送的,而是从中间的http服务器转发过去的)
反向代理 :访问同一域名的的两个URL,去到两个不同的服务器。
- NGINX实现隐藏跨域:
在下面的a.com.conf文件中配置参数后,在前端代码中把请求http://localhost:8081/test地址改成代理地址/ajaxserver
- APACHE实现隐藏跨域:
apache配置文件配置好后,同样在前端代码中把ajax请求地址http://localhost:8080/test替换成代理地址/ajaxserverapache