在不影响历史记录的情况下,在iframe中进行表单POST提交

10

如何在不影响浏览器历史记录的情况下在iframe内提交表单?

我已经实现了跨域POST请求。它使用JavaScript创建并提交一个iframe内的表单。它能够工作,但是每个请求都会添加一项到浏览器的历史记录中。

有人知道解决此问题的方法吗?我已经尝试使用innerHTML和createElement创建iframe,但是没有看到任何区别。

PS- 我很想使用XMLHttpRequest(“Ajax”),但它不支持在跨域上发送数据。并且我很想使用GET而不是post,但我需要发送超过2k的数据。

这是我的代码的一个版本。我已经尝试了许多变化并进行了全面搜寻,但似乎找不到不影响浏览器历史记录的解决方案。我相信这是不可能的 - 有人能确认一下吗?

<html>

<head>
  <script type="text/javascript">
    function submit(params) {

      var div = document.createElement('div');
      div.innerHTML = '<iframe height="50" width="50"></iframe>';
      document.body.appendChild(div);

      var iframe = div.firstChild;
      var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
      iframeDocument.open();
      iframeDocument.close();

      var form = iframeDocument.createElement('form');
      iframeDocument.body.appendChild(form);
      form.setAttribute('action', 'http://some-other-domain.com/submit-here');
      form.setAttribute('method', 'POST');

      for (param in params) {
        var field = iframeDocument.createElement('input');
        field.setAttribute('type', 'hidden');
        field.setAttribute('name', param);
        field.setAttribute('value', params[param]);
        form.appendChild(field);
      }
      form.submit();
    }

    window.onload = function() {
      document.getElementById('button').onclick = function() {
        submit({
          'x' : 'Some Value',
          'y' : 'Another Value',
          'z' : new Date().getTime()
        });
      }
    }
  </script>
</head>

<body>
  <h1>Example of using Javascript to POST across domains...</h1>
  <input id="button" type="button" value="click to send">
</body>

</html>

1
为什么你不能只使用ajax来提交表单呢?这样就不会重新加载任何页面,从而释放你的历史记录。我有什么遗漏吗? - Alex Sexton
3
我需要跨域发布内容。使用Ajax(XMLHttpRequest)的POST方法无法将数据发送到与主页面不同的域名。 - Brian
我认为你实际上可以通过ajax发送POST请求。请查看我的更新答案。希望能对你有所帮助。 - Robert Massaioli
1
我认为这是不可能的(即使以某种方式实现,也很可能是特定于浏览器的)。 - hasen
Brian,你有最终解决这个问题所用的代码示例可以分享吗?谢谢。 - user576703
1
最终的解决方案是:1)插入一个托管在我的域名下的 iframe;2)使用 window.name 技巧将数据从不同域名的宿主页面发送到 iframe 中;3)向我域名上的服务器发送 Ajax POST 请求。 - Brian
5个回答

3

你应该 使用一个 AJAX POST

通常 创建 Ajax 应用程序时仅使用 GET 方法。但有几种情况需要在创建 ajax 请求时使用 POST 方法。这可能是出于多种原因。例如,相对于创建 GET 请求,创建 POST 请求更加安全,因为创建 POST 请求比创建 GET 请求相对较难。

AJAX 调用不会被存储到浏览历史记录中。


有用的链接,你应该关注它们,但不需要太多描述。 - Robert Massaioli
@Shhnap:这是一种有点严厉的爱。无论如何,我已经添加了Brian所需的相关信息。 - Esteban Küber
8
Ajax的POST方法在跨域时无法使用。该页面将托管在一个域上并向另一个域发送数据。此外,数据大小超过2k,因此使用GET方法不可行。 - Brian

1

使用JS添加一个IFRAME,其src托管在您的站点上(第三方托管脚本需要发送数据的域名?)是否有效?此IFRAME可以包含所需的Javascript,以使XMLHttpRequest到您/其域。至于将实际数据传输到此IFRAME的第三方站点-请尝试:http://softwareas.com/cross-domain-communication-with-iframes。这是一种相当聪明的解决方案,涉及更改IFRAME URL末尾的片段标识符(#something),然后您可以通过IFRAME内的JS读取它。

