【问题标题】:XMLHttpRequest POST in iFrame on Page Load页面加载时 iFrame 中的 XMLHttpRequest POST
【发布时间】:2018-05-04 23:12:33
【问题描述】:

所以我想在页面加载时通过 iFrame 发送 XMLHttpRequest POST 请求。通过 iFrame 发布的原因是不显示推荐人。

Javascript:

function load() {
var http = new XMLHttpRequest();
var url = "action url here";
var params = "name1=one&name2=two";
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
http.send(params);
}

HTML:

<body onload="load();">
<iframe name="f1" src="about:blank" id="noreferer" width="0px" height="0px" style="border: 0px none;"> </iframe>
</body>

如何将请求附加到 iFrame。任何帮助,将不胜感激。



更新:

对于任何询问我为什么在 HTML 正文中添加和触发 load(); 的人,以下是通过 innerHTML 连接到 f1 iframe 的无引荐来源帖子请求代码,该代码适用于所有浏览器,因为 src is 'about blank'。但不是 XMLHttpRequest,也不能添加标头。

Javascript:

function load() {
var postdata = '<form id=NoReferrerPost method=POST action=\'action url here\'>' +
                '<input type=hidden name=name1 value=one />' +
                '<input type=hidden name=name2 value=two />' +
                '</form>';
top.frames['f1'].document.body.innerHTML=postdata;
top.frames['f1'].document.getElementById('NoReferrerPost').submit();
}

所以仍然需要一种附加 XMLHttpRequest 以在 iframe f1 中发布的方法,就像我上面的代码一样。


这里有一些部分有效的解决方案:

@fedeghe HERE 使用 src="data:text/html 和 no-referrer 元标记的解决方案可以在 some browsers 上工作。

【问题讨论】:

  • 如果您从主体onload 调用load 函数,这意味着脚本是在body 标记所在的同一页面中定义的......那么我有一个基本问题。 .. 究竟是什么让您认为iframe 可以处理load 函数?
  • "如何将请求附加到 iFrame。"为什么需要将它附加到 iframe?
  • @epascarello — 查看问题的第一段。
  • 完全错过了,我非常怀疑这样做会奏效....大声笑
  • @fedeghe 我刚刚更新了这个问题,以回答您最初的问题,即为什么我从 body onload 中触发了 load 函数。所需要的可能是一个连接器,因此需要 onload 函数。

标签: javascript html xmlhttprequest


【解决方案1】:

&lt;body&gt;&lt;iframe&gt; 标记中使用onload 不会更改引荐来源网址,因为代码仍从父窗口触发。

您应该在 iframe 中触发 ajax。要将代码从 this example 这样的父窗口放入 iframe:

frames[0].window.foo = function(){
   console.log ("Look at me, executed inside an iframe!", window);
}

你必须观察Same-origin policy,但是在这种情况下,由于你要更改referrer,你将拥有相同的来源和referrer,那么referrer不会改变

另外,浏览器在 ajax 请求中设置引用者(参见 thisthis尽管存在 referrer header 来操纵引用者行为。不幸的是,像&lt;meta name="referrer" content="no-referrer" /&gt; 这样的东西有一些重要的restrictions(不支持 Edge、IE 和 Safari)。

所以我认为更改或隐藏引荐来源网址的一种可能方法是通过某种服务器代理。这是:将所有 ajax 请求重定向到您控制的一台服务器,在服务器中执行 POST/GET 请求,在这种情况下隐藏引荐来源网址。其实很简单,这里用php(CURL)和javascript的例子:

myproxy.php:

<?php
$url = $_GET['url'];
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $url); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, "referrer you want");//<-- spoof referrer here 
$output = curl_exec($ch); 
curl_close($ch);
echo $content;//content is from $_GET['url'] passed from javascript ajax
?>

在javascript中

var url = "Url we want to hide the referrer";
    var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
     //response from myproxy.php here
    }
  };
  xhttp.open("GET", "myproxy.php?="+url , true);
  xhttp.send();

【讨论】:

  • 我已经更新了这个问题来回答你的问题,使用 POST 正常请求而不发送可在任何浏览器上使用的引荐来源网址的代码,并且还为 XMLHttpRequest POST 添加了一个无引荐来源元标记的解决方法。就像你说的,这并不适用于所有浏览器。
  • @Julius 我已经更新了答案,并添加了一个小型服务器代理的示例,以防您可以使用服务器端代码。
  • 看到了。然而,curl 方法的问题在于,它使用服务器 IP 而不是用户 IP。
  • @Julius 是的,不幸的是我们不能欺骗 IP。
  • @Julius 你见过这个jpgerek.github.io/referrer-killer/example.html 吗?我没试过
【解决方案2】:

使用src="data:text/html,,你可以做到,但你至少要注意脚本的编码

<iframe src="data:text/html,<html><head><meta name=%22referrer%22 content=%22no-referrer%22/></head><body><script>(function(){var http = new XMLHttpRequest(), url = %22http://www.yourTargetDomain.com%22, params = %22name1=one%26name2=two%22; http.open(%22POST%22, url, true); http.setRequestHeader(%22Content-type%22, %22application/x-www-form-urlencoded; charset=UTF-8%22); http.send(params);})(); </script></body></html>"
  width=0 height=0 style="display:none;"></iframe>

