跨域的几种方式

跨域的几种方式

参考资料:https://www.bilibili.com/video/av31173487?from=search&seid=17845079103401026420

http://www.ruanyifeng.com/blog/2016/04/cors.html

这里后端全部使用koa,写的只是为了方便理解,很多实际中不应该这样写。例子重复代码太多,但是直接粘贴就可以测试。

1.JSONP

1) 举个🌰,打开百度搜索

可以看见请求不在XHR内,请求地址为:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=12334&sugmode=2&json=1&p=3&sid=26522_1448_27209_21127_28131_27751&req=2&bs=12334&pbs=12334&csor=5&pwd=12334&cb=jQuery110209787636885175626_1545020875748&_=1545020875776

修改一下请求地址的查询参数cb部分

https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=12334&sugmode=2&json=1&p=3&sid=26522_1448_27209_21127_28131_27751&req=2&bs=12334&pbs=12334&csor=5&pwd=12334&cb=show

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>

<script>
function show(data) {
console.log(data);
}
</script>
<script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=12334&sugmode=2&json=1&p=3&sid=26522_1448_27209_21127_28131_27751&req=2&bs=12334&pbs=12334&csor=5&pwd=12334&cb=show"></script>

</body>

</html>

最后打印出结果

2) 实现一个简单JSONP例子
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>

<button onclick="send()">send</button>

</body>
<script>
function show(data) {
console.log(data);//这个是数据
}
</script>
<script>
function send() {
var script = document.createElement('script');
script.setAttribute('src','http://127.0.0.1:3000/jsonp?callback=show');
document.body.appendChild(script);
}
</script>

</html>

koa部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();

router.get('/jsonp', async (ctx, next) => {
const req = ctx.request.query;
console.log(req);
const data = '这个是数据';
ctx.body = req.callback + '(' + JSON.stringify(data) + ')';//show("这个是数据")
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');
3)封装一个JSONP函数

写完以后感觉,这写的什么鬼,我大概是忘了想写什么。

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
    function jsonp(url, params, cb) {
return new Promise((resolve, reject) => {
if (typeof url !== "string" || typeof cb !== "function" || !(params instanceof Object)) {
reject('参数错误');
return;
}
let script = document.createElement('script');
let str = '';
const paramsArray = Object.keys(params);

if (paramsArray.length) {
paramsArray.forEach((item) => {
str += `${item}=${params[item]}&`;
})
}
script.setAttribute('src', `${url}?${str}cb=${cb.name}`);
document.body.appendChild(script);
script.onload = () => {
resolve(script);
}
script.onerror = () => {
reject('错误');
}
})
}
//

function show(data) {
console.log(data);
}
//


jsonp('http://127.0.0.1:3000/jsonp', { data: 1 }, show).then(function (script) {
console.log(1);
document.body.removeChild(script);
}).catch(err => {
console.log(err);
})

复制一下视频里老师写的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function jsonp1({url,params,cb}) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
window[cb] = function(data){
resolve(data);
document.body.removeChild(script);
}
params = {...params,cb};
let arrs = [];
for(let key in params){
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
})
}
4) JSONP的缺点

1.必须传回调函数名称

2.只支持get请求

3.不安全 XSS攻击

2.CORS(最常用,安全性高)

1)先写一个简单🌰,一个get的请求(代码都是基于前一个的基础上修改)
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
function send() {
var xmlHttp;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject();
}

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status <= 300) || xmlHttp.status == 304) {
console.log(xmlHttp.response);
}
}
}

xmlHttp.open('GET', 'http://127.0.0.1:3000/cors', true);
xmlHttp.send();
}

send();
</script>

</html>

koa部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();

router.get('/cors', async (ctx, next) => {
console.log(ctx.headers);
ctx.body = {
success:true
};
})
app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

运行代码,发送请求的时候可以看到浏览器, Access-Control-Allow-Origin。表示后台没有允许域的访问。

同时也可以看到后台打印出来的结果

可以看出其实ajax请求已经发出,只是返回的时候被浏览器屏蔽。图中可以看到访问服务器的来源。

如何证明是返回被浏览器拦截:写一个简单的服务,一个get请求,里面操作数据库,操作成功了,结果返回给浏览器的时候失败。

解决方案:

我们添加了一个whiteList(白名单),并且判断如果来源在白名单内,就设置响应头。

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();