还有一个猜测,但如果您将this past SO solution附加到类似历史问题(使用location.replace)的上述部分中,这应该可以让您在不干扰历史堆栈的情况下更改锚点部分。


非常有趣!我需要一些时间来调查,但这可能就是我一直在寻找的东西。谢谢! - Brian
它完全起作用了,现在我可以在iframe中使用Ajax。 - Brian
很高兴听到这个消息!感谢您在此返回报告,我可以看出在不久的将来很可能需要使用这种方法。 - Ben Regenspan
我可能说得太早了。Safari不记录iframe历史记录,但其他浏览器会记录。仍在解决中。http://www.tagneto.org/blogcode/xframe/ui.html - Brian
最终的解决方案是:1)插入一个托管在我的域名下的 iframe;2)使用 window.name 技巧将数据从不同域名的宿主页面发送到 iframe 中;3)向我域名上的服务器发送 Ajax POST 请求。 - Brian

0

(?) 我不认为你使用 iframe 元素的理由很充分。(既然这是一个较早的问题,也许你是在测试1997年的HTML 4。顺便提一下,忽略对象名称中的 "XML" - 这是从2000年及以后版本的[X]HTML中遗留下来的,不需要 XML。)

如果你从 JavaScript 而不是文档中的元素发送 HTTP 请求,那么就不会向历史记录中添加任何内容。

function httpPost(body) {
  req = new XMLHttpRequest();
  req.open("POST", "/submit-here", true/*async*/);
     // or "http://some-other-domain.com/submit-here"
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  req.send(body);
}
window.onload = function() {
   document.getElementById('button').onclick = function() {
      httpPost('x=Some+Value&y=Another+Value&z=' + new Date().getTime());
      // or use a buildQuery function, JQuery formSerialize, etc. to create the body
   }
}

我使用符号链接(“ln -s ...”)使得表单可以提交到与文档相同的域名,因此在我的情况下,“/submit-here”是一个相对URI。


0
如果您的服务器可以运行代码,你可以通过 AJAX 查询来访问您服务器上的“代理”页面。该代理页面会运行远程服务器请求并返回结果到您的页面。

1
我不运行主机域。我运行需要发送数据的域。主机页面将包含我的代码作为第三方脚本。谢谢。 - Brian
我明白了。快速搜索似乎表明可以使用闪电代理来实现(参见http://blog.monstuff.com/archives/000280.html)。如果你不想选择这条路线,我不确定是否有可能实现。 - David Thibault
Flash有点重量级,但这是一个好主意。我一定会考虑的。 - Brian
实际上,闪存的重量不是问题。我不能使用它的原因是它在iPhone上无法工作。 - Brian

-2

正如评论中所提到的,解决这个问题的方法是从您的服务器发出AJAX请求,而不是尝试正常提交页面。W3schools有一个非常好的AJAX介绍,您可以在此处找到:http://www.w3schools.com/Ajax/Default.Asp

本质上,AJAX使用javascript向服务器发送请求并显示响应,因为它使用纯javascript,所以页面不会重新加载,历史记录也不会受到任何影响。这听起来就是您想要的。

编辑:AJAX无法发布数据。

我实际上认为它可以;或者至少有一些解决方法可以让您发布数据。请参见此处:

http://www.captain.at/howto-ajax-form-post-request.php

看起来它以一种相当直接的方式完成了。请参见页面底部的代码。具体地:

http_request.onreadystatechange = alertContents;
http_request.open('POST', url, true);
http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http_request.setRequestHeader("Content-length", parameters.length);
http_request.setRequestHeader("Connection", "close");
http_request.send(parameters);

6
XMLHttpRequest 支持 POST 方法,但不支持跨域发送数据。 - Brian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接