您可以阅读有关它的更多详细信息 herehere

更新加载

如果您确实需要在某些时候这样做,userORbrow 事件驱动您可以执行以下操作(也将 name 属性替换为 id 用于 @ 987654326@标签,但没关系):

<script>
function load () {
    var targetDomain = "http://www.yourTargetDomain.com",
        params = "name1=one%26name2=two",
        html = '<html><head><meta name="referrer" content="no-referrer"/></head><body><script>(function(){var http = new XMLHttpRequest(), url = "' + targetDomain + '", params = "' + params + '"; http.open("POST", url, true); http.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); http.send(params);})(); <\/script><\/body><\/html>',
        src = "data:text/html;charset=utf-8,"+ escape(html);
    document.getElementById('f1').src= src;
}
</script>
<body onload="load();">
    <iframe id="f1" src="about:blank" width="0px" height="0px" style="border: 0px none;"> </iframe>
</body>

...此时我建议您的函数可以轻松:首先创建 iframe(关于:空白 src,隐藏 ...an on),然后附加它,然后触发帖子,等待请求成功(也许也消耗它),最后从 dom 中删除 iframe,类似于:

<script>
    function postIt (p, url, cb) {
        url = url ||  "http://www.targetdomain.org";
        p = p || {};
        cb && (p.cb = +new Date);

        var params = (function (o) {
                var s=[];
                for (var j in o) {
                    o.hasOwnProperty(j) && s.push(j+'='+o[j]);
                }
                return s.join('%26');
            })(p),
            html = '<html><head><meta name="referrer" content="no-referrer"/></head><body><script>(function(){var http = new XMLHttpRequest(), url = "' + url + '", params = "' + params + '";http.onreadystatechange = function(){if (http.readyState == 4 && http.status == 200){window.parent.postMessage("posted", "*");}};http.open("POST", url, true); http.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); http.send(params);})(); <\/script><\/body><\/html>',
            src = "data:text/html;charset=utf-8,"+ escape(html),
            iframe = document.createElement('iframe');
        iframe.style.display= 'none';
        iframe.height = iframe.width = '0px';
        window.addEventListener('message', function (e) {
            e.data == "posted" && document.body.removeChild(iframe);
        }, false);
        iframe.src = src;
        document.body.appendChild(iframe);
    }
</script>
<body onload="postIt({hello:'there'});">
    <h1>Hello world</h1>
</body>

【讨论】:

  • 此代码显示引荐来源。对于不显示的引用者,逻辑是使默认 iframe src 为 about:blank。即 src="about:blank" 在 POST 请求之前。
  • @Julius ...奇怪,xhr 请求的请求标头中的来源为空...至少在我测试的眉毛上
  • &lt;meta name="referrer" content="no-referrer" /&gt; 添加到标头中编码的 iframe 内容可以解决它。我更新了答案
  • 虽然在some browsers 中没有引用者元数据可以解决这个问题,但有些浏览器与它不兼容,仍然会显示引用者。像 IE 和一些旧的 android 浏览器。
  • @Julius 虽然很可能在版本工作解决方案方面并没有落后太多,但您报告的 caniuse 链接仅突出显示迷你歌剧...您是否担心 :) 或其他兄弟旧版本?
【解决方案3】:

如果您只想不发送referer,那么您可以使用referrer-policy 提及它。在您网页的 html 中添加元信息 (source):

<meta name="referrer" content="no-referrer" />

只需创建一个所需的 html 并在本地提供它并在您的机器上进行测试。

$ cat untitled.html
<!DOCTYPE html>
<head>
     <meta name="referrer" content="no-referrer" />
</head>
<body>
    <p> SOME CONTENT </p>
    <script>
        (function(){
            var http = new XMLHttpRequest();
            var url = "https://demo6945017.mockable.io/random/post"
            http.open("POST", url, true);
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
            http.send();
        })();
    </script>
</body>

$ python -m http.server

在测试时,您可以看到带有和不带有引荐来源网址策略的请求标头。

(Without the meta info -> With referrer)

POST /random/post HTTP/1.1
Host: demo6945017.mockable.io
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0
Referer: http://localhost:8000/untitled.html
Content-type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://localhost:8000

===================================

(With the meta info -> Without referrer)

POST /random/post HTTP/1.1
Host: demo6945017.mockable.io
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0
Content-type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://localhost:8000

(我已经删除了很多常见的标题,例如 content-lengthcache-control 用于 redablilty)
但请注意,每个请求仍在发送源,并且无法更改,它与浏览器的行为有关。此外,浏览器支持仅限于 Chrome 和 Firefox。

【讨论】:

  • 此解决方案将适用于所有页面请求,而不是特定的 iFrame 请求。 @fedeghe 回答 stackoverflow.com/a/51382768/1777938 也是一个无推荐人元标记的解决方法,但对于特定的 iFrame,如前所述,这仅适用于某些浏览器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多