//新增的部分
const whiteList = ['http://localhost:8000'];
app.use((ctx,next)=>{
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {//如果判断是否存在,不建议使用indexOf
console.log(origin)
ctx.set('Access-Control-Allow-Origin', origin);
}
next();
})
//

router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

可以看到请求成功了

2)第二个🌰,自定义请求头

不修改koa代码的情况下,修改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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
function send() {
var xmlHttp;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject();
}

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status <= 300) || xmlHttp.status == 304) {
console.log(xmlHttp.response);
}
}
}
xmlHttp.open('GET', 'http://127.0.0.1:3000/cors', true);
//新增的部分
xmlHttp.setRequestHeader('name','qinhanwen');//必须在opend以后才可以设置
//
xmlHttp.send();
}

send();
</script>

</html>

请求发送后看到报错OPTIONS请求挂了

问题原因:非简单请求,会先发送一个OPTIONS预请求。

解决方案

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

//新增的部分,OPTIONS请求直接放过
app.use( (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});
//

app.use((ctx,next)=>{
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {
console.log(origin)
ctx.set('Access-Control-Allow-Origin', origin);
}
next();
})



router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

然后又出现了新的报错Access-Control-Allow-Headers,头部不被允许。

解决方案:设置允许的请求头部,多个头部使用逗号分隔

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use( (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx,next)=>{
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {
console.log(origin)
ctx.set('Access-Control-Allow-Origin', origin);
//新增的部分
ctx.set('Access-Control-Allow-Headers', "name,age");
//
}
next();
})
router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

可以看到请求成功了

3)第三个🌰,发一个PUT请求
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
function send() {
var xmlHttp;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject();
}

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status <= 300) || xmlHttp.status == 304) {
console.log(xmlHttp.response);
}
}
}
//修改的部分
xmlHttp.open('PUT', 'http://127.0.0.1:3000/cors', true);
//
xmlHttp.setRequestHeader('name','qinhanwen');
xmlHttp.send();
}

send();
</script>

</html>

同时接收一个PUT请求

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use( (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx,next)=>{
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {//如果判断是否存在,不建议使用indexOf
console.log(origin)
ctx.set('Access-Control-Allow-Origin', origin);
ctx.set('Access-Control-Allow-Headers', "name,age");
}
next();
})

//新增的部分
router.put('/cors' ,async (ctx, next) => {

ctx.body = {
success: true
};
})
//


router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

然后出现了报错Access-Control-Allow-Methods。请求方法不允许。

解决方案

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use( (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx,next)=>{
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {//如果判断是否存在,不建议使用indexOf
console.log(origin)
ctx.set('Access-Control-Allow-Origin', origin);
ctx.set('Access-Control-Allow-Headers', "name,age");
//新增的部分
ctx.set('Access-Control-Allow-Methods', "PUT");
//
}
next();
})
router.put('/cors' ,async (ctx, next) => {

ctx.body = {
success: true
};
})

router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

可以看到请求成功了

了解一下OPTIONS请求

在非简单请求的时候,会先发送一个预请求,主要用来判断是否允许跨域(我认为就是询问后台哪些头部,方法和来源是被允许的)。

在多次强制刷新页面的时候会发现,并不是每次请求的时候都会发送OPTIONS请求,有时候会发送

有时不会发送

问题原因:浏览器会加上一个默认的时间,也可以通过Access-Control-Max-Age设置

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use( (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx,next)=>{
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {
console.log(origin)
ctx.set('Access-Control-Allow-Origin', origin);
ctx.set('Access-Control-Allow-Headers', "name,age");
ctx.set('Access-Control-Allow-Methods', "PUT");
//新增的部分
ctx.set('Access-Control-Max-Age', 60);//这里设置了60秒内不会再发送
//
}
next();
})

router.put('/cors' ,async (ctx, next) => {
ctx.body = {
success: true
};
})

router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');
4)第四个🌰,设置cookie
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
function send() {
var xmlHttp;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject();
}

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status <= 300) || xmlHttp.status == 304) {
console.log(xmlHttp.response);
}
}
}
//新增的内容
document.cookie = "user=qinhanwen";
//
xmlHttp.open('PUT', 'http://127.0.0.1:3000/cors', true);
xmlHttp.setRequestHeader('name','qinhanwen');//必须在opend以后才可以设置
xmlHttp.send();
}

send();
</script>

</html>

