js跨域请求小结

来源:互联网 发布:域名免费的 编辑:程序博客网 时间:2024/04/28 21:09

同源策略及跨域网络访问

同源的定义:如果两个页面拥有相同的协议(protocol),端口(如果指定),和主机(即域名),那么这两个页面就属于同一个源(origin)。

反之就是跨域,以下场景均属于跨域:

假设http://www.qq.com是当前的页面,另一个是页面发的请求http://www.qq.comhttp://www.baidu.com/a.js   // 域名不同,属于跨域http://www.qq.comhttp://user.qzone.qq.com/a.js  // 顶级域名虽然相同,但整个域名不同,仍属于跨域http://www.qq.com:80http://www.qq.com:8000/a.js   // 域名虽然相同,但端口不同,属于跨域http://www.qq.com<pre name="code" class="javascript">https://www.qq.com/a.js  // 协议不同,属于跨域

使用XMLHttpRequest进行跨域访问的时候,会遇到问题

更详细参考:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy点击打开链接

跨域请求解决方案

最近在工作中常遇到的跨域场景有两种,一是调用跨域接口获取数据,二是跨域表单提交。

场景1:跨域get请求获取数据

解决方案:
1是使用jsonp,方法是在页面中加入一个<script>标签,src设置为请求url,<script>标签中的引入js,即使跨域,请求也能够成功,请求需要发送一个callback方法名作为参数,返回的数据需要服务端配合,将数据转成json字符串,同时callback也作为字符串包裹着数据返回,这样,由于<script>标签对请求回来的js会立即执行,这样就相当于执行一个回调,当然,在<script>做在的作用域上要声明好callback方法,本方法仅能用在get请求,因为<script>的加载都是get请求。
参考代码:
// 作用域内定义一个回调方法window.callback = function(data) {console.log(data)};
// 建立script节点var scriptElement = document.createElement("script");
// 设置src属性,需要加一个参数,值为回调方法名,这点很重要,服务端需要知道回调的方法名才能返回对应的脚本内容
scriptElement.src = "www.baidu.com/a.js&cb=callback";scriptElement.type = "text/javascript";// 将script节点添加进页面document.body.appendChild(scriptElement);
jQuery.ajax已支持这种方式,只需要将dataType设成jsonp即可。

2是使用CORS,即跨源资源共享(Cross-Origin Resource Sharing (CORS)),简单讲就是设置请求头Origin:http://www.qq.com,服务端再配合设置响应头:Access-Control-Allow-Origin:http://www.qq.com,这样就可以完成简单的get请求跨域。
更详细参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS点击打开链接

3是使用代理,简而言之,就是发送请求给同源的服务端(带上跨域请求的url跟数据),这样就不存在跨域问题,再由服务端发送跨域的请求,然后再返回给客户端即可,详细代码不附上,曾经用nodejs写过,但不是很熟练,日后再详细研究。

场景2:跨域表单提交

假如需要使用post方法进行跨域操作,则jsonp是不适用的,但仍然可以使用CORS,通过服务端的配合,进行跨域请求,当然也可以使用代理;
使用CORS实现post跨域的话,按http标准来说,应该要先发送一个options预请求,询问服务器支持的跨域请求方法,然后再发送post请求,如果服务器不支持post,理论上讲代码就走向请求终止的分支,而不应该去发送post请求。

最近工作中常遇到需要跨域提交表单(上传文件),因此发现使用form实现跨域,也是允许的,form表单提交本来就支持跨域,但是直接使用form提交,是没有回调的,想要有回调,则应该使用form+iframe形式,通过服务端配合,form设置target属性值为iframe的name,则form提交后,由于form本身的功能,post请求的返回内容会出现在iframe里面,因此只需要后端配合返回一个script脚本字符串,内容是调用父框架的方法,就可以实现跟父框架的数据传输。

说到这里,需要提一点,上述的form+iframe形式,只有在同源或者顶级域名相同,协议端口都相同(只有二级域名以上不同)的情况下,才有效。

顶级域名相同,二级域名不同的时候,需要在请求发起页,以及iframe返回的脚本里面,设置一个document.domain="qq.com",将document.domain设成自己的顶级域名,这样iframe才能向父框架传输数据。

详细代码如下,html侧:
<form id="form_id" action="www.qq.com/formTest.cgi" enctype="text/plain" target="iframe_name">      <input type="hidden" name="text_input">  </form>    <iframe id="iframe_id" name="iframe_name"></iframe>
js侧:
window.callback = function(param) {//todo}var form = $('form');form.trigger('submit');
表单提交之后,后台配合返回内容如下:
<script>document.domain = "qq.com";parent.callback(json);</script>
后台返回一个script标签会直接加进iframe,这样iframe加载就会执行里面的js代码,里面的js代码调用父框架定义好的callback方法,就可以完成回调,返回数据可以以json格式当作回调参数传进去。
顶级域名不同的时候,这种回调应该是不能生效的,因此总结来说,还是使用CORS最可靠。






0 0
原创粉丝点击