ie8下用iframe解决表单submit以及二级域名跨域的方法

Q:使用multipart/form-data方式上传表单,并且能够获得后台返回的数据

前几个月做项目的时候遇到的这个问题,现在空下来了有时间可以好好总结一下。

那会用chrome开发,使用jquery.form插件可以很完美的解决这个问题。后期在ie8兼容性测试的时候,不知为什么这个插件总是会报错,从源代码里面调试,也找不到问题的具体原因何在。随着项目上线时间越来越近,心里也越来越急,于是最后决定抛弃这个插件,自己写一个实现。

当然最后找到了原因,jquery.form插件在ie8下使用时是用iframe实现的,访问时涉及到二级域名跨域,因此在访问子iframe里面的东西时直接被block了,然后就挂了。(渣渣ie =_=)

那两个域名是类似这样的:
top:123456.cn
iframe:yyyyy.aaa.123456.cn

具体本文开头的这个问题是怎么解决的,接下来一步步介绍。

-使用iframe屏蔽submit提交表单后的自动跳转

正常的情况下,要上传包括文件的数据需要使用form中的multipart/form-data。

<form method="post" action="/submitTest" enctype="multipart/form-data">....</form>

如果直接使用form表单里的submit提交给后台,submit之后,后台返回的数据会在前端新建一个页面,并显示在上面。但这样的体验并不友好。

利用在html5中XMLHttpRequest Level 2提供的FormData这个接口,可以实现不依赖submit上传包含文件的数据。

var formData = new FormData();
formData.append('username', '张三');
formData.append('id', 123456);
formData.append('file', file);  //file为通过file input选择的文件obj
xhr.send(formData);

只要一个个往里面塞包括二进制的数据,然后回调success就好了。jquery.form默认就是使用这种方法。它会先检查浏览器是否有fileapi以及Formdata这个方法。但是遇到不支持html5的浏览器,比如ie8(渣渣ie =_=),就会走另一种用iframe的方法。

使用iframe是一种经典的老方法。将form的target熟悉指向iframe的name,后台表单返回的数据就会在iframe里面出现。

<iframe src="" frameborder="0" name="iframe"></iframe>
    <form method="post" target="iframe" action="/submitTest" enctype="multipart/form-data">
    ....
    </form>

iframe显示出后台返回的数据
最后将iframe设置为不可见即可

<iframe style="display:none;" src="" frameborder="0" name="iframe"></iframe>

有一点需要提醒一下。在ie中,需要将头设置为Content-Type:text/html,否则iframe里面接收到的是404,略蛋疼。

-使用onload获取后台返回在iframe中的数据

另一方面,我们需要得到后台返回的数据。一般使用的方式是在ajax的时候通过success回调,但明显用iframe不能直接用这样的方式。

iframe相当于一个新的窗口,有个属于自己的window对象。可以利用它的onload方法,当后台刷新iframe里面的数据时,用在父页面使用iframe的onload方法捕获这个动作,然后读取它的body就可以了。

var iframeEle = document.getElementsByName("iframe")[0];
iframeEle.onload = function(){
    console.log(document.iframe.window.document.body.innerHTML);
};

之后拿到后台数据该干嘛干嘛- -

在我实际的项目中额外多遇到了一个问题,就是开头提到跨域的问题。所以到这一步之后,还要多做一点工作。

-通过后台返回js代码,解决跨域

由于后台使用的域名为yyyyy.aaa.123456.cn,而主域用的是123456.cn,直接返回数据会引起跨域的问题。解决思路就是将iframe的domain设置为123456.cn。但是由于跨域,不能从父页读取iframe,也不能修改其内容,因此需要用另一种方法实现。

后台返回的数据头中的Content-Type有几种类型,作用是告诉前端这些数据的类型,常见的有

text/plain
text/javascript
text/html
text/json
application/json
...

其中text/html为html语言,前端会将它当做html来解析。

res.set({'Content-Type':'text/html'});

这时我们可以加一个script标记写自己的脚本,标记之外放后台传来的数据。

由于返回的这些代码是直接在iframe上跑起来的,为了解决这个跨域的问题,我们可以这样设计后台返回回来的内容:

<script>document.domain='123456.cn'</script>
{"code":"s_ok","var":[{"name":"jone","age":123}]}

这么操作之后,父页就可以无阻碍的访问子iframe,不受到浏览器的阻拦了。

顺带一提,jquery.form插件在后台返回这段脚本之后,也没有了本文开头说的那些问题。说明我当初遇到的那个问题确实是由于跨域的限制引起的,导致在ie8下jquery.form挂掉的原因。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SSO (Single Sign-On) 单点登录是指在访问多个系统或应用程序时,用户只需登录一次就可以访问所有的系统,而无需再次输入用户名和密码。基于cookie二级域名跨域共享是指在跨域访问的情况下,通过设置cookie的域名和路径,使得不同域名下的系统能够共享登录状态。 具体来说,当用户成功登录一个系统后,该系统会生成一个包含用户登录状态的cookie,并设置该cookie的域名为当前系统的二级域名。然后,该cookie会被发送给浏览器保存,在用户访问其他系统时,浏览器会自动通过cookie将用户的登录状态传递给其他系统。 为了实现跨域共享,所有需要实现SSO的系统的二级域名需要设置为相同的根域名。例如,系统A的域名为a.example.com,系统B的域名为b.example.com,则它们的根域名为example.com。为了在这两个系统之间实现跨域共享,可以将cookie的域名设置为.example.com,这样两个系统就可以共享同一个cookie。 当用户访问系统A时,系统A会检查是否存在含有登录状态的cookie,如果存在则表示用户已经登录,可以直接访问系统A的资源。如果用户访问系统B,系统B也会检查是否存在含有登录状态的cookie,如果存在则表示用户已经登录,可以直接访问系统B的资源。 通过基于cookie二级域名跨域共享的方式,SSO单点登录实现了用户在不同系统间的无缝登录体验,提高了用户的使用便捷性和系统的安全性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值