在后台把请求头打印出来看看,嗯!毛都没看到

问题原因:因为cookie是不允许跨域的(需要浏览器和服务器同时允许)。

解决方案:我非要加上,设置 withCredentials

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
function send() {
var xmlHttp;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject();
}

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status <= 300) || xmlHttp.status == 304) {
console.log(xmlHttp.response);
}
}
}
document.cookie = "user=qinhanwen";
//新增的部分
xmlHttp.withCredentials = true;
//
xmlHttp.open('PUT', 'http://127.0.0.1:3000/cors', true);
xmlHttp.setRequestHeader('name','qinhanwen');//必须在opend以后才可以设置
xmlHttp.send();
}

send();
</script>

</html>

看到的报错Access-Control-Allow-Credentials

解决方案:添加头

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use( (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx,next)=>{
console.log(ctx.headers);
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {//如果判断是否存在,不建议使用indexOf
ctx.set('Access-Control-Allow-Origin', origin);
ctx.set('Access-Control-Allow-Headers', "name,age");
ctx.set('Access-Control-Allow-Methods', "PUT");
//新增的部分
ctx.set('Access-Control-Allow-Credentials',true);
//
ctx.set('Access-Control-Max-Age', 60);
}
next();
})

router.put('/cors' ,async (ctx, next) => {

ctx.body = {
success: true
};
})

router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

可以看到请求成功了

然而,还是没在请求头里看到cookie,这个问题半天没查明白。猜测是只能带上服务器设置了的cookie,没添加的话就不行,先记着后面来补充!!!!!!!!!,后面来补充!!!!!!!!!,后面来补充!!!!!!!!!

5)设置响应头

在访问某些接口的时候,可能数据放在了响应头里。

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use((ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx, next) => {
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {//如果判断是否存在,不建议使用indexOf
ctx.set('Access-Control-Allow-Origin', origin);
ctx.set('Access-Control-Allow-Headers', "name,age");
ctx.set('Access-Control-Allow-Methods', "PUT");
ctx.set('Access-Control-Allow-Credentials', true);
ctx.set('Access-Control-Max-Age', 60);
}
next();
})

router.put('/cors', async (ctx, next) => {
//新增的部分
ctx.set('response','data');//设置响应头
//
ctx.body = {
success: true
};
})

router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

前端部分直接从响应头中取值

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
function send() {
var xmlHttp;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject();
}

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status <= 300) || xmlHttp.status == 304) {
console.log(xmlHttp.response);
//新增的部分
console.log(xmlHttp.getResponseHeader('response'));
//
}
}
}
document.cookie = "user=qinhanwen";
xmlHttp.withCredentials = true;
xmlHttp.open('PUT', 'http://127.0.0.1:3000/cors', true);
xmlHttp.setRequestHeader('name', 'qinhanwen');//必须在opend以后才可以设置
xmlHttp.send();
}

send();
</script>

</html>

看到报错 ,不允许获得不安全的头

解决方案:我天真的以为这种问题,看起来应该是前端解决的,然鹅,还是要设置响应头Access-Control-Expose-Headers

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
const koa = require('koa');
const app = new koa();

const Router = require('koa-router');
const router = new Router();


const whiteList = ['http://localhost:8000'];

app.use((ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.body = '';
}
next();
});

app.use((ctx, next) => {
let origin = ctx.headers.origin;
if (whiteList.includes(origin)) {//如果判断是否存在,不建议使用indexOf
ctx.set('Access-Control-Allow-Origin', origin);
ctx.set('Access-Control-Allow-Headers', "name,age");
ctx.set('Access-Control-Allow-Methods', "PUT");
ctx.set('Access-Control-Allow-Credentials', true);
ctx.set('Access-Control-Max-Age', 60);
//新增的部分
ctx.set('Access-Control-Expose-Headers', 'response');
//
}
next();
})

router.put('/cors', async (ctx, next) => {
ctx.set('response', 'data');
ctx.body = {
success: true
};
})

router.get('/cors', async (ctx, next) => {

ctx.body = {
success: true
};
})

app.use(router.routes());

app.listen(3000);
console.log('koa server is listening port 3000');

可以看到请求成功了

3.postMessage

1) 使用postMessage进行不同域页面之间的通信

首先新建两个页面:

