# iframe + postMessage


原理:postMessage可以与任意域名之间通信(只要能通信了,其他的就都是浮云了),
类似一个代理,A域名不能直接访问B域名的接口,于是B给A派了一个小弟(pageC.html页面),然后跟A说,你可以通过快递小哥(postMessage)把你的请求告诉我小弟,然后我小弟会把你想要的结果快递给你~

http://dev.test.com/post-message.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>iframe-posMessage示例</title>
</head>
<body>
	<button id="but">执行请求</button>

	<iframe src="http://dev.example.com/iframe-postMessage" id="iframe" frameborder="0"></iframe>
	
	<script type="text/javascript">
		window.onload = () =>{
			let but = document.querySelector("#but");

			but.onclick = function(){
				let requestOptions = {
					methods: 'get',
					url: 'http://dev.example.com/get-name',
				}

				createRequest(requestOptions, function(res){
					console.log('响应...');
					console.log(res);
				})
			}
		}

		// 初始化请求个数
		window.requestIndex = 0;

		let iframe = window.frames[0];

		// 创建一个请求
		function createRequest(opt, next){
			// 请求次数自增,避免下次请求时回调执行絮乱
			requestIndex++;

			// 回调函数名称
			let funName = 'postMessageBack_' + requestIndex;

			// 把请求标识带过去
			opt.callback = funName;

			// 定义回调名称
			window[funName] = function(res){
				// 执行回调
				next(res);
			}

			let str = JSON.stringify(opt)

			iframe.postMessage(str, '*');
		}

		window.addEventListener("message", function(event){
			let data = {};

			if(event.data){
				data = JSON.parse(event.data);
			}

			let callbackName = data.callback;

			if(callbackName){
				delete data.callback;
			}

			// 执行回调
			typeof window[callbackName] === 'function' && window[callbackName](data);

		}, false);
	</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

http://dev.example.com/iframe-postMessage.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>快递小哥</title>
</head>
<body>
	<script type="text/javascript">
		window.onload = () =>{

			window.addEventListener("message", function(event){
				let origin = event.origin;
				// 允许访问的白名单
				let whitelist = [
					'http://dev.test.com',
				];

				if(whitelist.indexOf(origin) == -1){
					console.log("不在白名单内~");
					return;
				}
				
				let requestOpstions = JSON.parse(event.data);

				// 发出请求
				request(requestOpstions, function(res){

					res.callback = requestOpstions.callback;

					let resJson = JSON.stringify(res);

					// 把数据广播出去
					window.parent.postMessage(resJson, origin);
				})

			}, false);

			// 常规请求
			function request(options, next){
				var xhr = new XMLHttpRequest(); 
				var methods = options.methods.toLocaleUpperCase();

				// 异步传输
				xhr.open(methods, options.url, true);

				//发送请求
				xhr.send(null);

				xhr.onreadystatechange = function() {//Call a function when the state changes.
					if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
						let response = xhr.responseText;

						response = JSON.parse(response);

						// 请求结束后,在此处写处理代码
						next(response)
					}
				}
			}

		}

	</script>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

# 小结

  • 本质
    • postMessage跨域通信
    • 把请求委托给目标域名的页面
  • 缺点
    • ie8+才支持,而且ie8+<ie10只支持iframe的方式
  • 优点
    • 支持各个类型的请求
  • 适用场景
上次更新: 1/10/2020, 2:20:13 PM