如何克服ajax跨域

背景

 最近做项目经常碰到跨域的问题,总在联调中浪费了不少时间,当然若时间充裕的话,跨域基本都是可以通jsonp来解决问题(get方式的请求),只是因为对接环境问题,就打算在请求头设置参数来解决跨域问题。

跨域资源共享 CORS 原理

 CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。这种方案也是我们最长用的,也是比较简单的。

例子如下:

JAVA后端代码:

response.setHeader("Access-Control-Allow-Origin", "http://www.xxx.com");

response.setHeader("Access-Control-Allow-Credentials", "true");

(1)Access-Control-Allow-Origin

表示接受任意域名的请求,如果是多个域名中间用','隔开,如果是 * 表示允许任何域名

(2)Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值

(4)Access-Control-Allow-Credentials

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。另外发送请求方需要varxhr=newXMLHttpRequest();   xhr.withCredentials=true; 否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials。

然而我们经常设置这样的选项,还是会在浏览器弹出:XMLHttpRequest cannot load http:/www.xxx.com.Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin. 这样的字眼,而且在post请求复现高。

这个时候多是因为浏览器发送了有一个预检请求,"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

在预检请求会带两个参数

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段

服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

所以如果是post的请求获取其他非简单的请求的话,我们可以尝试在请求头中加上

response.setHeader(Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");(注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。)

res.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");

就能解决上述的即使加了请求头允许跨域的域名以及Cookie的身份验证,依旧出现跨域的问题。

由于CORS请求和浏览器有关,所以在低版本IE或者其他的流量器如果不支持,该方式是行不通的,这个时候就只能使用JsonP的方式来解决跨域。

JSONP解决跨域原理

JSONP(JSON with Padding)是JSON的一种”使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的script元素是一个例外。利用 标签<script>元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。

通俗的来讲就是:JSONP的最基本的原理是:动态添加一个标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了。标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了。


下面是简单的dome  由于访问本地没有跨域,这里只是讲解:


6770660-cfdb04fbb05676ab.png

红色框内是一个ajax的跨域请求,假设前端请求的是一个不在当前域地址,这个时候浏览器会出现跨域的错误提示;

于是我们用,<script>标签的特性来解决这问题:


6770660-b76726ad40c4981d.png

这样的话,就能正常访问跨域的请求接口了。

两者相比:

Jsonp不会因为浏览器原因而不支持跨域,但是jsonp只是支持get方式的请求,所以两者相比的话,因环境而定,并没有谁好谁劣

猜你喜欢

转载自blog.csdn.net/weixin_34234721/article/details/87636153