代码之家  ›  专栏  ›  技术社区  ›  OverClocked

Safari和Chrome后退按钮更改隐藏并提交表单中的值

  •  6
  • OverClocked  · 技术社区  · 14 年前

    以下问题在Safari和Chrome上都会发生,因此可能是WebKit问题。

    A页:需要登录才能查看的页,包含一个表单,该表单的类型为submit按钮,名称为submit,值为a

    B页:另一页

    页面C:要求用户登录页面,包含一个type=submit按钮的表单,name=submit,value=C

    用户访问A页,然后访问B页。然后空闲,用户的登录会话超时。用户点击后退按钮返回A页。浏览器将用户重定向到C页。

    在safari和chrome上,当c被呈现时,c页上的表单有type=submit按钮,name=submit,但是值显示为“a”。

    如果在C页上重新加载,则“C”将显示为“名称=提交”按钮的值。

    type=hidden输入字段也会出现同样的问题;当用户单击back按钮时,它们的值也会从其他表单更改为其他值。同样,这个问题也会出现在没有重定向的情况下,只需提交然后返回。在这种情况下,上一页呈现的隐藏和提交CGI变量值不正确。

    到目前为止,我唯一能想到的解决方法是在加载了页面c之后,使用javascript重置type=hidden和type=submit变量值,以确保这些值是正确的。但这并不干净,也不普遍适用。

    除了WebKit修复此错误之外,是否有人遇到了更好的解决方法?

    谢谢。

    3 回复  |  直到 10 年前
        1
  •  17
  •   OverClocked    14 年前

    经过反复挖掘,我找到了答案。好吧,不是答案,而是为什么会这样。我希望这能节省别人一些时间。

    当前基于webkit的浏览器(截至2010年3月16日),如safari和chrome,显示出以下错误。也许有人可以看看。谢谢。

    错误1:如果一个页面A有多个表单元素F1和F2,并且第一个表单(按HTML中的外观顺序)F1的“自动完成”设置为“关闭”(即),而F2的“自动完成”设置为“打开”(默认行为),则在离开页面A导航后,单击“浏览器后退”按钮返回到A、F1和F2页可能无法正确自动完成。特别是,如果f1和f2都有相同名称和类型的输入元素,例如n和t(即),则当使用“上一步”按钮导航回a页时,f1.n的值将自动与f2.n的值一起完成。

    错误2:首先,浏览器点击页面A,服务器返回一个包含表单元素F1和F2的HTML页面(这两个表单的“自动完成”设置为“打开”)。然后,用户离开页面A,然后使用“浏览器后退”按钮返回页面A。在第二次访问a页时,webkit向服务器发出另一个a请求(这与firefox的行为不同,后者在后退按钮上不向服务器发出任何添加请求)。如果服务器返回一个不同的HTML页面(例如,因为用户会话已注销),表单元素f3和f4与f1和f2不同,但由具有相同名称和类型的输入元素组成,则f3和f4将使用f1和f2输入元素值自动完成,即使在隐藏元素类型并提交。

    周围工作

    错误1:不要使用autocomplete=“off”,除非您为同一html页面上的所有表单设置了此设置。

    错误2:具体情况,没有好的通用解决方案。我们找到了一个可以接受的解决方案,包括隐藏窗体,以确保A页的两个版本具有相似的窗体;第一个版本具有f1、f2、f3,第二个版本具有f1、f2'和f3,其中f2'是f2的隐藏版本。如果我们不包括f2',那么第二个版本的页面a是f1,f3和f3将使用f2的元素值自动完成,即使对于f3中的隐藏和提交元素也是如此。

    webkit代码分析

    这两个bug出现在代码的同一部分,但可能被视为两个单独的bug。代码位于webkit代码树的webcore子目录中。

    错误1:在document::formElementsState中,打开自动完成功能的输入元素(通过htmlinPutElement::saveFormControlState选中)的状态保存在向量中。但是,在htmlformcontrolelementwithstate::finishparsingchildren中,每个表单元素(无论autocomplete是打开还是关闭)都从上述向量恢复状态。这会导致错误1。

    错误1修复:这应该是一个相当直接的修复-finishparsingchildren不应该恢复状态,如果元素已关闭自动完成。

    免责声明:我不在Mac上开发。我只使用它,我们开发一个网站。我今天刚浏览了webkit代码。因此,我没有创建或测试修补程序。

    错误2。这要复杂得多。

    我假设在一个与autocomplete无关的设计决策中,如果用户使用back按钮在历史中返回到页面a,webkit被设计为重新获取页面a。

    (我也有兴趣听听这个)

    从根本上说,webkit错误地假设第二次提取页面a会产生与第一次提取相同的html或至少相同的表单集。如果不是这样,则自动完成逻辑将不再产生正确/预期的行为。

    当webkit保存页面的状态时,它调用document::formelementsstate,它只创建一个成对的映射,并将每个输入元素的名称+类型和值对放入映射中。如果两个单独表单中的两个输入元素具有相同的名称和类型,则将保存这两个值。

    例如,假设页a具有形式f1和f2,f1具有名称为a1和a2、类型为t1和t2、值分别为v1和v2的输入元素。f2有名称为a3和a2、类型为t1和t2、值分别为v3和v4的输入元素。webkit将此页面的状态保存为(在json通知中)

    {“a1,t1”:[v1],“a2,t2”:[v2,v4],“a3,t1”:[v3]}

    如果用户使用“浏览器后退”按钮重新访问A页,WebKit将尝试使用上述状态自动完成从服务器获取的A页新版本上的表单。如果新版本的A页与上一页的表单完全相同,那么一切都可以正常工作。否则,webkit将产生不正确的行为。例如,假设第二次获取页面a时,服务器只返回一个表单f3,f3的输入元素名为a4和a2,类型为t1和t2,那么f3的a2元素将填充上一页保存的v2。

    (注意:代码中使用的存储状态和恢复状态的实际逻辑略有不同,但思路相同)

    当用户会话可能过期时,这个问题会在网站上显现出来,在会话过期后,点击页面A可能会产生稍微不同的HTML。例如,可能会给你一个“请登录”表单,或可能会给你大致相同的内容,但在搜索用户数据表单的顶部,会出现一个登录表单。在这些情况下,可见文本输入元素、隐藏输入元素和提交输入元素的值都可能被webkit更改。

    错误2修复:这很困难,因为当用户使用back按钮时,webkit会重新获取页面a。如果页面A的新版本与旧版本不同,则WebKit无法轻松地将表单的状态从页面的旧版本匹配到新版本上的某个表单(如果它甚至存在)。实际上,您不能要求所有表单都具有相同的dom id,即使如此,这仍然不完全正确,因为dom id在html页面中必须是唯一的,但在单独的html文档中不需要是唯一的。

    我能想到的唯一解决方案是:当您第一次访问页面a时保存状态时,获取页面的md5或sha1散列,并将其与输入元素状态一起存储。返回到A页时,仅当MD5或SHA1哈希值相同时才还原状态。

        2
  •  4
  •   a1ex07    14 年前

    我不确定,但尝试将autocomplete='off'添加到所有表单中。

    <form .... autocomplete = 'off'>
    
        3
  •  1
  •   Ron    12 年前

    autocomplete="off"

    对我不起作用。我找到了另一个解决方法,可以使用 text 字段,使用

    DIV style="display:none"

    并添加 input_type="text" value="s" 中的字段 DIV 标签