第一个postMessage.html,这个页面iframe引入第二个页面的地址,并且向第二个页面推送。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<iframe src="http://localhost:8001/postMessage/postMessage1.html" id="frame"></iframe>
</body>
<script>
window.onload = function(){
const frame = document.getElementById('frame');
frame.contentWindow.postMessage('qinhanwen','http://localhost:8001');
}

</script>
</html>

和postMessage1.html,这个页面监听传入的消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

</body>
<script>
window.onmessage = function(e){
console.log(e.data);//qinhanwen
}
</script>
</html>

目录结构是这样的,我们使用puer(安装:npm install puer)启动本地服务器,让两个页面的端口号不同。

2)内嵌页面的回应

postMessage.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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
<iframe src="http://localhost:8001/postMessage/postMessage1.html" id="frame"></iframe>
</body>
<script>
window.onload = function () {
const frame = document.getElementById('frame');
frame.contentWindow.postMessage('qinhanwen', 'http://localhost:8001');
//新增的部分
window.onmessage = function (e) {
console.log(e.data);
}
//
}

</script>

</html>

postMessage1.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>

</body>
<script>
window.onmessage = function (e) {
console.log(e.data);
//新增的部分
e.source.postMessage('received', e.origin);
//
}
</script>

</html>

可以看到页面输出结果

4.window.name

关于window.name属性: name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。并且window.name很方便。

1)第一个🌰,新建两个页面,并且让这两个页面不同域。name.html启在端口号8000name1.html启在端口号8001,我在页面name.html去获取name1的数据。在加载页面name1.html的时候,设置window.name='qinhanwen'

name.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
<iframe src="http://localhost:8001/windowname/name1.html" frameborder="0" onload="load()" id="frame"></iframe>
</body>
<script>
let first = true;
function load() {
const frame = document.getElementById('frame');
console.log(frame.contentWindow.name);
}
</script>

</html>

name1.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
</body>
<script>
window.name = 'qinhanwen';
</script>

</html>

然后看到报错,因为域不同,所以无法获取。

解决方案:新建一个name2.html把iframe的src设置为这个页面,他与name.html同域

name2.html 实际上这个name2.html什么都没做

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

</body>
</html>

name.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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>
<iframe src="http://localhost:8001/windowname/name1.html" frameborder="0" onload="load()" id="frame"></iframe>
</body>
<script>
let first = true;
function load() {
const frame = document.getElementById('frame');
if (first) {
first = false;
frame.src = "http://localhost:8000/windowname/name2.html";
}else{
console.log(frame.contentWindow.name);
}
}
</script>

</html>

可以看到获取成功了

5.location.hash

路径后的hash值可以用于通信

1)新建三个页面 hash.htmlhash1.html同域,与hash2.html不同域。

hash.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<iframe src="http://localhost:8001/location/hash2.html#qinhanwen" frameborder="0"></iframe>
</body>
</html>

hash2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

</body>
<script>
window.onload = function(){
console.log(location.hash);//#qinhanwen
}
</script>
</html>

可以看到打印出了 #qinhanwen

2)那么要怎么传递给值给父窗体

使用window.parent.hash

我们把父窗体的hash设置为#qinhanwen

hash2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

</body>
<script>
window.onload = function(){
console.log(location.hash);
//新增的部分
window.parent.location.hash = '#qinhanwen';
//
}
</script>
</html>

然后看到报错,不同域的话,是不允许操作父窗体hash值的

解决方案:新增一个hash1.html页面,在hash2.html中添加一个iframe,iframse的 src指向与hash.html同域的hash1.html地址,而在hash1.html设置父亲的父亲窗体的hash值,看🌰

hash1.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

</body>
<script>
window.onload = function(){
window.parent.parent.location.hash = '#qinhanwen';
}
</script>
</html>

hash2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

</body>
<script>
window.onload = function(){
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = "http://localhost:8000/location/hash1.html#qinhanwen";
document.body.appendChild(iframe);
}
</script>
</html>

可以看到hash被设置为了#qinhanwen

3)hash值是改变了,怎么取得呢

hash.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<iframe src="http://localhost:8001/location/hash2.html#qinhanwen" frameborder="0"></iframe>
</body>

<!--新增的部分-->
<script>
window.onhashchange = function(){
console.log(location.hash);
}
</script>
<!---->

</html>

6.document.domain

这个要先了解一级域名和二级域名,大概视频80分钟的时候开始说。

7.WebSocket

WebSocket+koa

8.Nginx

大概视频90多分钟开始说。