国庆前(2013)无聊,就在铁道部的12306上“逛”了下下。
PS:原来之所以叫12306,是因为其客服号码是12306,好吧,我很无知……
首先是被“逛”的页面:票价查询。
之所以去逛,是因为一直听闻该网站在节假日期间抢票慢、难,而国内浏览器厂商等开发抢票插件等等,这让我有些心动,于是便去瞧了瞧“传说”中的12306。
对于该页面的第一反应是,功能应该可以的,不然大家抢不到票了,不过美观的角度就不怎么样了。
本以为该页面会是用Ajax方式提及获取数据(因点查询后页面并无刷新迹象,且余票查询是Ajax请求方式的),于是通过Firebug观察提交的方式及返回的内容,发现是以POST方式的表单提交,而返回的内容居然是如下形式的代码:
<script>
parent.document.getElementById("randCode").value="";
parent.document.getElementById("img_rrand_code").src="passCodeActi0n.do?rand=rrand"+'?'+Math.random();
parent.document.getElementById("stationDIV").innerHTML="<strong>北京</strong>→<strong>上海</strong>列车票价信息暂无";
parent.document.getElementById("stationDIV2").innerHTML="<strong>上海</strong>→<strong>北京</strong>列车票价信息暂无";
<!-- =====================================================返程========================================================== -->
parent.document.getElementById("stationDIV2").style.display='none';
parent.document.getElementById("gridbox2").style.display='none';
</script>
返回的这个信息让人非常不解,一般POST
提交都是会“跳转”页面的,而这里返回了似乎是html代码的script标签,内部是含有返回数据的js代码。(代码和数据这两家伙,这么亲密-_-!)
对此我有两个疑问: 1) 表单提交返回了这个代码,但是页面怎么没刷新呢? 2) 很明显返回的代码起了作用,因为查询结果出现在了页面上,咋回事?
细心的人可能注意到了上面的代码中一个明显的地方(我表示当时我没注意这个-.-),即parent.document
字样,这个是在iframe
嵌套时,调用父iframe
中window
的操作,明显这里有蹊跷,当前页面提交后,返回的代码中居然是通过parent.document
字样的js代码来操作页面的。
另外,页面中表单标签的代码如下:
<form action="iframeTicketPriceByStation.jsp"
method="post" name="ticketPriceByStationform"
target="iframeName1">
<!-- 此处略去x行代码 -->
</form>
这里的target
属性让我感到可疑,特别是搜索target
的值“iframeName1”后,在页面中有如下iframe
代码,该iframe
隐藏了:
<iframe name="iframeName1" id="iframeID1" src="" width="0" height="0"
frameborder="0" />
初步猜测表单提交后返回的页面加载到该iframe
中了,对form
的target
做些调查后便能确定下来了。
查询w3school上的介绍:target
属性规定在何处打开 action URL
。
不过对于该属性的使用上却有些“兼容性”的问题:
在 HTML 4.01 中,不赞成使用
form
元素的target
属性;在 XHTML 1.0 Strict DTD 中,不支持该属性。(链接) 在 HTML5 中target
属性不再是被废弃的属性。(链接)
通过查看XHTML 1.0 Strict DTD对form
的定义,已经没有target
属性了:
<!ATTLIST form
%attrs;
action %URI; #REQUIRED
method (get|post) "get"
enctype %ContentType; "application/x-www-form-urlencoded"
onsubmit %Script; #IMPLIED
onreset %Script; #IMPLIED
accept %ContentTypes; #IMPLIED
accept-charset %Charsets; #IMPLIED
>
但在XHTML 1.0 Transitional DTD中还保留着:
<!ATTLIST form
%attrs;
action %URI; #REQUIRED
method (get|post) "get"
name NMTOKEN #IMPLIED
enctype %ContentType; "application/x-www-form-urlencoded"
onsubmit %Script; #IMPLIED
onreset %Script; #IMPLIED
accept %ContentTypes; #IMPLIED
accept-charset %Charsets; #IMPLIED
target %FrameTarget; #IMPLIED
>
看来该属性一度有被遗弃的现象,虽然在HTML5中已能正常使用了,但对于该属性的使用我还是不怎么习惯,总觉得有些另类哈……
以上介绍已经明了,该属性指定在何处打开表单提交的url,按照我们平时的使用可推测,默认情况是在当前页面。
参考对Target
属性的介绍,它可以有如下值,这些值应该是很熟悉的了,涉及到链接的时候,都会有这几个出现:
值 | 描述 |
---|---|
_blank | 在新窗口/选项卡中打开。 |
_self | 在同一框架中打开。(默认) |
_parent | 在父框架中打开。 |
_top | 在整个窗口中打开。 |
framename | 在指定的框架中打开。 |
很明显,票价查询页面上用的是framename
这类型的值,起初在看该页面中的iframe
标签属性是还让人有点迷糊,因为这里给iframe
加了相同的id
和name
,这是一种习惯,但也让人疑惑target
中放入的到底是id
还是name
?
以下是我的测试代码: 1)主页面:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>The Target of Form</title>
</head>
<body>
<form action="js.html" method="post" target="iframeName1">
<input type="submit" value="test1" />
</form>
<iframe name="iframeName1" id="iframeID1" src="" width="0" height="0" frameborder="0" >
</iframe>
<form action="js.html" method="post" target="iframeName2"> <!-- 指定name,如果不存在,这个name作为新开窗口的window.name -->
<input type="submit" value="test2" />
</form>
<iframe id="iframeID2" src="" width="0" height="0" frameborder="0" >
</iframe>
</body>
</html>
2)表单提交的页面(虽然可以只写script
标签的代码就行了,但总觉得不规范……):
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>The Target of Form</title>
<script>
alert(123);
</script>
</head>
<body>
</body>
</html>
PS: 当target
指定的name
不存在时(这个涉及到window.name
属性了),那么会新开一个window.name
为该name
值的窗口。之后的每次提交都会到这个窗口来,如果关闭了此窗口,那么再次提交时还是会新开启窗口的。
PPS: 关于重复表单提交(点击刷新按钮),似乎对于新开窗口方式,无重复提交现象出现(感觉这种方式就是以POST
形式新开窗口-_-)。而针对内嵌的iframe
方式,则会有重复表单提交现象(IE8、Firefox如此,但Chrome除外),具体如何我就不进行测试了,这是题外话了,问题无处不在,有新的东西就有新的问题,有兴趣的朋友自己试试。
最后吐槽下,该页面的验证码是js生成的数字,不禁让我回想起去年写过的类似代码,只是这里的代码兼容性真是差呢,也就ie下能运行了。
参考资料
- 为什么铁道部的网站叫12306?
- 铁路客户服务中心客服电话号码
- HTML <form> 标签的 target 属性
- HTML 5 <form> target 属性
- xhtml1-transitional.dtd
- xhtml1-strict.dtd