利用iframe实现Ajax跨域通信原理与代码详解

作者:青柠

时间:2026-10-26

浏览:213

本文详细解析如何利用iframe嵌套机制解决Ajax跨域请求问题。通过主域页面嵌入目标域iframe,再由目标域iframe嵌入主域代理页面,利用URL参数传递数据与回调函数名,最终通过window.top实现跨域数据回传,完整展示了从参数传递到结果返回的全流程代码实现。

文章目录

iframe跨域通信原理概述

在前端开发中,Ajax请求通常受限于同源策略,即只能访问与当前页面域名、协议和端口相同的资源。若尝试跨域请求,浏览器会抛出异常并阻止请求执行,这主要是出于安全考量。尽管存在限制,但仍可通过特定方案实现跨域访问,例如利用iframe进行Ajax跨域请求。

iframe跨域通信原理概述

iframe跨域通信原理概述

具体架构如示意图所示:域a.com下的request.html页面中嵌入一个指向域b.com的response.html的iframe,而response.html内部又嵌入了域a.com下的proxy.html。

iframe跨域通信原理概述

实现跨域通信的核心逻辑是:域a.com的request.html通过URL参数将请求数据传递给域b.com的response.html,由response.html向同域的process.php发起真正的Ajax请求。随后,response.html将处理结果通过URL传递给域a.com的proxy.html。由于proxy.html与request.html同域,proxy.html可通过window.top对象将结果直接返回给request.html,从而完成跨域通信。

该流程的关键在于,真正的Ajax请求发生在域b.com内部,而非发起方域a.com。域a.com主要执行两个操作:一是由request.html负责向域b.com发送包含参数的请求;二是由proxy.html负责将域b.com返回的数据回传给request.html。

iframe跨域通信原理概述

跨域访问流程图

代码实现与流程解析

接下来展示具体的代码实现,首先明确文档结构如下:

http://a.com/

request.html

proxy.html

http://b.com/

response.html

process.php

首先分析request.html的代码,为便于理解,JavaScript代码直接嵌入页面中:

代码如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>该页面的路径是:http://a.com/request.html</title>
</head>
<body>
<p id="result">这里将会填上响应的结果</p>
<a id="sendBtn" href="javascript:void(0)">点击,发送跨域请求</a>
<iframe id="serverIf"></iframe>
<script type="text/javascript">
document.getElementById("sendBtn").onclick = function() {
var url = "http://b.com/response.html";
var fn = "GetPerson";//这是定义在response.html的方法
var reqdata = '{"id" : 24}';//这是请求的参数
var callback = "CallBack";//这是请求全过程完成后执行的回调函数,执行最后的动作
CrossRequest(url, fn, reqdata, callback);//发送请求
} 
function CrossRequest(url, fn, reqdata, callback) {
var server = document.getElementById("serverIf");
server.src = url + "?fn=" + encodeURIComponent(fn) + "&data=" + encodeURIComponent(reqdata) + "&callback=" + encodeURIComponent(callback);//这里由request.html向response.html发送的请求其实就是通过iframe的src将参数与回调方法传给response.html
} 
function CallBack(data) {//回调函数
var str = "My name is " + data.name + ". I am a " + data.sex + ". I am " + data.age + " years old.";
document.getElementById("result").innerHTML = str;
} 
</script>
</body>
</html>

结合代码与注释可知,该页面的核心意图是指示response.html执行其内部定义的GetPerson方法,并传入参数'{"id" : 24}'。关于为何将CallBack函数名传递给response.html,是因为该函数定义在当前页面,response.html无法直接执行。后续代码显示,response.html仅负责将该回调函数名传递给proxy.html,而proxy.html因与request.html同域,可直接调用该回调函数。

response.html处理逻辑

接下来查看response.html的代码实现:

代码如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>该页面的路径是:http://b.com/response.html</title>
</head>
<body>
<iframe id="proxy"></iframe>
<script type="text/javascript">
function _request(reqdata, url, callback) {//通用方法,ajax请求
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} 
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} 
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var data = xmlhttp.responseText;
callback(data);
} 
} 
xmlhttp.open("POST", url);
xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xmlhttp.send(reqdata);
} 
function _getQuery(key) {//通用方法,获取url参数
var query = location.href.split("?")[1];
var value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
return value;
} 
function GetPerson(reqdata, callback) {//向process.php发送ajax请求
var url = "process.php";
var fn = function(data) {
var proxy = document.getElementById("proxy");
proxy.src = "http://b.com/Proxy.html?data=" + encodeURIComponent(data) + "&callback=" + encodeURIComponent(callback);
} 
_request(reqdata, url, fn);
} 
(function() {
var fn = _getQuery("fn");
var reqdata = _getQuery("data");
var callback = _getQuery("callback");
eval(fn + "('" + reqdata +"', '" + callback + "')");
})(); 
</script>
</body>
</html>

该部分代码的主要功能是:接收来自request.html的请求参数与方法名,向服务器process.php发起Ajax请求,并将服务器返回的数据及从request.html传来的回调函数名传递给proxy.html。

process.php后端处理

随后查看process.php的代码,实现较为简单:

代码如下:

 
<?php
$data = json_decode(file_get_contents("php://input"));
header("Content-Type: application/json; charset=utf-8");
echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
?> 

这段PHP代码逻辑直观,具备基础PHP知识即可理解。

proxy.html结果回传

最后分析proxy.html的代码:

代码如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>该页面的路径是:http://a.com/proxy.html</title>
</head>
<body>
<script type="text/javascript">
function _getUrl(key) {//通用方法,获取URL参数
var query = location.href.split("?")[1];
var value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
return value;
} 
(function() {
var callback = _getUrl("callback");
var data = _getUrl("data");
eval("window.top." + decodeURIComponent(callback) + "(" + decodeURIComponent(data) + ")");
})() 
</script>
</body>
</html>

这是通信的最后一步:proxy.html从URL中获取由request.html经response.html传递过来的回调函数名及响应数据,并通过window.top调用request.html中定义的回调函数,完成数据回传。

在实际应用中,proxy.html可封装为通用代理组件,无需频繁修改。若需支持多种跨域方法,可在域a.com中定义相应接口,而域b.com则提供类似GetPerson这样的接口供调用。此外,实际部署时通常需隐藏iframe。最后强调:掌握技术本身并非最关键,具备学习能力更为重要。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章