js跨域请求小结

同源策略及跨域网络访问

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

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

假设http://www.qq.com是当前的页面,另一个是页面发的请求
http://www.qq.com
http://www.baidu.com/a.js   // 域名不同,属于跨域

http://www.qq.com
http://user.qzone.qq.com/a.js  // 顶级域名虽然相同,但整个域名不同,仍属于跨域

http://www.qq.com:80
http://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最可靠。






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值